mall: code review 商品模块的代码
parent
833fd33844
commit
f4324a22f2
|
@ -10,30 +10,29 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
|||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 商品分类相关 1008001000 ============
|
||||
ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1008001000, "商品分类不存在");
|
||||
ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1008001001, "父分类不存在");
|
||||
ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类");
|
||||
ErrorCode PRODUCT_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除");
|
||||
ErrorCode PRODUCT_CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用");
|
||||
ErrorCode PRODUCT_CATEGORY_LEVEL = new ErrorCode(1008001005, "商品需挂在三级分类下");
|
||||
ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1008001000, "商品分类不存在");
|
||||
ErrorCode CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1008001001, "父分类不存在");
|
||||
ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类");
|
||||
ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除");
|
||||
ErrorCode CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用");
|
||||
ErrorCode CATEGORY_LEVEL_ERROR = new ErrorCode(1008001005, "商品分类不正确,原因:必须使用第三级的商品分类下");
|
||||
|
||||
// ========== 品牌相关编号 1008002000 ==========
|
||||
ErrorCode PRODUCT_BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");
|
||||
// ========== 商品品牌相关编号 1008002000 ==========
|
||||
ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");
|
||||
|
||||
// ========== 规格名称 1008003000 ==========
|
||||
// ========== 商品规格名称 1008003000 ==========
|
||||
ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1008003000, "规格名称不存在");
|
||||
|
||||
// ========== 规格值 1008004000 ==========
|
||||
ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1008004000, "规格值不存在");
|
||||
|
||||
// ========== 商品spu 1008005000 ==========
|
||||
ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品spu不存在");
|
||||
// ========== 商品 SPU 1008005000 ==========
|
||||
ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在");
|
||||
|
||||
// ========== 商品sku 1008006000 ==========
|
||||
ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品sku不存在");
|
||||
ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品sku的属性组合存在重复");
|
||||
// ========== 商品 SKU 1008006000 ==========
|
||||
ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品 SKU 不存在");
|
||||
ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复");
|
||||
ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其规格数必须一致");
|
||||
ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复");
|
||||
|
||||
ErrorCode PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 Spu 下的每个 SKU ,其规格数必须一致");
|
||||
|
||||
ErrorCode PRODUCT_SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU ,必须不重复");
|
||||
}
|
||||
|
|
|
@ -2,15 +2,9 @@ package cn.iocoder.yudao.module.product.controller.admin.brand;
|
|||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryRespVO;
|
||||
import cn.iocoder.yudao.module.product.convert.brand.ProductBrandConvert;
|
||||
import cn.iocoder.yudao.module.product.convert.category.ProductCategoryConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
|
||||
import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
|
@ -20,14 +14,11 @@ 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.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||
|
||||
@Api(tags = "管理后台 - 商品品牌")
|
||||
@RestController
|
||||
|
@ -88,5 +79,4 @@ public class ProductBrandController {
|
|||
return success(ProductBrandConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -35,14 +35,14 @@ public class ProductCategoryController {
|
|||
@ApiOperation("创建商品分类")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:create')")
|
||||
public CommonResult<Long> createProductCategory(@Valid @RequestBody ProductCategoryCreateReqVO createReqVO) {
|
||||
return success(categoryService.createProductCategory(createReqVO));
|
||||
return success(categoryService.createCategory(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@ApiOperation("更新商品分类")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:update')")
|
||||
public CommonResult<Boolean> updateProductCategory(@Valid @RequestBody ProductCategoryUpdateReqVO updateReqVO) {
|
||||
categoryService.updateProductCategory(updateReqVO);
|
||||
categoryService.updateCategory(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class ProductCategoryController {
|
|||
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('product:category:delete')")
|
||||
public CommonResult<Boolean> deleteProductCategory(@RequestParam("id") Long id) {
|
||||
categoryService.deleteProductCategory(id);
|
||||
categoryService.deleteCategory(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ public class ProductCategoryController {
|
|||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('product:category:query')")
|
||||
public CommonResult<ProductCategoryRespVO> getProductCategory(@RequestParam("id") Long id) {
|
||||
ProductCategoryDO category = categoryService.getProductCategory(id);
|
||||
ProductCategoryDO category = categoryService.getCategory(id);
|
||||
return success(ProductCategoryConvert.INSTANCE.convert(category));
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ public class ProductCategoryController {
|
|||
@ApiOperation("获得商品分类列表")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:query')")
|
||||
public CommonResult<List<ProductCategoryRespVO>> getProductCategoryList(@Valid ProductCategoryListReqVO treeListReqVO) {
|
||||
List<ProductCategoryDO> list = categoryService.getEnableProductCategoryList(treeListReqVO);
|
||||
List<ProductCategoryDO> list = categoryService.getEnableCategoryList(treeListReqVO);
|
||||
list.sort(Comparator.comparing(ProductCategoryDO::getSort));
|
||||
return success(ProductCategoryConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public class ProductPropertyController {
|
|||
@ApiOperation("获得规格名称")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<ProductPropertyRespVO> getProperty(@RequestParam("id") Long id) {
|
||||
public CommonResult<ProductPropertyAndValueRespVO> getProperty(@RequestParam("id") Long id) {
|
||||
return success(productPropertyService.getPropertyResp(id));
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ public class ProductPropertyController {
|
|||
@ApiOperation("获得规格名称列表")
|
||||
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<List<ProductPropertyRespVO>> getPropertyList(@RequestParam("ids") Collection<Long> ids) {
|
||||
public CommonResult<List<ProductPropertyAndValueRespVO>> getPropertyList(@RequestParam("ids") Collection<Long> ids) {
|
||||
List<ProductPropertyDO> list = productPropertyService.getPropertyList(ids);
|
||||
return success(ProductPropertyConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ public class ProductPropertyController {
|
|||
@GetMapping("/page")
|
||||
@ApiOperation("获得规格名称分页")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<PageResult<ProductPropertyRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
|
||||
public CommonResult<PageResult<ProductPropertyAndValueRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
|
||||
return success(productPropertyService.getPropertyListPage(pageVO));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@ApiModel("管理后台 - 规格 + 规格值 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyAndValueRespVO extends ProductPropertyBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "规格的编号", required = true, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "创建时间", required = true)
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 规格值的集合
|
||||
*/
|
||||
private List<ProductPropertyValueRespVO> values;
|
||||
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import io.swagger.annotations.*;
|
||||
import javax.validation.constraints.*;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
// TODO @芋艿:完整的 review 下规格
|
||||
/**
|
||||
* 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import io.swagger.annotations.*;
|
||||
|
||||
@ApiModel("管理后台 - 规格名称 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyRespVO extends ProductPropertyBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "主键", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty(value = "属性值")
|
||||
private List<ProductPropertyValueRespVO> propertyValueList;
|
||||
|
||||
}
|
|
@ -6,14 +6,13 @@ import lombok.Data;
|
|||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
@ApiModel("管理后台 - 商品 SKU 创建/更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO {
|
||||
|
||||
// TODO @Luowenfeng:可以不用哈,如果基于规格匹配
|
||||
@ApiModelProperty(value = "商品 id 更新时须有", example = "1")
|
||||
private Long id;
|
||||
|
||||
|
|
|
@ -36,14 +36,14 @@ public class ProductSpuController {
|
|||
@ApiOperation("创建商品 SPU")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:create')")
|
||||
public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) {
|
||||
return success(spuService.createProductSpu(createReqVO));
|
||||
return success(spuService.createSpu(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@ApiOperation("更新商品 SPU")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:update')")
|
||||
public CommonResult<Boolean> updateSpu(@Valid @RequestBody ProductSpuUpdateReqVO updateReqVO) {
|
||||
spuService.updateProductSpu(updateReqVO);
|
||||
spuService.updateSpu(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ public class SpuRespVO extends ProductSpuBaseVO {
|
|||
@ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]")
|
||||
private LinkedList<Long> categoryIds;
|
||||
|
||||
// TODO @芋艿:再琢磨下 这个 VO 类,其实变成 SpuRespVO 内嵌的 VO 类会更好一点;然后把 SpuRespVO 改成 SpuDetailSpuVO
|
||||
|
||||
@ApiModelProperty(value = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]")
|
||||
private List<ProductPropertyViewRespVO> productPropertyViews;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ public class AppCategoryController {
|
|||
@GetMapping("/list")
|
||||
@ApiOperation("获得商品分类列表")
|
||||
public CommonResult<List<AppCategoryRespVO>> getProductCategoryList() {
|
||||
List<ProductCategoryDO> list = categoryService.getEnableProductCategoryList();
|
||||
List<ProductCategoryDO> list = categoryService.getEnableCategoryList();
|
||||
list.sort(Comparator.comparing(ProductCategoryDO::getSort));
|
||||
return success(ProductCategoryConvert.INSTANCE.convertList03(list));
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ public interface ProductPropertyConvert {
|
|||
|
||||
ProductPropertyDO convert(ProductPropertyUpdateReqVO bean);
|
||||
|
||||
ProductPropertyRespVO convert(ProductPropertyDO bean);
|
||||
ProductPropertyAndValueRespVO convert(ProductPropertyDO bean);
|
||||
|
||||
List<ProductPropertyRespVO> convertList(List<ProductPropertyDO> list);
|
||||
List<ProductPropertyAndValueRespVO> convertList(List<ProductPropertyDO> list);
|
||||
|
||||
PageResult<ProductPropertyRespVO> convertPage(PageResult<ProductPropertyDO> page);
|
||||
PageResult<ProductPropertyAndValueRespVO> convertPage(PageResult<ProductPropertyDO> page);
|
||||
|
||||
List<ProductPropertyExcelVO> convertList02(List<ProductPropertyDO> list);
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.product.dal.mysql.brand;
|
|||
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.product.controller.admin.brand.vo.ProductBrandBaseVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandListReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandPageReqVO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
|
||||
|
@ -27,4 +26,5 @@ public interface ProductBrandMapper extends BaseMapperX<ProductBrandDO> {
|
|||
return selectList(new LambdaQueryWrapperX<ProductBrandDO>()
|
||||
.likeIfPresent(ProductBrandDO::getName, reqVO.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuPageReq
|
|||
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -34,13 +33,12 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
|
|||
|
||||
|
||||
// TODO @franky:方法名 selectList; 可以直接调用 selectList
|
||||
default List<ProductSkuDO> selectBySpuIds(List<Long> spuIds) {
|
||||
return selectList(new LambdaQueryWrapperX<ProductSkuDO>()
|
||||
.inIfPresent(ProductSkuDO::getSpuId, spuIds));
|
||||
default List<ProductSkuDO> selectListBySpuIds(List<Long> spuIds) {
|
||||
return selectList(ProductSkuDO::getSpuId, spuIds);
|
||||
}
|
||||
|
||||
default List<ProductSkuDO> selectBySpuId(Long spuIds) {
|
||||
return selectBySpuIds(Collections.singletonList(spuIds));
|
||||
default List<ProductSkuDO> selectListBySpuId(Long spuId) {
|
||||
return selectList(ProductSkuDO::getSpuId, spuId);
|
||||
}
|
||||
|
||||
default void deleteBySpuId(Long spuId) {
|
||||
|
|
|
@ -55,10 +55,11 @@ public interface ProductBrandService {
|
|||
|
||||
/**
|
||||
* 获得品牌列表
|
||||
* @param listVo 请求参数
|
||||
*
|
||||
* @param listReqVO 请求参数
|
||||
* @return 品牌列表
|
||||
*/
|
||||
List<ProductBrandDO> getBrandList(ProductBrandListReqVO listVo);
|
||||
List<ProductBrandDO> getBrandList(ProductBrandListReqVO listReqVO);
|
||||
|
||||
/**
|
||||
* 验证选择的商品分类是否合法
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package cn.iocoder.yudao.module.product.service.brand;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandCreateReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandListReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandPageReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.product.convert.brand.ProductBrandConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
|
||||
import cn.iocoder.yudao.module.product.dal.mysql.brand.ProductBrandMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
|
@ -14,8 +16,7 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_BRAND_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_CATEGORY_LEVEL;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.BRAND_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 品牌 Service 实现类
|
||||
|
@ -57,7 +58,7 @@ public class ProductBrandServiceImpl implements ProductBrandService {
|
|||
|
||||
private void validateBrandExists(Long id) {
|
||||
if (brandMapper.selectById(id) == null) {
|
||||
throw exception(PRODUCT_BRAND_NOT_EXISTS);
|
||||
throw exception(BRAND_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,14 +73,14 @@ public class ProductBrandServiceImpl implements ProductBrandService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<ProductBrandDO> getBrandList(ProductBrandListReqVO listVo) {
|
||||
return brandMapper.selectList(listVo);
|
||||
public List<ProductBrandDO> getBrandList(ProductBrandListReqVO listReqVO) {
|
||||
return brandMapper.selectList(listReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateProductBrand(Long id) {
|
||||
if(getBrand(id) == null){
|
||||
throw exception(PRODUCT_BRAND_NOT_EXISTS);
|
||||
throw exception(BRAND_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,21 +22,21 @@ public interface ProductCategoryService {
|
|||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createProductCategory(@Valid ProductCategoryCreateReqVO createReqVO);
|
||||
Long createCategory(@Valid ProductCategoryCreateReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新商品分类
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateProductCategory(@Valid ProductCategoryUpdateReqVO updateReqVO);
|
||||
void updateCategory(@Valid ProductCategoryUpdateReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除商品分类
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deleteProductCategory(Long id);
|
||||
void deleteCategory(Long id);
|
||||
|
||||
/**
|
||||
* 获得商品分类
|
||||
|
@ -44,7 +44,7 @@ public interface ProductCategoryService {
|
|||
* @param id 编号
|
||||
* @return 商品分类
|
||||
*/
|
||||
ProductCategoryDO getProductCategory(Long id);
|
||||
ProductCategoryDO getCategory(Long id);
|
||||
|
||||
/**
|
||||
* 获得商品分类列表
|
||||
|
@ -52,7 +52,7 @@ public interface ProductCategoryService {
|
|||
* @param ids 编号
|
||||
* @return 商品分类列表
|
||||
*/
|
||||
List<ProductCategoryDO> getEnableProductCategoryList(Collection<Long> ids);
|
||||
List<ProductCategoryDO> getEnableCategoryList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得商品分类列表
|
||||
|
@ -60,20 +60,21 @@ public interface ProductCategoryService {
|
|||
* @param listReqVO 查询条件
|
||||
* @return 商品分类列表
|
||||
*/
|
||||
List<ProductCategoryDO> getEnableProductCategoryList(ProductCategoryListReqVO listReqVO);
|
||||
List<ProductCategoryDO> getEnableCategoryList(ProductCategoryListReqVO listReqVO);
|
||||
|
||||
/**
|
||||
* 验证选择的商品分类是否合法
|
||||
* 验证选择的商品分类的级别是否合法
|
||||
* 例如说,商品发布的时候,必须在第 3 级别
|
||||
*
|
||||
* @param id 分类编号
|
||||
*/
|
||||
void validateProductCategory(Long id);
|
||||
void validateCategoryLevel(Long id);
|
||||
|
||||
/**
|
||||
* 获得开启状态的商品分类列表
|
||||
*
|
||||
* @return 商品分类列表
|
||||
*/
|
||||
List<ProductCategoryDO> getEnableProductCategoryList();
|
||||
List<ProductCategoryDO> getEnableCategoryList();
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
|||
private ProductCategoryMapper productCategoryMapper;
|
||||
|
||||
@Override
|
||||
public Long createProductCategory(ProductCategoryCreateReqVO createReqVO) {
|
||||
public Long createCategory(ProductCategoryCreateReqVO createReqVO) {
|
||||
// 校验父分类存在
|
||||
validateParentProductCategory(createReqVO.getParentId());
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateProductCategory(ProductCategoryUpdateReqVO updateReqVO) {
|
||||
public void updateCategory(ProductCategoryUpdateReqVO updateReqVO) {
|
||||
// 校验分类是否存在
|
||||
validateProductCategoryExists(updateReqVO.getId());
|
||||
// 校验父分类存在
|
||||
|
@ -56,12 +56,12 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void deleteProductCategory(Long id) {
|
||||
public void deleteCategory(Long id) {
|
||||
// 校验分类是否存在
|
||||
validateProductCategoryExists(id);
|
||||
// 校验是否还有子分类
|
||||
if (productCategoryMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(PRODUCT_CATEGORY_EXISTS_CHILDREN);
|
||||
throw exception(CATEGORY_EXISTS_CHILDREN);
|
||||
}
|
||||
|
||||
// 删除
|
||||
|
@ -76,61 +76,69 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
|||
// 父分类不存在
|
||||
ProductCategoryDO category = productCategoryMapper.selectById(id);
|
||||
if (category == null) {
|
||||
throw exception(PRODUCT_CATEGORY_PARENT_NOT_EXISTS);
|
||||
throw exception(CATEGORY_PARENT_NOT_EXISTS);
|
||||
}
|
||||
// 父分类不能是二级分类
|
||||
if (Objects.equals(id, ProductCategoryDO.PARENT_ID_NULL)) {
|
||||
throw exception(PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL);
|
||||
throw exception(CATEGORY_PARENT_NOT_FIRST_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateProductCategoryExists(Long id) {
|
||||
ProductCategoryDO category = productCategoryMapper.selectById(id);
|
||||
if (category == null) {
|
||||
throw exception(PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
throw exception(CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateProductCategory(Long id) {
|
||||
Integer level = categoryLevel(id, 1);
|
||||
public void validateCategoryLevel(Long id) {
|
||||
Integer level = getProductCategoryLevel(id, 1);
|
||||
if(level < 3){
|
||||
throw exception(PRODUCT_CATEGORY_LEVEL);
|
||||
throw exception(CATEGORY_LEVEL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// 校验分类级别
|
||||
private Integer categoryLevel(Long id, int level){
|
||||
// TODO @Luowenfeng:建议使用 for 循环,避免递归
|
||||
/**
|
||||
* 获得商品分类的级别
|
||||
*
|
||||
* @param id 商品分类的编号
|
||||
* @return 级别
|
||||
*/
|
||||
private Integer getProductCategoryLevel(Long id, int level){
|
||||
ProductCategoryDO category = productCategoryMapper.selectById(id);
|
||||
if (category == null) {
|
||||
throw exception(PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
throw exception(CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
// TODO Luowenfeng:去掉是否开启,它不影响级别哈
|
||||
if (ObjectUtil.notEqual(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
|
||||
throw exception(PRODUCT_CATEGORY_DISABLED);
|
||||
throw exception(CATEGORY_DISABLED);
|
||||
}
|
||||
if(category.getParentId() == 0) {
|
||||
// TODO Luowenfeng:不使用 0 直接比较哈,使用枚举
|
||||
if (category.getParentId() == 0) {
|
||||
return level;
|
||||
}
|
||||
return categoryLevel(category.getParentId(), ++level);
|
||||
return getProductCategoryLevel(category.getParentId(), ++level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProductCategoryDO getProductCategory(Long id) {
|
||||
public ProductCategoryDO getCategory(Long id) {
|
||||
return productCategoryMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductCategoryDO> getEnableProductCategoryList(Collection<Long> ids) {
|
||||
public List<ProductCategoryDO> getEnableCategoryList(Collection<Long> ids) {
|
||||
return productCategoryMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductCategoryDO> getEnableProductCategoryList(ProductCategoryListReqVO listReqVO) {
|
||||
public List<ProductCategoryDO> getEnableCategoryList(ProductCategoryListReqVO listReqVO) {
|
||||
return productCategoryMapper.selectList(listReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductCategoryDO> getEnableProductCategoryList() {
|
||||
public List<ProductCategoryDO> getEnableCategoryList() {
|
||||
return productCategoryMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package cn.iocoder.yudao.module.product.service.property;
|
||||
|
||||
import java.util.*;
|
||||
import javax.validation.*;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.*;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 规格名称 Service 接口
|
||||
|
@ -72,14 +74,16 @@ public interface ProductPropertyService {
|
|||
* @param pageReqVO
|
||||
* @return
|
||||
*/
|
||||
PageResult<ProductPropertyRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO);
|
||||
PageResult<ProductPropertyAndValueRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO);
|
||||
|
||||
ProductPropertyRespVO getPropertyResp(Long id);
|
||||
ProductPropertyAndValueRespVO getPropertyResp(Long id);
|
||||
|
||||
/**
|
||||
* 根据数据名id集合查询属性名以及属性值的集合
|
||||
* @param propertyIds 属性名id集合
|
||||
* @return
|
||||
* 根据规格属性编号的集合,获得对应的规格 + 规格值的集合
|
||||
*
|
||||
* @param ids 规格编号的集合
|
||||
* @return 对应的规格 + 规格值的集合
|
||||
*/
|
||||
List<ProductPropertyRespVO> selectByIds(List<Long> propertyIds);
|
||||
List<ProductPropertyAndValueRespVO> getPropertyAndValueList(Collection<Long> ids);
|
||||
|
||||
}
|
||||
|
|
|
@ -108,11 +108,11 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PageResult<ProductPropertyRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO) {
|
||||
public PageResult<ProductPropertyAndValueRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO) {
|
||||
//获取属性列表
|
||||
PageResult<ProductPropertyDO> pageResult = productPropertyMapper.selectPage(pageReqVO);
|
||||
PageResult<ProductPropertyRespVO> propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
|
||||
List<Long> propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyRespVO::getId).collect(Collectors.toList());
|
||||
PageResult<ProductPropertyAndValueRespVO> propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
|
||||
List<Long> propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyAndValueRespVO::getId).collect(Collectors.toList());
|
||||
|
||||
//获取属性值列表
|
||||
List<ProductPropertyValueDO> productPropertyValueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
|
||||
|
@ -121,7 +121,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
|
|||
propertyRespVOPageResult.getList().forEach(x->{
|
||||
Long propertyId = x.getId();
|
||||
List<ProductPropertyValueRespVO> valueDOList = propertyValueRespVOList.stream().filter(v -> v.getPropertyId().equals(propertyId)).collect(Collectors.toList());
|
||||
x.setPropertyValueList(valueDOList);
|
||||
x.setValues(valueDOList);
|
||||
});
|
||||
return propertyRespVOPageResult;
|
||||
}
|
||||
|
@ -131,25 +131,25 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ProductPropertyRespVO getPropertyResp(Long id) {
|
||||
public ProductPropertyAndValueRespVO getPropertyResp(Long id) {
|
||||
//查询规格
|
||||
ProductPropertyDO property = getProperty(id);
|
||||
ProductPropertyRespVO propertyRespVO = ProductPropertyConvert.INSTANCE.convert(property);
|
||||
ProductPropertyAndValueRespVO propertyRespVO = ProductPropertyConvert.INSTANCE.convert(property);
|
||||
//查询属性值
|
||||
List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(Arrays.asList(id));
|
||||
List<ProductPropertyValueRespVO> propertyValueRespVOS = ProductPropertyValueConvert.INSTANCE.convertList(valueDOList);
|
||||
//组装
|
||||
propertyRespVO.setPropertyValueList(propertyValueRespVOS);
|
||||
propertyRespVO.setValues(propertyValueRespVOS);
|
||||
return propertyRespVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductPropertyRespVO> selectByIds(List<Long> propertyIds) {
|
||||
List<ProductPropertyRespVO> productPropertyRespVO = ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(propertyIds));
|
||||
public List<ProductPropertyAndValueRespVO> getPropertyAndValueList(Collection<Long> ids) {
|
||||
List<ProductPropertyAndValueRespVO> productPropertyRespVO = ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids));
|
||||
//查询属性值
|
||||
List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
|
||||
List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.selectBatchIds(ids);
|
||||
Map<Long, List<ProductPropertyValueDO>> propertyValuesMap = valueDOList.stream().collect(Collectors.groupingBy(ProductPropertyValueDO::getPropertyId));
|
||||
productPropertyRespVO.forEach(p -> p.setPropertyValueList(ProductPropertyValueConvert.INSTANCE.convertList(propertyValuesMap.get(p.getId()))));
|
||||
productPropertyRespVO.forEach(p -> p.setValues(ProductPropertyValueConvert.INSTANCE.convertList(propertyValuesMap.get(p.getId()))));
|
||||
return productPropertyRespVO;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品sku Service 接口
|
||||
* 商品 SKU Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface ProductSkuService {
|
||||
|
||||
/**
|
||||
* 创建商品sku
|
||||
* 创建商品 SKU
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
|
@ -68,14 +68,15 @@ public interface ProductSkuService {
|
|||
*
|
||||
* @param list sku组合的集合
|
||||
*/
|
||||
void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType);
|
||||
void validateSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType);
|
||||
|
||||
/**
|
||||
* 批量创建 SKU
|
||||
*
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @param list SKU 对象集合
|
||||
*/
|
||||
void createProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId);
|
||||
void createSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list);
|
||||
|
||||
/**
|
||||
* 根据 SPU 编号,批量更新它的 SKU 信息
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package cn.iocoder.yudao.module.product.service.sku;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
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.module.product.controller.admin.property.vo.ProductPropertyRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyAndValueRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
|
||||
|
@ -24,11 +25,10 @@ import java.util.*;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 商品sku Service 实现类
|
||||
* 商品 SKU Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
@ -90,48 +90,51 @@ public class ProductSkuServiceImpl implements ProductSkuService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType) {
|
||||
// 多规格才需校验
|
||||
if (specType.equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
|
||||
List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> Optional.of(p.getProperties()).orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
|
||||
// 1、校验规格属性存在
|
||||
List<Long> propertyIds = CollectionUtils.convertList(skuPropertyList, ProductSkuBaseVO.Property::getPropertyId);
|
||||
List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(propertyIds);
|
||||
if (propertyAndValueList.size() == propertyIds.size()) {
|
||||
throw exception(PROPERTY_NOT_EXISTS);
|
||||
}
|
||||
// 2. 校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId
|
||||
List<ProductPropertyValueRespVO> collect = propertyAndValueList.stream()
|
||||
.flatMap(v -> Optional.of(v.getPropertyValueList())
|
||||
.orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
|
||||
Map<Long, ProductPropertyValueRespVO> propertyValueRespVOMap = CollectionUtils.convertMap(collect, ProductPropertyValueRespVO::getId);
|
||||
list.forEach(v -> {
|
||||
Set<Long> keys = v.getProperties().stream().map(k -> propertyValueRespVOMap.get(k.getValueId()).getPropertyId()).collect(Collectors.toSet());
|
||||
if (keys.size() != v.getProperties().size()) {
|
||||
throw exception(ErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
|
||||
}
|
||||
});
|
||||
public void validateSkus(List<ProductSkuCreateOrUpdateReqVO> skus, Integer specType) {
|
||||
// 非多规格,不需要校验
|
||||
if (ObjectUtil.notEqual(specType, ProductSpuSpecTypeEnum.DISABLE.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 再校验,每个 Sku 的规格值的数量,是一致的。
|
||||
int attrValueIdsSize = list.get(0).getProperties().size();
|
||||
for (int i = 1; i < list.size(); i++) {
|
||||
if (attrValueIdsSize != list.get(i).getProperties().size()) {
|
||||
throw exception(ErrorCodeConstants.PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
|
||||
}
|
||||
}
|
||||
// 1、校验规格属性存在
|
||||
// TODO @Luowenfeng:stream 的写法;不用改哈,就是说下可以酱紫写;
|
||||
Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null).flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性
|
||||
.map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toSet()); // 将每个 Property 转换成对应的 propertyId,最后形成集合
|
||||
List<ProductPropertyAndValueRespVO> propertyAndValueList = productPropertyService.getPropertyAndValueList(propertyIds);
|
||||
if (propertyAndValueList.size() == propertyIds.size()) {
|
||||
throw exception(PROPERTY_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 4. 最后校验,每个 Sku 之间不是重复的
|
||||
Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
|
||||
for (ProductSkuCreateOrUpdateReqVO sku : list) {
|
||||
if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复
|
||||
throw exception(ErrorCodeConstants.PRODUCT_SPU_SKU_NOT_DUPLICATE);
|
||||
}
|
||||
// 2. 校验,一个 SKU 下,没有重复的规格。校验方式是,遍历每个 SKU ,看看是否有重复的规格 propertyId
|
||||
Map<Long, ProductPropertyValueRespVO> propertyValueMap = propertyAndValueList.stream().filter(p -> p.getValues() != null).flatMap(p -> p.getValues().stream())
|
||||
.collect(Collectors.toMap(ProductPropertyValueRespVO::getId, value -> value)); // KEY:规格属性值的编号
|
||||
skus.forEach(sku -> {
|
||||
Set<Long> skuPropertyIds = CollectionUtils.convertSet(sku.getProperties(), propertyItem -> propertyValueMap.get(propertyItem.getValueId()).getPropertyId());
|
||||
if (skuPropertyIds.size() != sku.getProperties().size()) {
|
||||
throw exception(SKU_PROPERTIES_DUPLICATED);
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 再校验,每个 Sku 的规格值的数量,是一致的。
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 最后校验,每个 Sku 之间不是重复的
|
||||
Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
|
||||
for (ProductSkuCreateOrUpdateReqVO sku : skus) {
|
||||
// TODO @Luowenfeng:可以使用 CollectionUtils.convertSet(),简化下面的 stream 操作
|
||||
if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复
|
||||
throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createProductSkus(List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList, Long spuId) {
|
||||
public void createSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
|
||||
// 批量插入 SKU
|
||||
List<ProductSkuDO> skuDOList = ProductSkuConvert.INSTANCE.convertSkuDOList(skuCreateReqList);
|
||||
skuDOList.forEach(v -> v.setSpuId(spuId));
|
||||
|
@ -140,13 +143,12 @@ public class ProductSkuServiceImpl implements ProductSkuService {
|
|||
|
||||
@Override
|
||||
public List<ProductSkuDO> getSkusBySpuId(Long spuId) {
|
||||
List<ProductSkuDO> productSkuDOS = productSkuMapper.selectBySpuIds(Collections.singletonList(spuId));
|
||||
return productSkuDOS;
|
||||
return productSkuMapper.selectListBySpuIds(Collections.singletonList(spuId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProductSkuDO> getSkusBySpuIds(List<Long> spuIds) {
|
||||
return productSkuMapper.selectBySpuIds(spuIds);
|
||||
return productSkuMapper.selectListBySpuIds(spuIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,16 +159,16 @@ public class ProductSkuServiceImpl implements ProductSkuService {
|
|||
@Override
|
||||
@Transactional
|
||||
public void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
|
||||
// 查询 spu 下已经存在的 sku 的集合
|
||||
List<ProductSkuDO> existsSkus = productSkuMapper.selectBySpuId(spuId);
|
||||
// 查询 SPU 下已经存在的 SKU 的集合
|
||||
List<ProductSkuDO> existsSkus = productSkuMapper.selectListBySpuId(spuId);
|
||||
Map<Long, ProductSkuDO> existsSkuMap = CollectionUtils.convertMap(existsSkus, ProductSkuDO::getId);
|
||||
|
||||
// 拆分三个集合,新插入的、需要更新的、需要删除的
|
||||
List<ProductSkuDO> insertSkus = new ArrayList<>();
|
||||
List<ProductSkuDO> updateSkus = new ArrayList<>();
|
||||
List<ProductSkuDO> updateSkus = new ArrayList<>(); // TODO Luowenfeng:使用 Long 即可
|
||||
List<ProductSkuDO> deleteSkus = new ArrayList<>();
|
||||
|
||||
// TODO @芋艿:是不是基于规格匹配会比较好。
|
||||
// TODO @Luowenfeng:是不是基于规格匹配会比较好。可以参考下 onemall 的 ProductSpuServiceImpl 的 updateProductSpu 逻辑
|
||||
List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus);
|
||||
allUpdateSkus.forEach(p -> {
|
||||
if (p.getId() != null) {
|
||||
|
|
|
@ -26,14 +26,14 @@ public interface ProductSpuService {
|
|||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createProductSpu(@Valid ProductSpuCreateReqVO createReqVO);
|
||||
Long createSpu(@Valid ProductSpuCreateReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新商品 SPU
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateProductSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
|
||||
void updateSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除商品spu
|
||||
|
|
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.product.service.spu;
|
|||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyAndValueRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
|
||||
|
@ -16,7 +16,6 @@ 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;
|
||||
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.ProductSpuSpecTypeEnum;
|
||||
|
@ -30,7 +29,6 @@ import org.springframework.validation.annotation.Validated;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
@ -62,14 +60,14 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createProductSpu(ProductSpuCreateReqVO createReqVO) {
|
||||
public Long createSpu(ProductSpuCreateReqVO createReqVO) {
|
||||
// 校验分类
|
||||
categoryService.validateProductCategory(createReqVO.getCategoryId());
|
||||
categoryService.validateCategoryLevel(createReqVO.getCategoryId());
|
||||
// 校验品牌
|
||||
brandService.validateProductBrand(createReqVO.getBrandId());
|
||||
// 校验SKU
|
||||
List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
|
||||
productSkuService.validateProductSkus(skuCreateReqList, createReqVO.getSpecType());
|
||||
productSkuService.validateSkus(skuCreateReqList, createReqVO.getSpecType());
|
||||
// 插入 SPU
|
||||
ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
|
||||
spu.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
|
||||
|
@ -78,24 +76,25 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
|
||||
ProductSpuMapper.insert(spu);
|
||||
// 插入 SKU
|
||||
productSkuService.createProductSkus(skuCreateReqList, spu.getId());
|
||||
productSkuService.createSkus(spu.getId(), skuCreateReqList);
|
||||
// 返回
|
||||
return spu.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateProductSpu(ProductSpuUpdateReqVO updateReqVO) {
|
||||
public void updateSpu(ProductSpuUpdateReqVO updateReqVO) {
|
||||
// 校验 SPU 是否存在
|
||||
validateSpuExists(updateReqVO.getId());
|
||||
// 校验分类
|
||||
categoryService.validateProductCategory(updateReqVO.getCategoryId());
|
||||
categoryService.validateCategoryLevel(updateReqVO.getCategoryId());
|
||||
// 校验品牌
|
||||
brandService.validateProductBrand(updateReqVO.getBrandId());
|
||||
// 校验SKU
|
||||
List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
|
||||
// 多规格才需校验
|
||||
productSkuService.validateProductSkus(skuCreateReqList, updateReqVO.getSpecType());
|
||||
productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType());
|
||||
|
||||
// 更新 SPU
|
||||
ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);
|
||||
updateObj.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
|
||||
|
@ -103,7 +102,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
updateObj.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
|
||||
updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
|
||||
ProductSpuMapper.updateById(updateObj);
|
||||
// 更新 SKU
|
||||
// 批量更新 SKU
|
||||
productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus());
|
||||
}
|
||||
|
||||
|
@ -111,7 +110,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
@Transactional
|
||||
public void deleteSpu(Long id) {
|
||||
// 校验存在
|
||||
this.validateSpuExists(id);
|
||||
validateSpuExists(id);
|
||||
// 删除 SPU
|
||||
ProductSpuMapper.deleteById(id);
|
||||
// 删除关联的 SKU
|
||||
|
@ -125,6 +124,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
}
|
||||
|
||||
@Override
|
||||
// TODO @芋艿:需要再 review 下
|
||||
public SpuRespVO getSpu(Long id) {
|
||||
ProductSpuDO spu = ProductSpuMapper.selectById(id);
|
||||
SpuRespVO spuVO = ProductSpuConvert.INSTANCE.convert(spu);
|
||||
|
@ -138,7 +138,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
properties.addAll(productSkuRespVO.getProperties());
|
||||
}
|
||||
Map<Long, List<ProductSkuBaseVO.Property>> propertyMaps = properties.stream().collect(Collectors.groupingBy(ProductSkuBaseVO.Property::getPropertyId));
|
||||
List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(new ArrayList<>(propertyMaps.keySet()));
|
||||
List<ProductPropertyAndValueRespVO> propertyAndValueList = productPropertyService.getPropertyAndValueList(new ArrayList<>(propertyMaps.keySet()));
|
||||
// 装载组装过后的属性
|
||||
List<ProductPropertyViewRespVO> productPropertyViews = new ArrayList<>();
|
||||
propertyAndValueList.forEach(p -> {
|
||||
|
@ -146,7 +146,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
productPropertyViewRespVO.setPropertyId(p.getId());
|
||||
productPropertyViewRespVO.setName(p.getName());
|
||||
List<ProductPropertyViewRespVO.Tuple2> propertyValues = new ArrayList<>();
|
||||
Map<Long, ProductPropertyValueRespVO> propertyValueMaps = p.getPropertyValueList().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv));
|
||||
Map<Long, ProductPropertyValueRespVO> propertyValueMaps = p.getValues().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv));
|
||||
propertyMaps.get(p.getId()).forEach(pv -> {
|
||||
ProductPropertyViewRespVO.Tuple2 tuple2 = new ProductPropertyViewRespVO.Tuple2(pv.getValueId(), propertyValueMaps.get(pv.getValueId()).getName());
|
||||
propertyValues.add(tuple2);
|
||||
|
@ -162,7 +162,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
Long parentId = spuVO.getCategoryId();
|
||||
categoryArray.addFirst(parentId);
|
||||
while (parentId != 0) {
|
||||
parentId = categoryService.getProductCategory(parentId).getParentId();
|
||||
parentId = categoryService.getCategory(parentId).getParentId();
|
||||
if (parentId > 0) {
|
||||
categoryArray.addFirst(parentId);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEq
|
|||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_BRAND_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.BRAND_NOT_EXISTS;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
|
@ -74,7 +74,7 @@ public class ProductBrandServiceImplTest extends BaseDbUnitTest {
|
|||
ProductBrandUpdateReqVO reqVO = randomPojo(ProductBrandUpdateReqVO.class);
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> brandService.updateBrand(reqVO), PRODUCT_BRAND_NOT_EXISTS);
|
||||
assertServiceException(() -> brandService.updateBrand(reqVO), BRAND_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -97,7 +97,7 @@ public class ProductBrandServiceImplTest extends BaseDbUnitTest {
|
|||
Long id = randomLongId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> brandService.deleteBrand(id), PRODUCT_BRAND_NOT_EXISTS);
|
||||
assertServiceException(() -> brandService.deleteBrand(id), BRAND_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -17,7 +17,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEq
|
|||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.CATEGORY_NOT_EXISTS;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
|
@ -43,7 +43,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
|
|||
productCategoryMapper.insert(parentProductCategory);
|
||||
|
||||
// 调用
|
||||
Long categoryId = productCategoryService.createProductCategory(reqVO);
|
||||
Long categoryId = productCategoryService.createCategory(reqVO);
|
||||
// 断言
|
||||
assertNotNull(categoryId);
|
||||
// 校验记录的属性是否正确
|
||||
|
@ -65,7 +65,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
|
|||
productCategoryMapper.insert(parentProductCategory);
|
||||
|
||||
// 调用
|
||||
productCategoryService.updateProductCategory(reqVO);
|
||||
productCategoryService.updateCategory(reqVO);
|
||||
// 校验是否更新正确
|
||||
ProductCategoryDO category = productCategoryMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, category);
|
||||
|
@ -77,7 +77,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
|
|||
ProductCategoryUpdateReqVO reqVO = randomPojo(ProductCategoryUpdateReqVO.class);
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> productCategoryService.updateProductCategory(reqVO), PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
assertServiceException(() -> productCategoryService.updateCategory(reqVO), CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -89,7 +89,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
|
|||
Long id = dbCategory.getId();
|
||||
|
||||
// 调用
|
||||
productCategoryService.deleteProductCategory(id);
|
||||
productCategoryService.deleteCategory(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(productCategoryMapper.selectById(id));
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
|
|||
Long id = randomLongId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> productCategoryService.deleteProductCategory(id), PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
assertServiceException(() -> productCategoryService.deleteCategory(id), CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -117,7 +117,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
|
|||
reqVO.setName("特曼");
|
||||
|
||||
// 调用
|
||||
List<ProductCategoryDO> list = productCategoryService.getEnableProductCategoryList(reqVO);
|
||||
List<ProductCategoryDO> list = productCategoryService.getEnableCategoryList(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(dbCategory, list.get(0));
|
||||
|
|
|
@ -41,7 +41,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
ProductSpuCreateReqVO reqVO = randomPojo(ProductSpuCreateReqVO.class);
|
||||
|
||||
// 调用
|
||||
Long spuId = spuService.createProductSpu(reqVO);
|
||||
Long spuId = spuService.createSpu(reqVO);
|
||||
// 断言
|
||||
assertNotNull(spuId);
|
||||
// 校验记录的属性是否正确
|
||||
|
@ -60,7 +60,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
});
|
||||
|
||||
// 调用
|
||||
spuService.updateProductSpu(reqVO);
|
||||
spuService.updateSpu(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.updateProductSpu(reqVO), SPU_NOT_EXISTS);
|
||||
assertServiceException(() -> spuService.updateSpu(reqVO), SPU_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue