Browse Source

fix:完善 review 拼团、秒杀活动的实现提到的问题

puhui999 1 year ago
parent
commit
d156d43d63
43 changed files with 391 additions and 695 deletions
  1. 4 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
  2. 12 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
  3. 1 11
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java
  4. 11 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java
  5. 3 6
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
  6. 5 4
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java
  7. 10 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java
  8. 7 7
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
  9. 1 2
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java
  10. 3 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  11. 5 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java
  12. 10 10
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
  13. 10 29
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
  14. 0 65
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExcelVO.java
  15. 0 61
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExportReqVO.java
  16. 0 44
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExcelVO.java
  17. 0 43
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExportReqVO.java
  18. 1 1
      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. 14 25
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
  21. 5 7
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
  22. 1 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java
  23. 3 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java
  24. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
  25. 2 11
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java
  26. 2 16
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationProductMapper.java
  27. 14 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
  28. 2 50
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
  29. 50 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
  30. 37 31
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationServiceImpl.java
  31. 32 33
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
  32. 2 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigService.java
  33. 4 5
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java
  34. 5 28
      yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java
  35. 4 6
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
  36. 3 9
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDeliveryReqVO.java
  37. 2 15
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  38. 0 60
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDeliveryDO.java
  39. 0 24
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderDeliveryMapper.java
  40. 19 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageService.java
  41. 39 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java
  42. 32 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/dto/TradeOrderMessageWhenDeliveryOrderReqDTO.java
  43. 33 80
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java

+ 4 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java

@@ -27,6 +27,10 @@ public class CollectionUtils {
         return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
     }
 
+    public static <T> boolean isAny(Collection<T> from, Predicate<T> predicate) {
+        return from.stream().anyMatch(predicate);
+    }
+
     public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
         if (CollUtil.isEmpty(from)) {
             return new ArrayList<>();

+ 12 - 1
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.date;
 import cn.hutool.core.date.LocalDateTimeUtil;
 
 import java.time.Duration;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 
@@ -70,7 +71,7 @@ public class LocalDateTimeUtils {
      * @param endTime2   校验所需的结束时间
      * @return 是否重叠
      */
-    // TODO @puhui999:LocalDateTimeUtil.isOverlap() 是不是可以满足呀?
+    @Deprecated
     public static boolean checkTimeOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
         // 判断时间是否重叠
         // 开始时间在已配置时段的结束时间之前 且 结束时间在已配置时段的开始时间之后 []
@@ -81,4 +82,14 @@ public class LocalDateTimeUtils {
                 || startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
     }
 
+    public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
+        // 日期部分使用了当前日期LocalDate.now()
+        LocalDateTime startDateTime1 = LocalDateTime.of(LocalDate.now(), startTime1);
+        LocalDateTime endDateTime1 = LocalDateTime.of(LocalDate.now(), endTime1);
+        LocalDateTime startDateTime2 = LocalDateTime.of(LocalDate.now(), startTime2);
+        LocalDateTime endDateTime2 = LocalDateTime.of(LocalDate.now(), endTime2);
+
+        return LocalDateTimeUtil.isOverlap(startDateTime1, endDateTime1, startDateTime2, endDateTime2);
+    }
+
 }

+ 1 - 11
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java

@@ -1,6 +1,5 @@
 package cn.iocoder.yudao.module.product.controller.app.comment;
 
-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.framework.common.util.collection.CollectionUtils;
@@ -9,10 +8,8 @@ import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStati
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
 import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
-import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
-import com.google.common.collect.Maps;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.Parameters;
@@ -27,7 +24,6 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -60,15 +56,9 @@ public class AppProductCommentController {
     @GetMapping("/page")
     @Operation(summary = "获得商品评价分页")
     public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
-        // TODO @puhui999:写到 convert 里,可以更简洁哈。
         PageResult<ProductCommentDO> commentDOPage = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
         Set<Long> skuIds = CollectionUtils.convertSet(commentDOPage.getList(), ProductCommentDO::getSkuId);
-        List<ProductSkuDO> skuList = productSkuService.getSkuList(skuIds);
-        Map<Long, ProductSkuDO> skuDOMap = Maps.newLinkedHashMapWithExpectedSize(skuIds.size());
-        if (CollUtil.isNotEmpty(skuList)) {
-            skuDOMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId, c -> c));
-        }
-        PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, skuDOMap);
+        PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, productSkuService.getSkuList(skuIds));
         return success(page);
     }
 

+ 11 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.module.product.convert.comment;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
@@ -13,6 +15,7 @@ import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProdu
 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
+import com.google.common.collect.Maps;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Named;
@@ -37,19 +40,23 @@ public interface ProductCommentConvert {
 
     @Mapping(target = "scores", expression = "java(calculateOverallScore(goodCount, mediocreCount, negativeCount))")
     AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount);
+
     @Named("calculateOverallScore")
     default double calculateOverallScore(long goodCount, long mediocreCount, long negativeCount) {
         return (goodCount * 5 + mediocreCount * 3 + negativeCount) / (double) (goodCount + mediocreCount + negativeCount);
     }
-    
+
     List<ProductCommentRespVO> convertList(List<ProductCommentDO> list);
 
     PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> page);
 
     PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult);
 
-    default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult,
-                                                              Map<Long, ProductSkuDO> skuMap) {
+    default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult, List<ProductSkuDO> skuList) {
+        Map<Long, ProductSkuDO> skuMap = Maps.newLinkedHashMapWithExpectedSize(skuList.size());
+        if (CollUtil.isNotEmpty(skuList)) {
+            skuMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId));
+        }
         PageResult<AppProductCommentRespVO> page = convertPage01(pageResult);
         page.getList().forEach(item -> {
             // 判断用户是否选择匿名
@@ -61,6 +68,7 @@ public interface ProductCommentConvert {
         });
         return page;
     }
+
     List<AppProductPropertyValueDetailRespVO> convertList01(List<ProductSkuDO.Property> properties);
 
     /**

+ 3 - 6
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.product.convert.spu;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
@@ -81,6 +82,7 @@ public interface ProductSpuConvert {
         }
         return voList;
     }
+
     @Named("convertListForGetSpuList0")
     List<AppProductSpuPageRespVO> convertListForGetSpuList0(List<ProductSpuDO> list);
 
@@ -112,12 +114,7 @@ public interface ProductSpuConvert {
     default List<ProductSpuDetailRespVO> convertForSpuDetailRespListVO(List<ProductSpuDO> spus, List<ProductSkuDO> skus) {
         List<ProductSpuDetailRespVO> vos = new ArrayList<>(spus.size());
         Map<Long, List<ProductSkuDO>> skuMultiMap = convertMultiMap(skus, ProductSkuDO::getSpuId);
-        // TODO @puhui999:可以直接使用 CollUtils.convertList
-        spus.forEach(spu -> {
-            ProductSpuDetailRespVO detailRespVO = convert03(spu);
-            detailRespVO.setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId())));
-            vos.add(detailRespVO);
-        });
+        CollectionUtils.convertList(spus, spu -> vos.add(convert03(spu).setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId())))));
         return vos;
     }
 

+ 5 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java

@@ -26,18 +26,19 @@ public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
     }
 
     static void appendTabQuery(LambdaQueryWrapperX<ProductCommentDO> queryWrapper, Integer type) {
-        // TODO @puhui999:是不是不用 apply 拉?直接用 mybatis 的方法就好啦
+        LambdaQueryWrapperX<ProductCommentDO> queryWrapperX = new LambdaQueryWrapperX<>();
         // 构建好评查询语句:好评计算 总评 >= 4
         if (ObjectUtil.equal(type, AppCommentPageReqVO.GOOD_COMMENT)) {
-            queryWrapper.apply("scores >= 4");
+            queryWrapperX.ge(ProductCommentDO::getScores, 4);
         }
         // 构建中评查询语句:中评计算 总评 >= 3 且 总评 < 4
         if (ObjectUtil.equal(type, AppCommentPageReqVO.MEDIOCRE_COMMENT)) {
-            queryWrapper.apply("scores >=3 and scores < 4");
+            queryWrapperX.ge(ProductCommentDO::getScores, 3);
+            queryWrapperX.lt(ProductCommentDO::getScores, 4);
         }
         // 构建差评查询语句:差评计算 总评 < 3
         if (ObjectUtil.equal(type, AppCommentPageReqVO.NEGATIVE_COMMENT)) {
-            queryWrapper.apply("scores < 3");
+            queryWrapperX.lt(ProductCommentDO::getScores, 3);
         }
     }
 

+ 10 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java

@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.module.promotion.api.combination;
+
+/**
+ * 拼团活动 API 接口
+ *
+ * @author HUIHUI
+ */
+public interface CombinationActivityApi {
+
+}

+ 7 - 7
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java → yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java

@@ -1,30 +1,30 @@
 package cn.iocoder.yudao.module.promotion.api.combination;
 
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 
 import javax.validation.Valid;
-
-// TODO @puhui999:CombinationRecordApi 分成活动、记录哈
 // TODO @芋艿:后面也再撸撸这几个接口
+
 /**
- * 拼团活动 API 接口
+ * 拼团记录 API 接口
  *
  * @author HUIHUI
  */
-public interface CombinationApi {
+public interface CombinationRecordApi {
 
     /**
      * 创建开团记录
      *
      * @param reqDTO 请求 DTO
      */
-    void createRecord(@Valid CombinationRecordReqDTO reqDTO);
+    void createRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
 
     /**
-     * 获取开团记录状态
+     * 校验拼团是否成功
      *
      * @param userId  用户编号
      * @param orderId 订单编号
+     * @return 拼团是否成功
      */
     boolean validateRecordStatusIsSuccess(Long userId, Long orderId);
 

+ 1 - 2
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordReqDTO.java → yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java

@@ -5,14 +5,13 @@ import lombok.Data;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
-// TODO @puhui999:CombinationRecordCreateReqDTO,这样更容易知道是创建噢
 /**
  * 拼团记录 Request DTO
  *
  * @author HUIHUI
  */
 @Data
-public class CombinationRecordReqDTO {
+public class CombinationRecordCreateReqDTO {
 
     /**
      * 拼团活动编号

+ 3 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -65,5 +65,8 @@ public interface ErrorCodeConstants {
     ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
     ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
     ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
+    ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013010005, "拼团失败,已参与过该拼团");
+    ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013010006, "拼团失败,父拼团不存在");
+    ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013010006, "拼团失败,拼团人数已满");
 
 }

+ 5 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.promotion.enums.combination;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
@@ -36,4 +37,8 @@ public enum CombinationRecordStatusEnum implements IntArrayValuable {
         return ARRAYS;
     }
 
+    public static boolean isSuccess(Integer status) {
+        return ObjectUtil.equal(status, SUCCESS.getStatus());
+    }
+
 }

+ 10 - 10
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java

@@ -1,7 +1,8 @@
 package cn.iocoder.yudao.module.promotion.api.combination;
 
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
-import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
+import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
+import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -13,30 +14,29 @@ import java.time.LocalDateTime;
  * @author HUIHUI
  */
 @Service
-public class CombinationApiImpl implements CombinationApi {
+public class CombinationRecordApiImpl implements CombinationRecordApi {
 
     @Resource
-    private CombinationActivityService activityService;
+    private CombinationRecordService recordService;
 
     @Override
-    public void createRecord(CombinationRecordReqDTO reqDTO) {
-        activityService.createRecord(reqDTO);
+    public void createRecord(CombinationRecordCreateReqDTO reqDTO) {
+        recordService.createRecord(reqDTO);
     }
 
     @Override
     public boolean validateRecordStatusIsSuccess(Long userId, Long orderId) {
-        return activityService.validateRecordStatusIsSuccess(userId, orderId);
+        return CombinationRecordStatusEnum.isSuccess(recordService.getRecord(userId, orderId).getStatus());
     }
 
     @Override
     public void updateRecordStatus(Long userId, Long orderId, Integer status) {
-        activityService.updateRecordStatusByUserIdAndOrderId(userId, orderId, status);
+        recordService.updateRecordStatusByUserIdAndOrderId(userId, orderId, status);
     }
 
     @Override
     public void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status) {
-        activityService.updateRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
+        recordService.updateRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
     }
 
-
 }

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

@@ -3,14 +3,14 @@ package cn.iocoder.yudao.module.promotion.controller.admin.combination;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 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.*;
+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;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
+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.service.combination.CombinationActivityService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -20,16 +20,12 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
-import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
-import java.io.IOException;
 import java.util.Collection;
 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;
-import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 
 @Tag(name = "管理后台 - 拼团活动")
 @RestController
@@ -82,7 +78,7 @@ public class CombinationActivityController {
     @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
     public CommonResult<List<CombinationActivityRespVO>> getCombinationActivityList(@RequestParam("ids") Collection<Long> ids) {
         List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(ids);
-        return success(CombinationActivityConvert.INSTANCE.convertList(list));
+        return success(CombinationActivityConvert.INSTANCE.complementList(list));
     }
 
     @GetMapping("/page")
@@ -91,24 +87,9 @@ public class CombinationActivityController {
     public CommonResult<PageResult<CombinationActivityRespVO>> getCombinationActivityPage(
             @Valid CombinationActivityPageReqVO pageVO) {
         PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO);
-        // TODO @puhui999:可以不一定 aIds,直接批量查询结果出来;下面也是类似;
-        Set<Long> aIds = CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getId);
-        List<CombinationProductDO> products = combinationActivityService.getProductsByActivityIds(aIds);
-        Set<Long> spuIds = CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getSpuId);
-        List<ProductSpuRespDTO> spus = spuApi.getSpuList(spuIds);
-        return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
-    }
-
-    @GetMapping("/export-excel")
-    @Operation(summary = "导出拼团活动 Excel")
-    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:export')")
-    @OperateLog(type = EXPORT)
-    public void exportCombinationActivityExcel(@Valid CombinationActivityExportReqVO exportReqVO,
-                                               HttpServletResponse response) throws IOException {
-        List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(exportReqVO);
-        // 导出 Excel
-        List<CombinationActivityExcelVO> datas = CombinationActivityConvert.INSTANCE.convertList02(list);
-        ExcelUtils.write(response, "拼团活动.xls", "数据", CombinationActivityExcelVO.class, datas);
+        return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult,
+                combinationActivityService.getProductsByActivityIds(CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getId)),
+                spuApi.getSpuList(CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getSpuId))));
     }
 
 }

+ 0 - 65
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExcelVO.java

@@ -1,65 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
-
-import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
-import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
-import com.alibaba.excel.annotation.ExcelProperty;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-// TODO @puhui999:如无必要,导出都可以删除哈
-/**
- * 拼团活动 Excel VO
- *
- * @author HUIHUI
- */
-@Data
-public class CombinationActivityExcelVO {
-
-    @ExcelProperty("活动编号")
-    private Long id;
-
-    @ExcelProperty("拼团名称")
-    private String name;
-
-    @ExcelProperty("商品 SPU 编号关联 ProductSpuDO 的 id")
-    private Long spuId;
-
-    @ExcelProperty("总限购数量")
-    private Integer totalLimitCount;
-
-    @ExcelProperty("单次限购数量")
-    private Integer singleLimitCount;
-
-    @ExcelProperty("开始时间")
-    private LocalDateTime startTime;
-
-    @ExcelProperty("结束时间")
-    private LocalDateTime endTime;
-
-    @ExcelProperty("开团人数")
-    private Integer userSize;
-
-    @ExcelProperty("开团组数")
-    private Integer totalNum;
-
-    @ExcelProperty("成团组数")
-    private Integer successNum;
-
-    @ExcelProperty("参与人数")
-    private Integer orderUserCount;
-
-    @ExcelProperty("虚拟成团")
-    private Integer virtualGroup;
-
-    @ExcelProperty(value = "活动状态:0开启 1关闭", converter = DictConvert.class)
-    @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
-    private Integer status;
-
-    @ExcelProperty("限制时长(小时)")
-    private Integer limitDuration;
-
-    @ExcelProperty("创建时间")
-    private LocalDateTime createTime;
-
-}

+ 0 - 61
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExportReqVO.java

@@ -1,61 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-// TODO @puhui999:如无必要,导出都可以删除哈
-@Schema(description = "管理后台 - 拼团活动 Excel 导出 Request VO,参数和 CombinationActivityPageReqVO 是一致的")
-@Data
-public class CombinationActivityExportReqVO {
-
-    @Schema(description = "拼团名称", example = "赵六")
-    private String name;
-
-    @Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "14016")
-    private Long spuId;
-
-    @Schema(description = "总限购数量", example = "16218")
-    private Integer totalLimitCount;
-
-    @Schema(description = "单次限购数量", example = "28265")
-    private Integer singleLimitCount;
-
-    @Schema(description = "开始时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] startTime;
-
-    @Schema(description = "结束时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] endTime;
-
-    @Schema(description = "开团人数")
-    private Integer userSize;
-
-    @Schema(description = "开团组数")
-    private Integer totalNum;
-
-    @Schema(description = "成团组数")
-    private Integer successNum;
-
-    @Schema(description = "参与人数", example = "25222")
-    private Integer orderUserCount;
-
-    @Schema(description = "虚拟成团")
-    private Integer virtualGroup;
-
-    @Schema(description = "活动状态:0开启 1关闭", example = "0")
-    private Integer status;
-
-    @Schema(description = "限制时长(小时)")
-    private Integer limitDuration;
-
-    @Schema(description = "创建时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
-}

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

@@ -1,44 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
-
-import com.alibaba.excel.annotation.ExcelProperty;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-// TODO @puhui999:可以考虑删除 excel 导出哈
-/**
- * 拼团商品 Excel VO
- *
- * @author HUIHUI
- */
-@Data
-public class CombinationProductExcelVO {
-
-    @ExcelProperty("编号")
-    private Long id;
-
-    @ExcelProperty("拼团活动编号")
-    private Long activityId;
-
-    @ExcelProperty("商品 SPU 编号")
-    private Long spuId;
-
-    @ExcelProperty("商品 SKU 编号")
-    private Long skuId;
-
-    @ExcelProperty("拼团商品状态")
-    private Integer activityStatus;
-
-    @ExcelProperty("活动开始时间点")
-    private LocalDateTime activityStartTime;
-
-    @ExcelProperty("活动结束时间点")
-    private LocalDateTime activityEndTime;
-
-    @ExcelProperty("拼团价格,单位分")
-    private Integer activePrice;
-
-    @ExcelProperty("创建时间")
-    private LocalDateTime createTime;
-
-}

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

@@ -1,43 +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 org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-// TODO @puhui999:可以考虑删除 excel 导出哈
-@Schema(description = "管理后台 - 拼团商品 Excel 导出 Request VO,参数和 CombinationProductPageReqVO 是一致的")
-@Data
-public class CombinationProductExportReqVO {
-
-    @Schema(description = "拼团活动编号", example = "6829")
-    private Long activityId;
-
-    @Schema(description = "商品 SPU 编号", example = "18731")
-    private Long spuId;
-
-    @Schema(description = "商品 SKU 编号", example = "31675")
-    private Long skuId;
-
-    @Schema(description = "拼团商品状态", example = "2")
-    private Integer activityStatus;
-
-    @Schema(description = "活动开始时间点")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] activityStartTime;
-
-    @Schema(description = "活动结束时间点")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] activityEndTime;
-
-    @Schema(description = "拼团价格,单位分", example = "27682")
-    private Integer activePrice;
-
-    @Schema(description = "创建时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
-}

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

@@ -85,7 +85,7 @@ public class SeckillActivityController {
     @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
     public CommonResult<List<SeckillActivityRespVO>> getSeckillActivityList(@RequestParam("ids") Collection<Long> ids) {
         List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(ids);
-        return success(SeckillActivityConvert.INSTANCE.convertList(list));
+        return success(SeckillActivityConvert.INSTANCE.complementList(list));
     }
 
     @GetMapping("/page")

+ 2 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*;
@@ -80,7 +81,7 @@ public class SeckillConfigController {
     @GetMapping("/list-all-simple")
     @Operation(summary = "获得所有开启状态的秒杀时段精简列表", description = "主要用于前端的下拉选项")
     public CommonResult<List<SeckillConfigSimpleRespVO>> getListAllSimple() {
-        List<SeckillConfigDO> list = seckillConfigService.getListAllSimple();
+        List<SeckillConfigDO> list = seckillConfigService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
         return success(SeckillConfigConvert.INSTANCE.convertList1(list));
     }
 

+ 14 - 25
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java

@@ -1,19 +1,18 @@
 package cn.iocoder.yudao.module.promotion.convert.combination;
 
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExcelVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
 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.controller.admin.combination.vo.product.CombinationProductRespVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationRecordDO;
+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.dataobject.combination.CombinationRecordDO;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
@@ -71,20 +70,18 @@ public interface CombinationActivityConvert {
         return respVO;
     }
 
-    List<CombinationActivityRespVO> convertList(List<CombinationActivityDO> list);
+    List<CombinationActivityRespVO> complementList(List<CombinationActivityDO> list);
 
     PageResult<CombinationActivityRespVO> convertPage(PageResult<CombinationActivityDO> page);
 
     default PageResult<CombinationActivityRespVO> convertPage(PageResult<CombinationActivityDO> page,
                                                               List<CombinationProductDO> productList,
                                                               List<ProductSpuRespDTO> spuList) {
-        // TODO @puhui999:c -> c 可以去掉哈
-        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId, c -> c);
+        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
         PageResult<CombinationActivityRespVO> pageResult = convertPage(page);
         pageResult.getList().forEach(item -> {
-            // TODO @puhui999:最好 MapUtils.findAndThen,万一没找到呢,啊哈哈。
-            item.setSpuName(spuMap.get(item.getSpuId()).getName());
-            item.setPicUrl(spuMap.get(item.getSpuId()).getPicUrl());
+            MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setSpuName(spu.getName()));
+            MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()));
             item.setProducts(convertList2(productList));
         });
         return pageResult;
@@ -92,8 +89,6 @@ public interface CombinationActivityConvert {
 
     List<CombinationProductRespVO> convertList2(List<CombinationProductDO> productDOs);
 
-    List<CombinationActivityExcelVO> convertList02(List<CombinationActivityDO> list);
-
     @Mappings({
             @Mapping(target = "id", ignore = true),
             @Mapping(target = "activityId", source = "activityDO.id"),
@@ -105,34 +100,28 @@ public interface CombinationActivityConvert {
     })
     CombinationProductDO convert(CombinationActivityDO activityDO, CombinationProductBaseVO vo);
 
-    default List<CombinationProductDO> convertList(CombinationActivityDO activityDO, List<? extends CombinationProductBaseVO> products) {
+    default List<CombinationProductDO> complementList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activityDO) {
         List<CombinationProductDO> list = new ArrayList<>();
         products.forEach(sku -> {
             CombinationProductDO productDO = convert(activityDO, sku);
-            // TODO 状态设置
-            productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
+            productDO.setActivityStatus(activityDO.getStatus());
             list.add(productDO);
         });
         return list;
     }
 
-    // TODO @puhui999:这个方法的参数,调整成 productDOs、vos、activityDO;因为 productDOs 是主角;
-    // 然后,这个方法,感觉不是为了 convert,而是为了补全;
-    default List<CombinationProductDO> convertList1(CombinationActivityDO activityDO,
-                                                    List<CombinationProductUpdateReqVO> vos,
-                                                    List<CombinationProductDO> productDOs) {
+    default List<CombinationProductDO> complementList(List<CombinationProductDO> productDOs, List<CombinationProductUpdateReqVO> vos, CombinationActivityDO activityDO) {
         Map<Long, Long> longMap = convertMap(productDOs, CombinationProductDO::getSkuId, CombinationProductDO::getId);
         List<CombinationProductDO> list = new ArrayList<>();
         vos.forEach(sku -> {
             CombinationProductDO productDO = convert(activityDO, sku);
             productDO.setId(longMap.get(sku.getSkuId()));
-            // TODO @puhui999:是是不是用 activityDO 的状态;
-            productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
+            productDO.setActivityStatus(activityDO.getStatus());
             list.add(productDO);
         });
         return list;
     }
 
-    CombinationRecordDO convert(CombinationRecordReqDTO reqDTO);
+    CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
 
 }

+ 5 - 7
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java

@@ -1,6 +1,5 @@
 package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
 
-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.spu.dto.ProductSpuRespDTO;
@@ -38,7 +37,7 @@ public interface SeckillActivityConvert {
 
     SeckillActivityRespVO convert(SeckillActivityDO bean);
 
-    List<SeckillActivityRespVO> convertList(List<SeckillActivityDO> list);
+    List<SeckillActivityRespVO> complementList(List<SeckillActivityDO> list);
 
     PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
 
@@ -74,24 +73,23 @@ public interface SeckillActivityConvert {
     })
     SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo);
 
-    default List<SeckillProductDO> convertList(SeckillActivityDO activityDO, List<? extends SeckillProductBaseVO> products) {
+    default List<SeckillProductDO> complementList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activityDO) {
         List<SeckillProductDO> list = new ArrayList<>();
         products.forEach(sku -> {
             SeckillProductDO productDO = convert(activityDO, sku);
-            productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
+            productDO.setActivityStatus(activityDO.getStatus());
             list.add(productDO);
         });
         return list;
     }
 
-    // TODO @puhui999:同拼团那个 convert 想通的情况哈。
-    default List<SeckillProductDO> convertList1(SeckillActivityDO activityDO, List<SeckillProductUpdateReqVO> vos, List<SeckillProductDO> productDOs) {
+    default List<SeckillProductDO> complementList(List<SeckillProductDO> productDOs, List<SeckillProductUpdateReqVO> vos, SeckillActivityDO activityDO) {
         Map<Long, Long> longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId);
         List<SeckillProductDO> list = new ArrayList<>();
         vos.forEach(sku -> {
             SeckillProductDO productDO = convert(activityDO, sku);
             productDO.setId(longMap.get(sku.getSkuId()));
-            productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
+            productDO.setActivityStatus(activityDO.getStatus());
             list.add(productDO);
         });
         return list;

+ 1 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/combinationactivity/CombinationActivityDO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity;
+package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;
 
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
@@ -9,7 +9,6 @@ import lombok.*;
 
 import java.time.LocalDateTime;
 
-// TODO @puhui999:是不是应该在 combination 哈?
 /**
  * 拼团活动 DO
  *

+ 3 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/combinationactivity/CombinationProductDO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity;
+package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.KeySequence;
@@ -42,6 +42,8 @@ public class CombinationProductDO extends BaseDO {
     private Long skuId;
     /**
      * 拼团商品状态
+     *
+     * 关联 {@link CombinationActivityDO#getStatus()}
      */
     private Integer activityStatus;
     /**

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/combinationactivity/CombinationRecordDO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity;
+package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;

+ 2 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/combinationactivity/CombinationActivityMapper.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java

@@ -1,16 +1,14 @@
-package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity;
+package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
 
-// TODO @puhui999:是不是应该在 combination 哈?
 /**
  * 拼团活动 Mapper
  *
@@ -25,13 +23,6 @@ public interface CombinationActivityMapper extends BaseMapperX<CombinationActivi
                 .orderByDesc(CombinationActivityDO::getId));
     }
 
-    default List<CombinationActivityDO> selectList(CombinationActivityExportReqVO reqVO) {
-        return selectList(new LambdaQueryWrapperX<CombinationActivityDO>()
-                .likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
-                .eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus())
-                .orderByDesc(CombinationActivityDO::getId));
-    }
-
     default List<CombinationActivityDO> selectListByStatus(Integer status) {
         return selectList(CombinationActivityDO::getStatus, status);
     }

+ 2 - 16
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/combinationactivity/CombinationProductMapper.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationProductMapper.java

@@ -1,11 +1,10 @@
-package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity;
+package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductExportReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductPageReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.Collection;
@@ -32,19 +31,6 @@ public interface CombinationProductMapper extends BaseMapperX<CombinationProduct
                 .orderByDesc(CombinationProductDO::getId));
     }
 
-    default List<CombinationProductDO> selectList(CombinationProductExportReqVO reqVO) {
-        return selectList(new LambdaQueryWrapperX<CombinationProductDO>()
-                .eqIfPresent(CombinationProductDO::getActivityId, reqVO.getActivityId())
-                .eqIfPresent(CombinationProductDO::getSpuId, reqVO.getSpuId())
-                .eqIfPresent(CombinationProductDO::getSkuId, reqVO.getSkuId())
-                .eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus())
-                .betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime())
-                .betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime())
-                .eqIfPresent(CombinationProductDO::getActivePrice, reqVO.getActivePrice())
-                .betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(CombinationProductDO::getId));
-    }
-
     default List<CombinationProductDO> selectListByActivityIds(Collection<Long> ids) {
         return selectList(CombinationProductDO::getActivityId, ids);
     }

+ 14 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/combinationactivity/CombinationRecordMapper.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java

@@ -1,8 +1,8 @@
-package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity;
+package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
 
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationRecordDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
@@ -20,6 +20,18 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
                 CombinationRecordDO::getOrderId, orderId);
     }
 
+    /**
+     * 查询拼团记录
+     *
+     * @param headId     团长编号
+     * @param activityId 活动编号
+     * @return 拼团记录
+     */
+    default CombinationRecordDO selectRecordByHeadId(Long headId, Long activityId, Integer status) {
+        return selectOne(CombinationRecordDO::getUserId, headId, CombinationRecordDO::getActivityId, activityId,
+                CombinationRecordDO::getStatus, status);
+    }
+
     default List<CombinationRecordDO> selectListByHeadIdAndStatus(Long headId, Integer status) {
         return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
                 .eq(CombinationRecordDO::getHeadId, headId)

+ 2 - 50
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java

@@ -1,16 +1,13 @@
 package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
 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.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
 
 import javax.validation.Valid;
-import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.List;
 
@@ -67,14 +64,6 @@ public interface CombinationActivityService {
      */
     PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO);
 
-    /**
-     * 获得拼团活动列表, 用于 Excel 导出
-     *
-     * @param exportReqVO 查询条件
-     * @return 拼团活动列表
-     */
-    List<CombinationActivityDO> getCombinationActivityList(CombinationActivityExportReqVO exportReqVO);
-
     /**
      * 获得拼团活动商品列表
      *
@@ -83,41 +72,4 @@ public interface CombinationActivityService {
      */
     List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids);
 
-    // TODO @puhui999:拆一个 CombinationRecordService 里,方法名可以简洁成 updateRecordStatusByOrderId;service 方法可以稍微简单一点,如果是 update 方法
-    /**
-     * 更新拼团状态
-     *
-     * @param userId  用户编号
-     * @param orderId 订单编号
-     * @param status  状态
-     */
-    void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
-
-    /**
-     * 更新拼团状态和开始时间
-     *
-     * @param userId    用户编号
-     * @param orderId   订单编号
-     * @param status    状态
-     * @param startTime 开始时间
-     */
-    void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime);
-
-    // TODO @puhui999:拆一个 CombinationRecordService 里
-    /**
-     * 创建拼团记录
-     *
-     * @param reqDTO 创建信息
-     */
-    void createRecord(CombinationRecordReqDTO reqDTO);
-
-    /**
-     * 获得拼团状态
-     *
-     * @param userId  用户编号
-     * @param orderId 订单编号
-     * @return 拼团状态
-     */
-    boolean validateRecordStatusIsSuccess(Long userId, Long orderId);
-
 }

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

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.promotion.service.combination;
+
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
+
+import java.time.LocalDateTime;
+
+/**
+ * 商品活动记录 service
+ *
+ * @author HUIHUI
+ */
+public interface CombinationRecordService {
+
+    /**
+     * 更新拼团状态
+     *
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     * @param status  状态
+     */
+    void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
+
+    /**
+     * 创建拼团记录
+     *
+     * @param reqDTO 创建信息
+     */
+    void createRecord(CombinationRecordCreateReqDTO reqDTO);
+
+    /**
+     * 更新拼团状态和开始时间
+     *
+     * @param userId    用户编号
+     * @param orderId   订单编号
+     * @param status    状态
+     * @param startTime 开始时间
+     */
+    void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime);
+
+    /**
+     * 获得拼团状态
+     *
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     * @return 拼团状态
+     */
+    CombinationRecordDO getRecord(Long userId, Long orderId);
+
+}

+ 37 - 31
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationServiceImpl.java

@@ -12,20 +12,19 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
 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.CombinationProductCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationRecordDO;
-import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationActivityMapper;
-import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationProductMapper;
-import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationRecordMapper;
+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.dataobject.combination.CombinationRecordDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
+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;
@@ -47,7 +46,7 @@ import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProd
  */
 @Service
 @Validated
-public class CombinationActivityServiceImpl implements CombinationActivityService {
+public class CombinationServiceImpl implements CombinationActivityService, CombinationRecordService {
 
     @Resource
     private CombinationActivityMapper combinationActivityMapper;
@@ -81,7 +80,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
         combinationActivityMapper.insert(activityDO);
         // 插入商品
-        List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList(activityDO, createReqVO.getProducts());
+        List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.complementList(createReqVO.getProducts(), activityDO);
         combinationProductMapper.insertBatch(productDOs);
         // 返回
         return activityDO.getId();
@@ -144,15 +143,14 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         Map<String, List<CombinationProductDO>> data = CollectionUtils.convertCDUMap(convertSet1, convertSet, mapData -> {
             HashMap<String, List<CombinationProductDO>> cdu = MapUtil.newHashMap(3);
             MapUtils.findAndThen(mapData, "create", list -> {
-                cdu.put("create", CombinationActivityConvert.INSTANCE.convertList(updateObj,
-                        CollectionUtils.filterList(products, item -> list.contains(item.getSkuId()))));
+                cdu.put("create", CombinationActivityConvert.INSTANCE.complementList(CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
             });
             MapUtils.findAndThen(mapData, "delete", list -> {
                 cdu.put("create", CollectionUtils.filterList(combinationProductDOs, item -> list.contains(item.getSkuId())));
             });
             MapUtils.findAndThen(mapData, "update", list -> {
-                cdu.put("update", CombinationActivityConvert.INSTANCE.convertList1(updateObj,
-                        CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), combinationProductDOs));
+                cdu.put("update", CombinationActivityConvert.INSTANCE.complementList(combinationProductDOs,
+                        CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
             });
             return cdu;
         });
@@ -200,11 +198,6 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         return combinationActivityMapper.selectPage(pageReqVO);
     }
 
-    @Override
-    public List<CombinationActivityDO> getCombinationActivityList(CombinationActivityExportReqVO exportReqVO) {
-        return combinationActivityMapper.selectList(exportReqVO);
-    }
-
     @Override
     public List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids) {
         return combinationProductMapper.selectListByActivityIds(ids);
@@ -236,7 +229,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
             recordDOs.forEach(item -> {
                 item.setUserCount(recordDOs.size());
                 // 校验拼团是否满足要求
-                if (recordDOs.size() >= recordDO.getUserSize()) {
+                if (ObjectUtil.equal(recordDOs.size(), recordDO.getUserSize())) {
                     item.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
                 }
             });
@@ -254,13 +247,30 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
     }
 
     @Override
-    public void createRecord(CombinationRecordReqDTO reqDTO) {
+    public void createRecord(CombinationRecordCreateReqDTO reqDTO) {
         // 校验拼团活动
         CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
-        // TODO @puhui999:需要校验下,它当前是不是已经参加了该拼团;
-        // TODO @puhui999: 父拼团是否存在,是否已经满了
+        // 需要校验下,它当前是不是已经参加了该拼团;
+        CombinationRecordDO recordDO = recordMapper.selectRecord(reqDTO.getUserId(), reqDTO.getOrderId());
+        if (recordDO != null) {
+            throw exception(COMBINATION_RECORD_EXISTS);
+        }
+        // 父拼团是否存在,是否已经满了
+        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);
+            }
+        }
 
         CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
+        if (reqDTO.getHeadId() == null) {
+            record.setHeadId(reqDTO.getUserId());
+        }
         record.setVirtualGroup(false);
         // TODO @puhui999:过期时间,应该是 Date 哈;
         record.setExpireTime(activity.getLimitDuration());
@@ -269,21 +279,17 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
     }
 
     @Override
-    public boolean validateRecordStatusIsSuccess(Long userId, Long orderId) {
-        CombinationRecordDO record = validateCombinationRecord(userId, orderId);
-        // TODO @puhui999:可以搞个 getRecrod 方法,然后业务通过 CombinationRecordStatusEnum.isSuccess 方法校验
-        return ObjectUtil.equal(record.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus());
+    public CombinationRecordDO getRecord(Long userId, Long orderId) {
+        return validateCombinationRecord(userId, orderId);
     }
 
-    // TODO @puhui999:status 传入进来搞哈;
-
     /**
      * APP 端获取开团记录
      *
      * @return 开团记录
      */
-    public List<CombinationRecordDO> getRecordList() {
-        return recordMapper.selectListByStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
+    public List<CombinationRecordDO> getRecordListByStatus(Integer status) {
+        return recordMapper.selectListByStatus(status);
     }
 
 }

+ 32 - 33
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java

@@ -1,10 +1,12 @@
 package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
 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.collection.MapUtils;
 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;
@@ -26,11 +28,10 @@ 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.Set;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+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.validateProductSkuExistence;
@@ -63,8 +64,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         // 获取所选 spu 下的所有 sku
         List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId()));
         // 校验商品 sku 是否存在
-        // TODO @puhui999:直接校验 sku 数量,是不是就完事啦,不需要校验的特别严谨哈;
-        validateProductSkuExistence(createReqVO.getProducts(), skus, SeckillProductCreateReqVO::getSkuId);
+        if (skus.size() != createReqVO.getProducts().size()) {
+            throw exception(SKU_NOT_EXISTS);
+        }
 
         // 插入秒杀活动
         SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
@@ -72,9 +74,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
                 .setTotalStock(CollectionUtils.getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
         seckillActivityMapper.insert(activity);
         // 插入商品
-        // TODO @puhui999:products 要注意复数哈
-        List<SeckillProductDO> product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts());
-        seckillProductMapper.insertBatch(product);
+        List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.complementList(createReqVO.getProducts(), activity);
+        seckillProductMapper.insertBatch(products);
         return activity.getId();
     }
 
@@ -99,11 +100,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         }
         List<SeckillActivityDO> activityDOs2 = CollectionUtils.convertList(activityDOs, c -> c, s -> {
             // 判断秒杀时段是否有交集
-            // TODO @puhui999:是不是 containsAny 就是有交集呀
-            List<Long> configIdsClone = CollUtil.newArrayList(s.getConfigIds());
-            configIdsClone.retainAll(configIds);
-            return CollUtil.isNotEmpty(configIdsClone);
+            return CollectionUtils.containsAny(s.getConfigIds(), configIds);
         });
+
         if (CollUtil.isNotEmpty(activityDOs2)) {
             throw exception(SECKILL_TIME_CONFLICTS);
         }
@@ -147,31 +146,31 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         // 数据库中的活动商品
         List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateObj.getId());
         Set<Long> dbSkuIds = CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getSkuId);
-        // 1. 删除后台存在的前端不存在的商品
-        // TODO @puhui999:delete 应该是 id,不是 skuId 哈
         Set<Long> voSkuIds = CollectionUtils.convertSet(products, SeckillProductUpdateReqVO::getSkuId);
-        List<Long> d = CollectionUtils.filterList(dbSkuIds, item -> !voSkuIds.contains(item));
-        if (CollUtil.isNotEmpty(d)) {
-            seckillProductMapper.deleteBatchIds(d);
-        }
-        // 2. 前端存在的后端不存在的商品
-        List<Long> c = CollectionUtils.filterList(voSkuIds, item -> !dbSkuIds.contains(item));
-        if (CollUtil.isNotEmpty(c)) {
-            List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> c.contains(item.getSkuId()));
-            List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(updateObj, vos);
-            seckillProductMapper.insertBatch(productDOs);
-        }
-        // 3. 更新已存在的商品
-        List<Long> u = CollectionUtils.filterList(voSkuIds, dbSkuIds::contains);
-        if (CollUtil.isNotEmpty(u)) {
-            List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> u.contains(item.getSkuId()));
-            List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList1(updateObj, vos, seckillProductDOs);
-            seckillProductMapper.updateBatch(productDOs);
-        }
+        Map<String, List<SeckillProductDO>> data = CollectionUtils.convertCDUMap(voSkuIds, dbSkuIds, mapData -> {
+            HashMap<String, List<SeckillProductDO>> cdu = MapUtil.newHashMap(3);
+            MapUtils.findAndThen(mapData, "create", list -> {
+                cdu.put("create", SeckillActivityConvert.INSTANCE.complementList(
+                        CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
+            });
+            MapUtils.findAndThen(mapData, "delete", list -> {
+                cdu.put("create", CollectionUtils.filterList(seckillProductDOs, item -> list.contains(item.getSkuId())));
+            });
+            MapUtils.findAndThen(mapData, "update", list -> {
+                cdu.put("update", SeckillActivityConvert.INSTANCE.complementList(seckillProductDOs,
+                        CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
+            });
+            return cdu;
+        });
+
+        // 执行增删改
+        MapUtils.findAndThen(data, "create", item -> seckillProductMapper.insertBatch(item));
+        MapUtils.findAndThen(data, "delete", item -> seckillProductMapper.deleteBatchIds(
+                CollectionUtils.convertSet(item, SeckillProductDO::getId)));
+        MapUtils.findAndThen(data, "update", item -> seckillProductMapper.updateBatch(item));
     }
 
     @Override
-    @Transactional(rollbackFor = Exception.class) // TODO @puhui999:这个不用加事务哈
     public void closeSeckillActivity(Long id) {
         // TODO 待验证没使用过
         // 校验存在

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

@@ -73,9 +73,10 @@ public interface SeckillConfigService {
     /**
      * 获得所有正常状态的时段配置列表
      *
+     * @param status 状态
      * @return 秒杀时段列表
      */
-    List<SeckillConfigDO> getListAllSimple();
+    List<SeckillConfigDO> getSeckillConfigListByStatus(Integer status);
 
     /**
      * 更新秒杀时段配置状态

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

@@ -62,7 +62,7 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
         seckillConfigMapper.updateById(updateObj);
     }
 
-    // TODO  @puhui999: 这个要不合并到更新操作里? 不单独有个操作咧; 更新状态不用那么多必须的参数,更新的时候需要校验时间段
+    // TODO  @puhui999: 这个要不合并到更新操作里? 不单独有个操作咧; fix: 更新状态不用那么多必须的参数,更新的时候需要校验时间段
     @Override
     public void updateSeckillConfigStatus(Long id, Integer status) {
         // 校验秒杀时段是否存在
@@ -108,7 +108,7 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
             LocalTime startTime2 = LocalTime.parse(config.getStartTime());
             LocalTime endTime2 = LocalTime.parse(config.getEndTime());
             // 判断时间是否重叠
-            return LocalDateTimeUtils.checkTimeOverlap(startTime1, endTime1, startTime2, endTime2);
+            return LocalDateTimeUtils.isOverlap(startTime1, endTime1, startTime2, endTime2);
         });
 
         if (hasConflict) {
@@ -151,10 +151,9 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
         return seckillConfigMapper.selectPage(pageVO);
     }
 
-    // TODO @puhui999:改成传入 enable 状态哈。一个通用的 getSeckillConfigList 方法
     @Override
-    public List<SeckillConfigDO> getListAllSimple() {
-        return seckillConfigMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+    public List<SeckillConfigDO> getSeckillConfigListByStatus(Integer status) {
+        return seckillConfigMapper.selectListByStatus(status);
     }
 
 }

+ 5 - 28
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java

@@ -3,17 +3,15 @@ package cn.iocoder.yudao.module.promotion.service.combination;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
 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.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationActivityMapper;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
-import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
@@ -26,15 +24,15 @@ import static org.junit.jupiter.api.Assertions.*;
 
 // TODO 芋艿:等完成后,在补全单测
 /**
- * {@link CombinationActivityServiceImpl} 的单元测试类
+ * {@link CombinationServiceImpl} 的单元测试类
  *
  * @author HUIHUI
  */
-@Import(CombinationActivityServiceImpl.class)
+@Import(CombinationServiceImpl.class)
 public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
 
     @Resource
-    private CombinationActivityServiceImpl combinationActivityService;
+    private CombinationServiceImpl combinationActivityService;
 
     @Resource
     private CombinationActivityMapper combinationActivityMapper;
@@ -225,28 +223,7 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
         combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setLimitDuration(null)));
         // 测试 createTime 不匹配
         combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setCreateTime(null)));
-        // 准备参数
-        CombinationActivityExportReqVO reqVO = new CombinationActivityExportReqVO();
-        reqVO.setName(null);
-        reqVO.setSpuId(null);
-        reqVO.setTotalLimitCount(null);
-        reqVO.setSingleLimitCount(null);
-        reqVO.setStartTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
-        reqVO.setEndTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
-        reqVO.setUserSize(null);
-        reqVO.setTotalNum(null);
-        reqVO.setSuccessNum(null);
-        reqVO.setOrderUserCount(null);
-        reqVO.setVirtualGroup(null);
-        reqVO.setStatus(null);
-        reqVO.setLimitDuration(null);
-        reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
 
-        // 调用
-        List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(reqVO);
-        // 断言
-        assertEquals(1, list.size());
-        assertPojoEquals(dbCombinationActivity, list.get(0));
     }
 
 }

+ 4 - 6
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java

@@ -31,6 +31,10 @@ public interface ErrorCodeConstants {
     ErrorCode ORDER_COMMENT_STATUS_NOT_FALSE = new ErrorCode(1011000020, "创建交易订单项的评价失败,订单已评价");
     ErrorCode ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE = new ErrorCode(1011000021, "交易订单发货失败,订单已退款或部分退款");
     ErrorCode ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000022, "交易订单发货失败,拼团未成功");
+    // TODO 已移除订单单独发货
+    ErrorCode ORDER_DELIVERY_FAILED_ITEMS_NOT_EMPTY = new ErrorCode(1011000023, "订单发货失败,请选择发货商品");
+    ErrorCode ORDER_DELIVERY_FAILED_ITEM_NOT_EXISTS = new ErrorCode(1011000024, "订单发货失败,所选发货商品不存在");
+    ErrorCode ORDER_DELIVERY_FAILED_ITEM_ALREADY_DELIVERY = new ErrorCode(1011000025, "订单发货失败,所选商品已发货");
 
     // ==========  After Sale 模块 1011000100 ==========
     ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
@@ -69,10 +73,4 @@ public interface ErrorCodeConstants {
     // ==========  物流 PICK_UP 模块 1011006000 ==========
     ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011006000, "自提门店不存在");
 
-    // ==========  物流 PICK_UP 模块 1011007000 ==========
-    // TODO @puhui999:这几个错误码,应该属于订单哈
-    ErrorCode ORDER_DELIVERY_FAILED_ITEMS_NOT_EMPTY = new ErrorCode(1011007000, "订单发货失败,请选择发货商品");
-    ErrorCode ORDER_DELIVERY_FAILED_ITEM_NOT_EXISTS = new ErrorCode(1011007001, "订单发货失败,所选发货商品不存在");
-    ErrorCode ORDER_DELIVERY_FAILED_ITEM_ALREADY_DELIVERY = new ErrorCode(1011007002, "订单发货失败,所选商品已发货");
-
 }

+ 3 - 9
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDeliveryReqVO.java

@@ -5,8 +5,8 @@ import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
-import java.util.List;
 
 @Schema(description = "管理后台 - 订单发货 Request VO")
 @Data
@@ -21,20 +21,14 @@ public class TradeOrderDeliveryReqVO {
     @NotNull(message = "发货类型不能为空")
     private Integer type;
 
-    // TODO @puhui999:还是要校验下
-
     @Schema(description = "发货物流公司编号", example = "1")
+    @NotNull(message = "发货物流公司不能为空")
     private Long logisticsId;
 
     @Schema(description = "发货物流单号", example = "SF123456789")
+    @NotEmpty(message = "发货物流单号不能为空")
     private String logisticsNo;
 
-    // TODO 订单项商品单独发货;不做单独发
-
-    @Schema(description = "发货订单项", example = "[1,2,3]")
-    @NotNull(message = "发货订单项不能为空")
-    private List<Long> orderItemIds;
-
     // =============== 同城配送  ================
     // TODO
 

+ 2 - 15
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -13,12 +13,11 @@ import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
-import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageItemRespVO;
 import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
@@ -27,7 +26,6 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderI
 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.order.TradeOrderDO;
-import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDeliveryDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
@@ -334,17 +332,6 @@ public interface TradeOrderConvert {
             @Mapping(target = "avatar", source = "user.avatar"),
             @Mapping(target = "status", ignore = true)
     })
-    CombinationRecordReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem, AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
-
-    TradeOrderDeliveryDO covert(Long orderId, Long orderItemId, Long userId, Integer deliveryType, Long logisticsId, String logisticsNo);
-
-    default List<TradeOrderDeliveryDO> covert(TradeOrderDO order, TradeOrderDeliveryReqVO deliveryReqVO) {
-        ArrayList<TradeOrderDeliveryDO> arrayList = new ArrayList<>();
-        deliveryReqVO.getOrderItemIds().forEach(item -> {
-            arrayList.add(covert(order.getId(), item, order.getUserId(), deliveryReqVO.getType(),
-                    deliveryReqVO.getLogisticsId(), deliveryReqVO.getLogisticsNo()));
-        });
-        return arrayList;
-    }
+    CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem, AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
 
 }

+ 0 - 60
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDeliveryDO.java

@@ -1,60 +0,0 @@
-package cn.iocoder.yudao.module.trade.dal.dataobject.order;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-// TODO @puhui999:
-/**
- * 交易订单发货记录 DO
- *
- * @author HUIHUI
- */
-@TableName("trade_order_delivery")
-@KeySequence("trade_order_delivery_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class TradeOrderDeliveryDO extends BaseDO {
-
-    /**
-     * 订单发货记录 id
-     */
-    private Long id;
-    /**
-     * 订单 id
-     */
-    private Long orderId;
-    /**
-     * 订单项 id TODO 要不要一个发货记录可对应多个订单项?
-     */
-    private Long orderItemId;
-    /**
-     * 用户编号
-     *
-     * 关联 MemberUserDO 的 id 编号
-     */
-    private Long userId;
-    /**
-     * 配送方式
-     *
-     * 枚举 {@link DeliveryTypeEnum}
-     */
-    private Integer deliveryType;
-    /**
-     * 发货物流公司编号
-     */
-    private Long logisticsId;
-    /**
-     * 发货物流单号
-     */
-    private String logisticsNo;
-
-    // TODO 同城配送
-
-}

+ 0 - 24
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderDeliveryMapper.java

@@ -1,24 +0,0 @@
-package cn.iocoder.yudao.module.trade.dal.mysql.order;
-
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDeliveryDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.List;
-
-// TODO @puhui999:应该去掉啦
-/**
- * 交易订单发货记录 Mapper
- *
- * @author HUIHUI
- */
-@Mapper
-public interface TradeOrderDeliveryMapper extends BaseMapperX<TradeOrderDeliveryDO> {
-
-    default List<TradeOrderDeliveryDO> selsectListByOrderIdAndItemIds(Long orderId, List<Long> orderItemIds) {
-        return selectList(new LambdaQueryWrapperX<TradeOrderDeliveryDO>()
-                .eq(TradeOrderDeliveryDO::getOrderId, orderId).in(TradeOrderDeliveryDO::getOrderItemId, orderItemIds));
-    }
-
-}

+ 19 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageService.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.trade.service.message;
+
+import cn.iocoder.yudao.module.trade.service.message.dto.TradeOrderMessageWhenDeliveryOrderReqDTO;
+
+/**
+ * Trade 消息 service 接口
+ *
+ * @author HUIHUI
+ */
+public interface TradeMessageService {
+
+    /**
+     * 订单发货时发送消息
+     *
+     * @param reqDTO 发送消息
+     */
+    void sendMessageWhenDeliveryOrder(TradeOrderMessageWhenDeliveryOrderReqDTO reqDTO);
+
+}

+ 39 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.trade.service.message;
+
+import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
+import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
+import cn.iocoder.yudao.module.trade.service.message.dto.TradeOrderMessageWhenDeliveryOrderReqDTO;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Trade 消息 service 实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+@Validated
+public class TradeMessageServiceImpl implements TradeMessageService {
+
+    @Resource
+    private NotifyMessageSendApi notifyMessageSendApi;
+
+    @Override
+    public void sendMessageWhenDeliveryOrder(TradeOrderMessageWhenDeliveryOrderReqDTO reqDTO) {
+        // 1、构造消息
+        Map<String, Object> msgMap = new HashMap<>();
+        msgMap.put("orderId", reqDTO.getOrderId());
+        msgMap.put("msg", reqDTO.getMessage());
+        // 2、发送站内信
+        notifyMessageSendApi.sendSingleMessageToMember(
+                new NotifySendSingleToUserReqDTO()
+                        .setUserId(reqDTO.getUserId())
+                        .setTemplateCode("order_delivery")
+                        .setTemplateParams(msgMap));
+    }
+
+}

+ 32 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/dto/TradeOrderMessageWhenDeliveryOrderReqDTO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.trade.service.message.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 订单发货时 Req DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class TradeOrderMessageWhenDeliveryOrderReqDTO {
+
+    /**
+     * 订单编号
+     */
+    @NotNull(message = "订单编号不能为空")
+    private Long orderId;
+    /**
+     * 用户编号
+     */
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+    /**
+     * 消息
+     */
+    @NotEmpty(message = "发送消息不能为空")
+    private String message;
+
+}

+ 33 - 80
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java

@@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.core.KeyValue;
 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.module.member.api.address.AddressApi;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
@@ -21,12 +22,10 @@ import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
+import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
-import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
-import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
@@ -38,9 +37,7 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
 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.TradeOrderDeliveryDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
-import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderDeliveryMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
@@ -49,6 +46,8 @@ import cn.iocoder.yudao.module.trade.enums.order.*;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 import cn.iocoder.yudao.module.trade.service.cart.TradeCartService;
 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
+import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
+import cn.iocoder.yudao.module.trade.service.message.dto.TradeOrderMessageWhenDeliveryOrderReqDTO;
 import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
@@ -102,15 +101,13 @@ public class TradeOrderServiceImpl implements TradeOrderService {
     @Resource
     private ProductCommentApi productCommentApi;
     @Resource
-    private NotifyMessageSendApi notifyMessageSendApi;
-
+    private TradeMessageService tradeMessageService;
     @Resource
     private TradeOrderProperties tradeOrderProperties;
 
     @Resource
-    private CombinationApi combinationApi;
-    @Resource
-    private TradeOrderDeliveryMapper orderDeliveryMapper;
+    private CombinationRecordApi combinationRecordApi;
+
     // =================== Order ===================
 
     @Override
@@ -177,7 +174,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
             MemberUserRespDTO user = memberUserApi.getUser(userId);
             // TODO 拼团一次应该只能选择一种规格的商品
-            combinationApi.createRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user)
+            combinationRecordApi.createRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user)
                     .setStatus(CombinationRecordStatusEnum.WAITING.getStatus()));
         }
         // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
@@ -314,7 +311,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         // 1、拼团活动
         if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
             // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
-            combinationApi.updateRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
+            combinationRecordApi.updateRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
         }
         // TODO 芋艿:发送订单变化的消息
 
@@ -385,23 +382,26 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         // 校验并获得交易订单(可发货)
         TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
 
-        TradeOrderDO tradeOrderDO = new TradeOrderDO();
-        List<TradeOrderDeliveryDO> deliveryDOs = new ArrayList<>();
         /* TODO
          * fix: 首先需要店铺设置配送方式如: 自提 、配送、物流-配送、物流-配送-自提、商家配送
          * 1.如果店铺有设置配送方式用户只填写收货地址的情况下店家后台自己选择配送方式
          * 2.如果店铺只支持到店自提那么下单后默认发货不需要物流
          * 3.如果店铺支持 物流-配送-自提 的情况下后台不需要选择配送方式按前端用户选择的配送方式发货即可
          */
+        TradeOrderDO tradeOrderDO = new TradeOrderDO();
         // 判断发货类型
         // 快递发货
         if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.EXPRESS.getMode())) {
-            deliveryDOs = express(order, deliveryReqVO);
+            // 校验快递公司
+            DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
+            if (deliveryExpress == null) {
+                throw exception(EXPRESS_NOT_EXISTS);
+            }
             tradeOrderDO.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
         }
         // 用户自提
         if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.PICK_UP.getMode())) {
-            deliveryDOs = pickUp(order, deliveryReqVO);
+            // TODO 校验自提门店是否存在
             // 重置一下确保快递公司和快递单号为空
             tradeOrderDO.setLogisticsId(null).setLogisticsNo("");
         }
@@ -409,6 +409,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.NULL.getMode())) {
             // TODO 情况一:正常走发货逻辑和用户自提有点像 不同点:不需要自提门店只需要用户确认收货
             // TODO 情况二:用户下单付款后直接确认收货或等待用户确认收货
+            // 重置一下确保快递公司和快递单号为空
+            tradeOrderDO.setLogisticsId(null).setLogisticsNo("");
         }
 
         // 更新 TradeOrderDO 状态为已发货,等待收货
@@ -418,72 +420,16 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         if (updateCount == 0) {
             throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
         }
-        // 发货成功记录发货表
-        orderDeliveryMapper.insertBatch(deliveryDOs);
         // TODO 芋艿:发送订单变化的消息
 
-        // TODO @puhui999:可以抽个 message 包,里面是 Order 所有的 message;类似工作流的
         // 发送站内信
-        // 1、构造消息
-        Map<String, Object> msgMap = new HashMap<>();
-        msgMap.put("orderId", deliveryReqVO.getId());
-        msgMap.put("msg", TradeOrderStatusEnum.DELIVERED.getStatus());
-        // 2、发送站内信
-        notifyMessageSendApi.sendSingleMessageToMember(
-                new NotifySendSingleToUserReqDTO()
-                        .setUserId(userId)
-                        .setTemplateCode("order_delivery")
-                        .setTemplateParams(msgMap));
+        tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqDTO().setOrderId(order.getId())
+                .setUserId(userId).setMessage(TradeOrderDeliveryStatusEnum.DELIVERED.getName()));
 
         // TODO 芋艿:OrderLog
         // TODO 设计:lili:是不是发货后,才支持售后?
     }
 
-    private List<TradeOrderDeliveryDO> express(TradeOrderDO order, TradeOrderDeliveryReqVO deliveryReqVO) {
-        // 校验快递公司
-        DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
-        if (deliveryExpress == null) {
-            throw exception(EXPRESS_NOT_EXISTS);
-        }
-        // 校验发货商品
-        validateDeliveryOrderItem(order, deliveryReqVO);
-        // 创建发货记录
-        return TradeOrderConvert.INSTANCE.covert(order, deliveryReqVO);
-    }
-
-    private List<TradeOrderDeliveryDO> pickUp(TradeOrderDO order, TradeOrderDeliveryReqVO deliveryReqVO) {
-        // TODO 校验自提门店是否存在
-        // 重置一下确保快递公司和快递单号为空
-        deliveryReqVO.setLogisticsId(null);
-        deliveryReqVO.setLogisticsNo("");
-        // 校验发货商品
-        validateDeliveryOrderItem(order, deliveryReqVO);
-        // 创建发货记录
-        return TradeOrderConvert.INSTANCE.covert(order, deliveryReqVO);
-    }
-
-    private void validateDeliveryOrderItem(TradeOrderDO order, TradeOrderDeliveryReqVO deliveryReqVO) {
-        // TODO 设计:like:是否要单独一个 delivery 发货单表??? fix: 多商品可分开单独发货,添加 trade_order_delivery 交易订单发货日志表关联发货所选订单项设置物流单号
-        // TODO 设计:niu:要不要支持一个订单下,多个 order item 单独发货,类似有赞 fix
-        // 校验发货商品
-        if (CollUtil.isEmpty(deliveryReqVO.getOrderItemIds())) {
-            throw exception(ORDER_DELIVERY_FAILED_ITEMS_NOT_EMPTY);
-        }
-        // 校验发货商品是否存在
-        List<TradeOrderItemDO> orderItemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
-        Set<Long> itemIds = convertSet(orderItemDOs, TradeOrderItemDO::getId);
-        if (!itemIds.containsAll(deliveryReqVO.getOrderItemIds())) {
-            throw exception(ORDER_DELIVERY_FAILED_ITEM_NOT_EXISTS);
-        }
-        // 校验所选订单项是否存在有已发货的
-        List<TradeOrderDeliveryDO> deliveryDOList = orderDeliveryMapper.selsectListByOrderIdAndItemIds(order.getId(), deliveryReqVO.getOrderItemIds());
-        if (CollUtil.isNotEmpty(deliveryDOList)) {
-            HashSet<Long> hashSet = CollUtil.newHashSet(deliveryReqVO.getOrderItemIds());
-            hashSet.retainAll(convertSet(deliveryDOList, TradeOrderDeliveryDO::getOrderItemId));
-            throw exception(ORDER_DELIVERY_FAILED_ITEM_ALREADY_DELIVERY);
-        }
-    }
-
     /**
      * 校验交易订单满足被发货的条件
      *
@@ -511,7 +457,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
             // 校验订单拼团是否成功
             // TODO 用户 ID 使用当前登录用户的还是订单保存的?
-            if (combinationApi.validateRecordStatusIsSuccess(order.getUserId(), order.getId())) {
+            if (combinationRecordApi.validateRecordStatusIsSuccess(order.getUserId(), order.getId())) {
                 throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS);
             }
         }
@@ -532,7 +478,6 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         if (updateCount == 0) {
             throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
         }
-
         // TODO 芋艿:OrderLog
 
         // TODO 芋艿:lili 发送订单变化的消息
@@ -683,6 +628,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Long createOrderItemComment(AppTradeOrderItemCommentCreateReqVO createReqVO) {
         Long loginUserId = getLoginUserId();
         // 先通过订单项 ID,查询订单项是否存在
@@ -690,7 +636,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         if (orderItem == null) {
             throw exception(ORDER_ITEM_NOT_FOUND);
         }
-        // 校验订单
+        // 校验订单相关状态
         TradeOrderDO order = getOrderByIdAndUserId(orderItem.getOrderId(), loginUserId);
         if (order == null) {
             throw exception(ORDER_NOT_FOUND);
@@ -701,11 +647,18 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         if (ObjectUtil.notEqual(order.getCommentStatus(), Boolean.FALSE)) {
             throw exception(ORDER_COMMENT_STATUS_NOT_FALSE);
         }
-        // TODO @puhui999:是不是评论完,要更新 status、commentStatus;另外,是不是上面 order 可以不校验,直接只判断 orderItem 就够;
-        // 对于 order 来说,就是评论完,把 order 更新完合理的 status 等字段。
 
+        // 创建评价
         ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItem);
-        return productCommentApi.createComment(productCommentCreateReqDTO);
+        Long comment = productCommentApi.createComment(productCommentCreateReqDTO);
+        // 更新订单项评价状态
+        tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE));
+        List<TradeOrderItemDO> orderItems = getOrderItemListByOrderId(CollUtil.newArrayList(order.getId()));
+        if (!CollectionUtils.isAny(orderItems, item -> ObjectUtil.equal(item.getCommentStatus(), Boolean.FALSE))) {
+            // 对于 order 来说,就是评论完,把 order 更新完合理的 status 等字段。
+            tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE));
+        }
+        return comment;
     }
 
     /**