Browse Source

初步完成商品CRUD

puhui999 2 years ago
parent
commit
70816371e5
16 changed files with 132 additions and 183 deletions
  1. 10 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
  2. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
  3. 14 47
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
  4. 0 24
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
  5. 31 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageRespVO.java
  6. 0 18
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
  7. 1 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
  8. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
  9. 3 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java
  10. 0 13
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
  11. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
  12. 2 4
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
  13. 20 10
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
  14. 38 25
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
  15. 1 1
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java
  16. 9 33
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java

+ 10 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java

@@ -50,4 +50,14 @@ public class ProductSkuBaseVO {
 
     @Schema(description = "商品体积", example = "1024") // 单位:m^3 平米
     private Double volume;
+    /**
+     * 一级分销的佣金,单位:分
+     */
+    @Schema(description = "一级分销的佣金", example = "1024")
+    private Integer subCommissionFirstPrice;
+    /**
+     * 二级分销的佣金,单位:分
+     */
+    @Schema(description = "二级分销的佣金", example = "1024")
+    private Integer subCommissionSecondPrice;
 }

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java

@@ -94,7 +94,7 @@ public class ProductSpuController {
     @GetMapping("/page")
     @Operation(summary = "获得商品 SPU 分页")
     @PreAuthorize("@ss.hasPermission('product:spu:query')")
-    public CommonResult<PageResult<ProductSpuRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
+    public CommonResult<PageResult<ProductSpuPageRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
         return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO)));
     }
 

+ 14 - 47
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java

@@ -38,16 +38,11 @@ public class ProductSpuBaseVO {
     @NotEmpty(message = "商品详情不能为空")
     private String description;
 
-    @Schema(description = "商品条码(一维码)", required = true, example = "芋道")
-    @NotEmpty(message = "商品条码(一维码)不能为空")
-    private String barCode;
-
     @Schema(description = "商品分类编号", required = true, example = "芋道")
-    @NotEmpty(message = "商品分类编号不能为空")
+    @NotNull(message = "商品分类编号不能为空")
     private Long categoryId;
 
     @Schema(description = "商品品牌编号", required = true, example = "芋道")
-    @NotEmpty(message = "商品品牌编号不能为空")
     private Long brandId;
 
     @Schema(description = "商品封面图", required = true, example = "芋道")
@@ -55,99 +50,71 @@ public class ProductSpuBaseVO {
     private String picUrl;
 
     @Schema(description = "商品轮播图", required = true)
-    @NotEmpty(message = "商品轮播图不能为空")
     private List<String> sliderPicUrls;
 
     @Schema(description = "商品视频")
     private String videoUrl;
 
     @Schema(description = "单位", required = true, example = "1")
-    @NotEmpty(message = "商品单位不能为空")
+    @NotNull(message = "商品单位不能为空")
     private Integer unit;
 
     @Schema(description = "排序字段", required = true, example = "1")
-    @NotEmpty(message = "商品排序字段不能为空")
+    @NotNull(message = "商品排序字段不能为空")
     private Integer sort;
 
-    @Schema(description = "商品状态", required = true, example = "1")
-    @NotEmpty(message = "商品状态不能为空")
-    private Integer status;
-
     // ========== SKU 相关字段 =========
 
     @Schema(description = "规格类型", required = true, example = "true")
-    @NotEmpty(message = "商品规格类型不能为空")
+    @NotNull(message = "商品规格类型不能为空")
     private Boolean specType;
 
-    @Schema(description = "商品价格", required = true, example = "1212")
-    @NotEmpty(message = "商品价格不能为空")
-    private Integer price;
-
-    @Schema(description = "市场价", required = true, example = "3")
-    @NotEmpty(message = "商品市场价不能为空")
-    private Integer marketPrice;
-
-    @Schema(description = "成本价", required = true, example = "12")
-    @NotEmpty(message = "商品成本价不能为空")
-    private Integer costPrice;
-
-    @Schema(description = "库存", required = true, example = "111")
-    @NotEmpty(message = "商品库存不能为空")
-    private Integer stock;
-
     // ========== 物流相关字段 =========
 
     @Schema(description = "物流配置模板编号", required = true, example = "111")
-    @NotEmpty(message = "物流配置模板编号不能为空")
+    @NotNull(message = "物流配置模板编号不能为空")
     private Long deliveryTemplateId;
 
     // ========== 营销相关字段 =========
 
     @Schema(description = "是否热卖推荐", required = true, example = "true")
-    @NotEmpty(message = "商品推荐不能为空")
+    @NotNull(message = "商品推荐不能为空")
     private Boolean recommendHot;
 
     @Schema(description = "是否优惠推荐", required = true, example = "true")
-    @NotEmpty(message = "商品推荐不能为空")
+    @NotNull(message = "商品推荐不能为空")
     private Boolean recommendBenefit;
 
     @Schema(description = "是否精品推荐", required = true, example = "true")
-    @NotEmpty(message = "商品推荐不能为空")
+    @NotNull(message = "商品推荐不能为空")
     private Boolean recommendBest;
 
     @Schema(description = "是否新品推荐", required = true, example = "true")
-    @NotEmpty(message = "商品推荐不能为空")
+    @NotNull(message = "商品推荐不能为空")
     private Boolean recommendNew;
 
     @Schema(description = "是否优品推荐", required = true, example = "true")
-    @NotEmpty(message = "商品推荐不能为空")
+    @NotNull(message = "商品推荐不能为空")
     private Boolean recommendGood;
 
     @Schema(description = "赠送积分", required = true, example = "111")
-    @NotEmpty(message = "商品赠送积分不能为空")
+    @NotNull(message = "商品赠送积分不能为空")
     private Integer giveIntegral;
 
-    @Schema(description = "赠送的优惠劵编号的数组")
+    @Schema(description = "赠送的优惠劵编号的数组") // TODO 这块前端还未实现
     private List<Long> giveCouponTemplateIds;
 
     @Schema(description = "分销类型")
+    @NotNull(message = "商品分销类型不能为空")
     private Boolean subCommissionType;
 
-    @Schema(description = "活动展示顺序")
+    @Schema(description = "活动展示顺序") // TODO 这块前端还未实现
     private List<Integer> activityOrders;
 
     // ========== 统计相关字段 =========
 
-    @Schema(description = "商品销量", required = true, example = "芋道")
-    @NotEmpty(message = "商品销量不能为空")
-    private Integer salesCount;
-
     @Schema(description = "虚拟销量", required = true, example = "芋道")
-    @NotEmpty(message = "商品虚拟销量不能为空")
     private Integer virtualSalesCount;
 
-    @Schema(description = "浏览量", required = true, example = "芋道")
-    @NotEmpty(message = "商品浏览量不能为空")
-    private Integer browseCount;
 
 }

+ 0 - 24
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java

@@ -15,31 +15,7 @@ public class ProductSpuPageReqVO extends PageParam {
     @Schema(description = "商品名称", example = "yutou")
     private String name;
 
-    @Schema(description = "商品编码", example = "yudaoyuanma")
-    private String code;
-
     @Schema(description = "分类编号", example = "1")
     private Long categoryId;
 
-    @Schema(description = "商品品牌编号", example = "1")
-    private Long brandId;
-
-    @Schema(description = "上下架状态", example = "1")
-    private Integer status;
-
-    @Schema(description = "销量最小值", example = "1")
-    private Integer salesCountMin;
-
-    @Schema(description = "销量最大值", example = "1024")
-    private Integer salesCountMax;
-
-    @Schema(description = "市场价最小值", example = "1")
-    private Integer marketPriceMin;
-
-    @Schema(description = "市场价最大值", example = "1024")
-    private Integer marketPriceMax;
-
-    @Schema(description = "是否库存告警", example = "true")
-    private Boolean alarmStock;
-
 }

+ 31 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageRespVO.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 商品 SPU 分页 response VO")
+@Data
+public class ProductSpuPageRespVO {
+    @Schema(description = "spuId", example = "1")
+    private Long id;
+    @Schema(description = "商品封面图", example = "1")
+    private String picUrl;
+    @Schema(description = "商品名称", example = "1")
+    private String name;
+    @Schema(description = "商品价格", example = "1")
+    private Integer price;
+    @Schema(description = "商品销量", example = "1")
+    private Integer salesCount;
+    @Schema(description = "商品排序", example = "1")
+    private Integer stock;
+    @Schema(description = "商品封面图", example = "1")
+    private Integer sort;
+    @Schema(description = "商品创建时间", example = "1")
+    private LocalDateTime createTime;
+    @Schema(description = "商品状态", example = "1")
+    private Integer status;
+}

+ 0 - 18
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java

@@ -19,22 +19,4 @@ public class ProductSpuRespVO extends ProductSpuBaseVO {
     @Schema(description = "创建时间")
     private LocalDateTime createTime;
 
-    // ========== SKU 相关字段 =========
-
-    @Schema(description = "库存", required = true, example = "true")
-    private Integer totalStock;
-
-    @Schema(description = " 最小价格,单位使用:分", required = true, example = "1024")
-    private Integer minPrice;
-
-    @Schema(description = "最大价格,单位使用:分", required = true, example = "1024")
-    private Integer maxPrice;
-
-    @Schema(description = "商品销量", example = "1024")
-    private Integer salesCount;
-
-    // ========== 统计相关字段 =========
-
-    @Schema(description = "点击量", example = "1024")
-    private Integer clickCount;
 }

+ 1 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java

@@ -35,9 +35,8 @@ public interface ProductSkuConvert {
 
     List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list);
 
-    default List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId, String spuName) {
+    default List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId) {
         List<ProductSkuDO> result = convertList06(list);
-        // result.forEach(item -> item.setSpuId(spuId).setSpuName(spuName)); TODO ProductSkuDO中已经没有name相关属性
         result.forEach(item -> item.setSpuId(spuId));
         return result;
     }

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

@@ -38,7 +38,7 @@ public interface ProductSpuConvert {
 
     List<ProductSpuDO> convertList(List<ProductSpuDO> list);
 
-    PageResult<ProductSpuRespVO> convertPage(PageResult<ProductSpuDO> page);
+    PageResult<ProductSpuPageRespVO> convertPage(PageResult<ProductSpuDO> page);
 
     ProductSpuPageReqVO convert(AppProductSpuPageReqVO bean);
 

+ 3 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java

@@ -116,19 +116,19 @@ public class ProductSpuDO extends TenantBaseDO {
     /**
      * 商品价格,单位使用:分
      *
-     * 基于其对应的 {@link ProductSkuDO#getPrice()} 最小值
+     * 基于其对应的 {@link ProductSkuDO#getPrice()} sku单价最低的商品的
      */
     private Integer price;
     /**
      * 市场价,单位使用:分
      *
-     * 基于其对应的 {@link ProductSkuDO#getMarketPrice()} 最大值 TODO 芋艿:待确定最大还是最小
+     * 基于其对应的 {@link ProductSkuDO#getMarketPrice()} sku单价最低的商品的
      */
     private Integer marketPrice;
     /**
      * 成本价,单位使用:分
      *
-     * 基于其对应的 {@link ProductSkuDO#getCostPrice()} 最大值 TODO 芋艿:待确定最大还是最小
+     * 基于其对应的 {@link ProductSkuDO#getCostPrice()} sku单价最低的商品的
      */
     private Integer costPrice;
     /**

+ 0 - 13
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java

@@ -24,11 +24,6 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
         return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
                 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
                 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
-                .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
-                .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
-                .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
-                .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
-                .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
                 .orderByDesc(ProductSpuDO::getSort));
     }
 
@@ -36,13 +31,7 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
         return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
                 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
                 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
-                .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
-                .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
-                .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
-                .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
-                .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
                 .inIfPresent(ProductSpuDO::getId, alarmStockSpuIds) // 库存告警
-                .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
                 .orderByDesc(ProductSpuDO::getSort));
     }
 
@@ -52,8 +41,6 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
                 .eqIfPresent(ProductSpuDO::getStatus, status);
         // 排序逻辑
         if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) {
-            // TODO ProductSpuDO 已经没有maxPrice 属性
-            //query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getMaxPrice);
         } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) {
             query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getSalesCount);
         }

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java

@@ -100,7 +100,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
         if (category == null) {
             throw exception(CATEGORY_NOT_EXISTS);
         }
-        if (Objects.equals(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
+        if (Objects.equals(category.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
             throw exception(CATEGORY_DISABLED, category.getName());
         }
     }

+ 2 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java

@@ -56,19 +56,17 @@ public interface ProductSkuService {
      * 批量创建 SKU
      *
      * @param spuId 商品 SPU 编号
-     * @param spuName 商品 SPU 名称
      * @param list SKU 对象集合
      */
-    void createSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> list);
+    void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list);
 
     /**
      * 根据 SPU 编号,批量更新它的 SKU 信息
      *
      * @param spuId SPU 编码
-     * @param spuName 商品 SPU 名称
      * @param skus SKU 的集合
      */
-    void updateSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skus);
+    void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
 
     /**
      * 更新 SKU 库存(增量)

+ 20 - 10
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java

@@ -84,10 +84,17 @@ public class ProductSkuServiceImpl implements ProductSkuService {
             return;
         }
 
+        // 0、校验skus是否为空
+        if (CollUtil.isEmpty(skus)){
+            throw exception(SKU_NOT_EXISTS);
+        }
+
         // 1、校验属性项存在
         Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null)
-                .flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性
-                .map(ProductSkuCreateOrUpdateReqVO.Property::getPropertyId) // 将每个 Property 转换成对应的 propertyId,最后形成集合
+                // 遍历多个 Property 属性
+                .flatMap(p -> p.getProperties().stream())
+                // 将每个 Property 转换成对应的 propertyId,最后形成集合
+                .map(ProductSkuCreateOrUpdateReqVO.Property::getPropertyId)
                 .collect(Collectors.toSet());
         List<ProductPropertyDO> propertyList = productPropertyService.getPropertyList(propertyIds);
         if (propertyList.size() != propertyIds.size()) {
@@ -107,22 +114,24 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         int attrValueIdsSize = skus.get(0).getProperties().size();
         for (int i = 1; i < skus.size(); i++) {
             if (attrValueIdsSize != skus.get(i).getProperties().size()) {
-                throw exception(ErrorCodeConstants.SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
+                throw exception(SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
             }
         }
 
         // 4. 最后校验,每个 Sku 之间不是重复的
-        Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
+        // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
+        Set<Set<Long>> skuAttrValues = new HashSet<>();
         for (ProductSkuCreateOrUpdateReqVO sku : skus) {
-            if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuCreateOrUpdateReqVO.Property::getValueId))) { // 添加失败,说明重复
-                throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
+            // 添加失败,说明重复
+            if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuCreateOrUpdateReqVO.Property::getValueId))) {
+                throw exception(SPU_SKU_NOT_DUPLICATE);
             }
         }
     }
 
     @Override
-    public void createSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
-        productSkuMapper.insertBatch(ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuId, spuName));
+    public void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
+        productSkuMapper.insertBatch(ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuId));
     }
 
     @Override
@@ -152,7 +161,7 @@ public class ProductSkuServiceImpl implements ProductSkuService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void updateSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skus) {
+    public void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
         // 构建属性与 SKU 的映射关系;
         Map<String, Long> existsSkuMap = convertMap(productSkuMapper.selectListBySpuId(spuId),
                 ProductSkuConvert.INSTANCE::buildPropertyKey, ProductSkuDO::getId);
@@ -160,13 +169,14 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         // 拆分三个集合,新插入的、需要更新的、需要删除的
         List<ProductSkuDO> insertSkus = new ArrayList<>();
         List<ProductSkuDO> updateSkus = new ArrayList<>();
-        List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertList06(skus, null, spuName);
+        List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertList06(skus, null);
         allUpdateSkus.forEach(sku -> {
             String propertiesKey = ProductSkuConvert.INSTANCE.buildPropertyKey(sku);
             // 1、找得到的,进行更新
             Long existsSkuId = existsSkuMap.remove(propertiesKey);
             if (existsSkuId != null) {
                 sku.setId(existsSkuId);
+                // TODO 那spuId岂不是为null了
                 updateSkus.add(sku);
                 return;
             }

+ 38 - 25
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java

@@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
+import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
 import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
 import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
@@ -21,10 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
@@ -54,20 +52,21 @@ public class ProductSpuServiceImpl implements ProductSpuService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Long createSpu(ProductSpuCreateReqVO createReqVO) {
-        // 校验分类
-        validateCategory(createReqVO.getCategoryId());
-        // 校验品牌
-        brandService.validateProductBrand(createReqVO.getBrandId());
-        // 校验SKU
+        // 校验分类 TODO 暂不清楚为什么只能选择第三层的结点
+        //validateCategory(createReqVO.getCategoryId());
+        // 校验品牌 TODO 暂不校验
+        //brandService.validateProductBrand(createReqVO.getBrandId());
+
         List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = createReqVO.getSkus();
+        // 校验SKU
         productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());
-
-        // 插入 SPU
         ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
+        // 初始化SPU中SKU相关属性
         initSpuFromSkus(spu, skuSaveReqList);
+        // 插入 SPU
         productSpuMapper.insert(spu);
         // 插入 SKU
-        productSkuService.createSkuList(spu.getId(), spu.getName(), skuSaveReqList);
+        productSkuService.createSkuList(spu.getId(), skuSaveReqList);
         // 返回
         return spu.getId();
     }
@@ -90,7 +89,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         initSpuFromSkus(updateObj, skuSaveReqList);
         productSpuMapper.updateById(updateObj);
         // 批量更新 SKU
-        productSkuService.updateSkuList(updateObj.getId(), updateObj.getName(), updateReqVO.getSkus());
+        productSkuService.updateSkuList(updateObj.getId(), updateReqVO.getSkus());
     }
 
     /**
@@ -101,11 +100,25 @@ public class ProductSpuServiceImpl implements ProductSpuService {
      * @param skus 商品 SKU 数组
      */
     private void initSpuFromSkus(ProductSpuDO spu, List<ProductSkuCreateOrUpdateReqVO> skus) {
-        spu.setMarketPrice(getMaxValue(skus, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
-        // TODO ProductSpuDO中已没有相关属性
-        //spu.setMaxPrice(getMaxValue(skus, ProductSkuCreateOrUpdateReqVO::getPrice));
-        //spu.setMinPrice(getMinValue(skus, ProductSkuCreateOrUpdateReqVO::getPrice));
-        //spu.setTotalStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
+        // 断言,避免告警
+        assert skus.size() > 0;
+        // 获取sku单价最低的商品
+        ProductSkuCreateOrUpdateReqVO vo = skus.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateReqVO::getPrice)).get();
+        // sku单价最低的商品的价格
+        spu.setPrice(vo.getPrice());
+        // sku单价最低的商品的市场价格
+        spu.setMarketPrice(vo.getMarketPrice());
+        // sku单价最低的商品的成本价格
+        spu.setCostPrice(vo.getCostPrice());
+        // sku单价最低的商品的条形码
+        spu.setBarCode(vo.getBarCode());
+        // 默认状态为上架
+        spu.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
+        // TODO 默认商品销量和浏览量为零
+        spu.setSalesCount(0);
+        spu.setBrowseCount(0);
+        // skus库存总数
+        spu.setStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
     }
 
     /**
@@ -155,14 +168,14 @@ public class ProductSpuServiceImpl implements ProductSpuService {
 
     @Override
     public PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
-        // 库存告警的 SPU 编号的集合
+        // 库存告警的 SPU 编号的集合 TODO 一个接口一个接口来
         Set<Long> alarmStockSpuIds = null;
-        if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
-            alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId);
-            if (CollUtil.isEmpty(alarmStockSpuIds)) {
-                return PageResult.empty();
-            }
-        }
+        //if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
+        //    alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId);
+        //    if (CollUtil.isEmpty(alarmStockSpuIds)) {
+        //        return PageResult.empty();
+        //    }
+        //}
         // 分页查询
         return productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds);
     }

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java

@@ -75,7 +75,7 @@ public class ProductSkuServiceTest extends BaseDbUnitTest {
         );
 
         // 调用
-        productSkuService.updateSkuList(spuId, spuName, skus);
+        productSkuService.updateSkuList(spuId, skus);
         // 断言
         List<ProductSkuDO> dbSkus = productSkuMapper.selectListBySpuId(spuId);
         assertEquals(dbSkus.size(), 2);

+ 9 - 33
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java

@@ -9,10 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
@@ -37,6 +34,7 @@ import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
@@ -83,21 +81,9 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         // 准备参数
         ProductSpuCreateReqVO createReqVO = randomPojo(ProductSpuCreateReqVO.class, o -> {
             o.setSpecType(true);
-            o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
         });
-
-        // 校验SKU
-        List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
-
         Long spu = productSpuService.createSpu(createReqVO);
         ProductSpuDO productSpuDO = productSpuMapper.selectById(spu);
-
-        createReqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
-        // TODO ProductSpuCreateReqVO中已没有相关属性
-//        createReqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
-//        createReqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
-//        createReqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
-
         assertPojoEquals(createReqVO, productSpuDO);
 
     }
@@ -111,18 +97,9 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
             o.setId(createReqVO.getId()); // 设置更新的 ID
             o.setSpecType(true);
-            o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
         });
         // 调用
         productSpuService.updateSpu(reqVO);
-
-        List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = reqVO.getSkus();
-        reqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
-        // TODO ProductSpuUpdateReqVO中已没有相关属性
-//        reqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
-//        reqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
-//        reqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
-
         // 校验是否更新正确
         ProductSpuDO spu = productSpuMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, spu);
@@ -132,7 +109,6 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
     public void testValidateSpuExists_exception() {
         ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
             o.setSpecType(true);
-            o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
         });
         // 调用
         Assertions.assertThrows(ServiceException.class, () -> productSpuService.updateSpu(reqVO));
@@ -175,7 +151,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
     void getSpuPage_alarmStock_empty() {
         // 调用
         ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
-        productSpuPageReqVO.setAlarmStock(true);
+        //productSpuPageReqVO.setAlarmStock(true);
 
         PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
 
@@ -225,10 +201,10 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
 
         // 调用
         ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
-        productSpuPageReqVO.setAlarmStock(true);
+        //productSpuPageReqVO.setAlarmStock(true);
         PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
 
-        PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
+        PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
         Assertions.assertIterableEquals(result.getList(), spuPage.getList());
         assertEquals(spuPage.getTotal(), result.getTotal());
     }
@@ -273,14 +249,14 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
 
         // 调用
         ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
-        productSpuPageReqVO.setAlarmStock(false);
-        productSpuPageReqVO.setBrandId(brandId);
-        productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
+        //productSpuPageReqVO.setAlarmStock(false);
+        //productSpuPageReqVO.setBrandId(brandId);
+        //productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
         productSpuPageReqVO.setCategoryId(categoryId);
 
         PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
 
-        PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
+        PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
         assertEquals(result, spuPage);
     }