From c2fd24f597003ea04ff8e726c85c169735f8e0c3 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Tue, 23 Aug 2022 23:58:22 +0800
Subject: [PATCH] =?UTF-8?q?mall=EF=BC=9Acode=20review=20=E5=95=86=E5=93=81?=
 =?UTF-8?q?=20spu=20=E7=9A=84=E5=90=8E=E7=AB=AF=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../admin/sku/vo/ProductSkuBaseVO.java        |  4 +-
 .../admin/spu/ProductSpuController.java       |  6 +--
 .../dal/mysql/sku/ProductSkuMapper.java       |  1 +
 .../service/sku/ProductSkuService.java        | 23 +++++-----
 .../service/sku/ProductSkuServiceImpl.java    | 33 ++++++++-------
 .../service/spu/ProductSpuService.java        |  8 ++--
 .../service/spu/ProductSpuServiceImpl.java    | 42 +++++++++++++------
 .../spu/ProductSpuServiceImplTest.java        |  6 +--
 8 files changed, 74 insertions(+), 49 deletions(-)

diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
index 07fddc9ac..c6d8b5459 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
@@ -21,7 +21,9 @@ public class ProductSkuBaseVO {
     @NotEmpty(message = "商品 SKU 名字不能为空")
     private String name;
 
-    @ApiModelProperty(value = "规格值数组-json格式 单规格中无此列表, [{propertyId: , valueId: }, {propertyId: , valueId: }]")
+    /**
+     * 规格值数组
+     */
     private List<Property> properties;
 
     @ApiModelProperty(value = "销售价格,单位:分", required = true, example = "1024", notes = "单位:分")
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
index 7aa73068f..565a20c7b 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
@@ -35,15 +35,15 @@ public class ProductSpuController {
     @PostMapping("/create")
     @ApiOperation("创建商品 SPU")
     @PreAuthorize("@ss.hasPermission('product:spu:create')")
-    public CommonResult<Long> createSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) {
-        return success(spuService.createSpu(createReqVO));
+    public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) {
+        return success(spuService.createProductSpu(createReqVO));
     }
 
     @PutMapping("/update")
     @ApiOperation("更新商品 SPU")
     @PreAuthorize("@ss.hasPermission('product:spu:update')")
     public CommonResult<Boolean> updateSpu(@Valid @RequestBody ProductSpuUpdateReqVO updateReqVO) {
-        spuService.updateSpu(updateReqVO);
+        spuService.updateProductSpu(updateReqVO);
         return success(true);
     }
 
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
index eff999be0..134631650 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
@@ -44,4 +44,5 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
                 .eqIfPresent(ProductSkuDO::getSpuId, spuId);
         delete(lambdaQueryWrapperX);
     }
+
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
index 4b299030b..20c7680bf 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
@@ -68,14 +68,22 @@ public interface ProductSkuService {
      *
      * @param list sku组合的集合
      */
-    void validateSkus(List<ProductSkuCreateOrUpdateReqVO> list);
+    void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list);
 
     /**
-     * 批量保存 sku
+     * 批量创建 SKU
      *
-     * @param list sku对象集合
+     * @param list SKU 对象集合
      */
-    void createSkus(List<ProductSkuDO> list);
+    void createProductSkus(List<ProductSkuDO> list);
+
+    /**
+     * 根据 SPU 编号,批量更新它的 SKU 信息
+     *
+     * @param spuId SPU 编码
+     * @param skus SKU 的集合
+     */
+    void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
 
     /**
      * 获得商品 sku 集合
@@ -100,11 +108,4 @@ public interface ProductSkuService {
      */
     void deleteSkuBySpuId(Long spuId);
 
-    /**
-     * 根据 spuId 更新 spu 下的 sku 信息
-     *
-     * @param spuId spu 编码
-     * @param skus sku 的集合
-     */
-    void updateSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
index ea9e97c81..50408bcb3 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
@@ -1,6 +1,5 @@
 package cn.iocoder.yudao.module.product.service.sku;
 
-import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
@@ -87,25 +86,30 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         return productSkuMapper.selectPage(pageReqVO);
     }
 
+    // TODO luowenfeng:参考下 yudao-cloud 的 checkProductAttr 方法,重构下
     @Override
-    public void validateSkus(List<ProductSkuCreateOrUpdateReqVO> list) {
+    public void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list) {
         List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> Optional.of(p.getProperties()).orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
-        // 校验规格属性以及规格值是否存在
+        // 校验规格属性存在
+        // TODO @luowenfeng:使用 CollectionUtils.convert
         List<Long> propertyIds = skuPropertyList.stream().map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toList());
         List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(propertyIds);
+        // TODO @luowenfeng:校验数量一致;
         if (propertyAndValueList.isEmpty()) {
-            throw ServiceExceptionUtil.exception(PROPERTY_NOT_EXISTS);
+            throw exception(PROPERTY_NOT_EXISTS);
         }
+        // 校验规格属性值存在
+        // TODO @luowenfeng:使用 CollectionUtils.convert
         Map<Long, ProductPropertyRespVO> propertyMap = propertyAndValueList.stream().collect(Collectors.toMap(ProductPropertyRespVO::getId, p -> p));
         skuPropertyList.forEach(p -> {
             ProductPropertyRespVO productPropertyRespVO = propertyMap.get(p.getPropertyId());
             // 如果对应的属性名不存在或属性名下的属性值集合为空,给出提示
             if (null == productPropertyRespVO || productPropertyRespVO.getPropertyValueList().isEmpty()) {
-                throw ServiceExceptionUtil.exception(PROPERTY_NOT_EXISTS);
+                throw exception(PROPERTY_NOT_EXISTS);
             }
             // 判断改属性名对应的属性值是否存在,不存在,给出提示
             if (!productPropertyRespVO.getPropertyValueList().stream().map(ProductPropertyValueRespVO::getId).collect(Collectors.toSet()).contains(p.getValueId())) {
-                throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS);
+                throw exception(ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS);
             }
         });
         // 校验是否有重复的sku组合
@@ -114,13 +118,13 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         skuProperties.forEach(p -> {
             // 组合属性值id为 1~2~3.... 形式的字符串,通过set的特性判断是否有重复的组合
             if (!skuPropertiesConvertSet.add(p.stream().map(pr -> String.valueOf(pr.getValueId())).sorted().collect(Collectors.joining("~")))) {
-                throw ServiceExceptionUtil.exception(ErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
+                throw exception(ErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
             }
         });
     }
 
     @Override
-    public void createSkus(List<ProductSkuDO> skuDOList) {
+    public void createProductSkus(List<ProductSkuDO> skuDOList) {
         productSkuMapper.insertBatch(skuDOList);
     }
 
@@ -141,21 +145,23 @@ public class ProductSkuServiceImpl implements ProductSkuService {
 
     @Override
     @Transactional
-    public void updateSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
-        List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus);
+    public void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
         // 查询 spu 下已经存在的 sku 的集合
+        // TODO @luowenfeng:selectListBySpuId 搞个
         List<ProductSkuDO> existsSkus = productSkuMapper.selectBySpuIds(Collections.singletonList(spuId));
         // TODO @franky:使用 CollUtils 即可
         Map<Long, ProductSkuDO> existsSkuMap = existsSkus.stream().collect(Collectors.toMap(ProductSkuDO::getId, p -> p));
 
-        // 拆分三个集合, 新插入的, 需要更新的,需要删除的
+        // 拆分三个集合,新插入的、需要更新的、需要删除的
         List<ProductSkuDO> insertSkus = new ArrayList<>();
         List<ProductSkuDO> updateSkus = new ArrayList<>();
         List<ProductSkuDO> deleteSkus = new ArrayList<>();
 
         // TODO @芋艿:是不是基于规格匹配会比较好。
+        List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus);
         allUpdateSkus.forEach(p -> {
-            if (null != p.getId()) {
+            if (p.getId() != null) {
+                // TODO @luowenfeng:contains
                 if (existsSkuMap.get(p.getId()) != null) {
                     updateSkus.add(p);
                     return;
@@ -167,14 +173,13 @@ public class ProductSkuServiceImpl implements ProductSkuService {
             insertSkus.add(p);
         });
 
+        // TODO @luowenfeng:使用 CollUtil.isNotEmpty 判断
         if (insertSkus.size() > 0) {
             productSkuMapper.insertBatch(insertSkus);
         }
-
         if (updateSkus.size() > 0) {
             updateSkus.forEach(p -> productSkuMapper.updateById(p));
         }
-
         if (deleteSkus.size() > 0) {
             productSkuMapper.deleteBatchIds(deleteSkus.stream().map(ProductSkuDO::getId).collect(Collectors.toList()));
         }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
index b3ba4b99f..37883b677 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
@@ -21,19 +21,19 @@ import java.util.List;
 public interface ProductSpuService {
 
     /**
-     * 创建商品spu
+     * 创建商品 SPU
      *
      * @param createReqVO 创建信息
      * @return 编号
      */
-    Long createSpu(@Valid ProductSpuCreateReqVO createReqVO);
+    Long createProductSpu(@Valid ProductSpuCreateReqVO createReqVO);
 
     /**
-     * 更新商品spu
+     * 更新商品 SPU
      *
      * @param updateReqVO 更新信息
      */
-    void updateSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
+    void updateProductSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
 
     /**
      * 删除商品spu
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
index 988f8e1df..26c564f34 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
@@ -7,7 +7,10 @@ import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.Product
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuRespVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
@@ -53,47 +56,60 @@ public class ProductSpuServiceImpl implements ProductSpuService {
 
     @Override
     @Transactional
-    public Long createSpu(ProductSpuCreateReqVO createReqVO) {
+    public Long createProductSpu(ProductSpuCreateReqVO createReqVO) {
         // 校验分类
+        // TODO @luowenfeng:可以在这个类里加个方法,校验分类;商品必须挂在三级分类下;
         categoryService.validateProductCategory(createReqVO.getCategoryId());
+        // TODO @luowenfeng:校验品牌
         // 校验SKU
         List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
         // 多规格才需校验
+        // TODO @luowenfeng:可以把 type 传递到 productSkuService 里,通过它统一判断处理
         if(Objects.equals(createReqVO.getSpecType(), ProductSpuSpecTypeEnum.DISABLE.getType())) {
-            productSkuService.validateSkus(skuCreateReqList);
+            productSkuService.validateProductSkus(skuCreateReqList);
         }
-        // 插入SPU
+
+        // 插入 SPU
         ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
+        // TODO @luowenfeng:可以在 CollectionUtils 增加 getMaxValue 方法,增加一个 defaultValue 方法,如果为空,则返回 defaultValue
         spu.setMarketPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getMarketPrice).max(Integer::compare).orElse(0));
         spu.setMaxPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getPrice).max(Integer::compare).orElse(0));
         spu.setMinPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getPrice).min(Integer::compare).orElse(0));
+        // TODO @luowenfeng:库存求和
         ProductSpuMapper.insert(spu);
+
+        // 批量插入 SKU
+        // TODO @luowenfeng:convert 逻辑,交给 createProductSkus 一起处理
         List<ProductSkuDO> skuDOList = ProductSkuConvert.INSTANCE.convertSkuDOList(skuCreateReqList);
         skuDOList.forEach(v->v.setSpuId(spu.getId()));
-        // 批量插入sku
-        productSkuService.createSkus(skuDOList);
+        productSkuService.createProductSkus(skuDOList);
         // 返回
         return spu.getId();
     }
 
     @Override
     @Transactional
-    public void updateSpu(ProductSpuUpdateReqVO updateReqVO) {
-        // 校验 spu 是否存在
-        this.validateSpuExists(updateReqVO.getId());
+    public void updateProductSpu(ProductSpuUpdateReqVO updateReqVO) {
+        // 校验 SPU 是否存在
+        validateSpuExists(updateReqVO.getId());
         // 校验分类
         categoryService.validateProductCategory(updateReqVO.getCategoryId());
+        // TODO @luowenfeng:校验品牌
         // 校验SKU
         List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
         // 多规格才需校验
+        // TODO @luowenfeng:可以把 type 传递到 productSkuService 里,通过它统一判断处理
         if(updateReqVO.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
-            productSkuService.validateSkus(skuCreateReqList);
+            productSkuService.validateProductSkus(skuCreateReqList);
         }
-        // 更新
+
+        // 更新 SPU
         ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);
+        // TODO @计算各种字段
         ProductSpuMapper.updateById(updateObj);
-        // 更新 sku
-        productSkuService.updateSkus(updateObj.getId(), updateReqVO.getSkus());
+
+        // 更新 SKU
+        productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus());
     }
 
     @Override
diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
index 57b7fdfeb..e2b3a3d98 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
@@ -41,7 +41,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         ProductSpuCreateReqVO reqVO = randomPojo(ProductSpuCreateReqVO.class);
 
         // 调用
-        Long spuId = spuService.createSpu(reqVO);
+        Long spuId = spuService.createProductSpu(reqVO);
         // 断言
         assertNotNull(spuId);
         // 校验记录的属性是否正确
@@ -60,7 +60,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         });
 
         // 调用
-        spuService.updateSpu(reqVO);
+        spuService.updateProductSpu(reqVO);
         // 校验是否更新正确
         ProductSpuDO spu = ProductSpuMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, spu);
@@ -72,7 +72,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class);
 
         // 调用, 并断言异常
-        assertServiceException(() -> spuService.updateSpu(reqVO), SPU_NOT_EXISTS);
+        assertServiceException(() -> spuService.updateProductSpu(reqVO), SPU_NOT_EXISTS);
     }
 
     @Test