进行商品修改的迁移
This commit is contained in:
@@ -3,9 +3,9 @@ package cn.iocoder.mall.productservice.rpc.spu;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,7 +27,7 @@ public interface ProductSpuRpc {
|
||||
*
|
||||
* @param updateDTO 更新商品 SPU DTO
|
||||
*/
|
||||
CommonResult<Boolean> updateProductSpu(ProductSpuUpdateReqDTO updateDTO);
|
||||
CommonResult<Boolean> updateProductSpu(ProductSpuAndSkuUpdateReqDTO updateDTO);
|
||||
|
||||
/**
|
||||
* 获得商品 SPU
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package cn.iocoder.mall.productservice.rpc.spu.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品 SPU 和 SKU 更新 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ProductSpuAndSkuUpdateReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* SKU 信息
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class Sku implements Serializable {
|
||||
|
||||
/**
|
||||
* 规格值数组
|
||||
*/
|
||||
@NotNull(message = "规格值数组不能为空")
|
||||
private List<Integer> attrValueIds;
|
||||
/**
|
||||
* 价格,单位:分
|
||||
*/
|
||||
@NotNull(message = "价格不能为空")
|
||||
@Min(value = 1L, message = "最小价格为 1")
|
||||
private Integer price;
|
||||
/**
|
||||
* 库存数量
|
||||
*/
|
||||
@NotNull(message = "库存数量不能为空")
|
||||
@Min(value = 1L, message = "最小库存为 1")
|
||||
private Integer quantity;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Spu 编号
|
||||
*/
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Integer id;
|
||||
|
||||
// ========== 基本信息 =========
|
||||
/**
|
||||
* SPU 名字
|
||||
*/
|
||||
@NotEmpty(message = "SPU 名字不能为空")
|
||||
private String name;
|
||||
/**
|
||||
* 卖点
|
||||
*/
|
||||
@NotEmpty(message = "卖点不能为空")
|
||||
private String sellPoint;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@NotEmpty(message = "描述不能为空")
|
||||
private String description;
|
||||
/**
|
||||
* 分类编号
|
||||
*/
|
||||
@NotNull(message = "分类编号不能为空")
|
||||
private Integer cid;
|
||||
/**
|
||||
* 商品主图地址
|
||||
*/
|
||||
@NotEmpty(message = "商品主图地址不能为空")
|
||||
private List<String> picUrls;
|
||||
|
||||
// ========== 其他信息 =========
|
||||
/**
|
||||
* 是否上架商品
|
||||
*/
|
||||
@NotNull(message = "是否上架商品不能为空")
|
||||
private Boolean visible;
|
||||
|
||||
// ========== SKU =========
|
||||
|
||||
/**
|
||||
* SKU 数组
|
||||
*/
|
||||
@NotNull(message = "SKU 不能为空")
|
||||
@Valid
|
||||
private List<Sku> skus;
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package cn.iocoder.mall.productservice.rpc.spu.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品 SPU 更新 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ProductSpuUpdateReqDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
@NotNull(message = "商品 SPU 编号不能为空")
|
||||
private Integer id;
|
||||
/**
|
||||
* SPU 名字
|
||||
*/
|
||||
@NotEmpty(message = "SPU 名字不能为空")
|
||||
private String name;
|
||||
/**
|
||||
* 卖点
|
||||
*/
|
||||
@NotEmpty(message = "卖点不能为空")
|
||||
private String sellPoint;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@NotEmpty(message = "描述不能为空")
|
||||
private String description;
|
||||
/**
|
||||
* 分类编号
|
||||
*/
|
||||
@NotNull(message = "分类编号不能为空")
|
||||
private Integer cid;
|
||||
/**
|
||||
* 商品主图地址
|
||||
*/
|
||||
@NotEmpty(message = "商品主图地址不能为空")
|
||||
private List<String> picUrls;
|
||||
/**
|
||||
* 是否上架商品
|
||||
*/
|
||||
@NotNull(message = "是否上架商品不能为空")
|
||||
private Boolean visible;
|
||||
/**
|
||||
* 排序字段
|
||||
*/
|
||||
@NotNull(message = "排序字段不能为空")
|
||||
private Integer sort;
|
||||
/**
|
||||
* 价格
|
||||
*/
|
||||
@NotNull(message = "价格不能为空")
|
||||
private Integer price;
|
||||
/**
|
||||
* 库存数量
|
||||
*/
|
||||
@NotNull(message = "库存数量不能为空")
|
||||
private Integer quantity;
|
||||
|
||||
}
|
||||
@@ -18,7 +18,7 @@ public interface ProductSkuConvert {
|
||||
List<ProductSkuDO> convertList(List<ProductSkuCreateOrUpdateBO> list);
|
||||
|
||||
@Mapping(source = "attrValueIds", target = "attrs", qualifiedByName = "translatePicUrlsFromStringList")
|
||||
ProductSkuDO convertList(ProductSkuCreateOrUpdateBO bean);
|
||||
ProductSkuDO convert(ProductSkuCreateOrUpdateBO skuUpdateDTO);
|
||||
|
||||
@Named("translateAttrValueIdsFromString")
|
||||
default List<String> translateAttrValueIdsFromString(String attrValueIdsStar) {
|
||||
|
||||
@@ -3,11 +3,11 @@ package cn.iocoder.mall.productservice.convert.spu;
|
||||
import cn.iocoder.common.framework.util.StringUtils;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.productservice.dal.mysql.dataobject.spu.ProductSpuDO;
|
||||
import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO;
|
||||
import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO;
|
||||
import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuBO;
|
||||
import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuCreateBO;
|
||||
import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuPageBO;
|
||||
@@ -41,7 +41,7 @@ public interface ProductSpuConvert {
|
||||
|
||||
ProductSpuCreateBO convert(ProductSpuAndSkuCreateReqDTO bean);
|
||||
|
||||
ProductSpuUpdateBO convert(ProductSpuUpdateReqDTO bean);
|
||||
ProductSpuUpdateBO convert(ProductSpuAndSkuUpdateReqDTO bean);
|
||||
|
||||
ProductSpuRespDTO convert(ProductSpuBO bean);
|
||||
|
||||
@@ -51,6 +51,9 @@ public interface ProductSpuConvert {
|
||||
|
||||
PageResult<ProductSpuRespDTO> convertPage(PageResult<ProductSpuBO> page);
|
||||
|
||||
List<ProductSkuCreateOrUpdateBO> convert(List<ProductSpuAndSkuCreateReqDTO.Sku> list);
|
||||
List<ProductSkuCreateOrUpdateBO> convert02(List<ProductSpuAndSkuUpdateReqDTO.Sku> list);
|
||||
|
||||
@Named("translatePicUrlsFromString")
|
||||
default List<String> translatePicUrlsFromList(String picUrls) {
|
||||
return StringUtils.split(picUrls, ",");
|
||||
@@ -61,6 +64,5 @@ public interface ProductSpuConvert {
|
||||
return StringUtils.join(picUrls, ",");
|
||||
}
|
||||
|
||||
List<ProductSkuCreateOrUpdateBO> convert(List<ProductSpuAndSkuCreateReqDTO.Sku> list);
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.productservice.convert.spu.ProductSpuConvert;
|
||||
import cn.iocoder.mall.productservice.enums.category.ProductCategoryIdEnum;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO;
|
||||
import cn.iocoder.mall.productservice.service.attr.ProductAttrService;
|
||||
import cn.iocoder.mall.productservice.service.attr.bo.ProductAttrKeyValueBO;
|
||||
import cn.iocoder.mall.productservice.service.category.ProductCategoryService;
|
||||
@@ -17,17 +17,15 @@ import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO;
|
||||
import cn.iocoder.mall.productservice.service.spu.ProductSpuService;
|
||||
import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuBO;
|
||||
import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuCreateBO;
|
||||
import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuUpdateBO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS;
|
||||
import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2;
|
||||
import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 商品 SPU Manager
|
||||
@@ -52,30 +50,18 @@ public class ProductSpuManager {
|
||||
*/
|
||||
@Transactional
|
||||
public Integer createProductSpu(ProductSpuAndSkuCreateReqDTO createDTO) {
|
||||
// 校验商品分类分类存在
|
||||
ProductCategoryBO categoryBO = productCategoryService.getProductCategory(createDTO.getCid());
|
||||
if (categoryBO == null) {
|
||||
// 不存在
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
if (ProductCategoryIdEnum.ROOT.getId().equals(categoryBO.getPid())) {
|
||||
// 商品只能添加到二级分类下
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2);
|
||||
}
|
||||
// 校验规格是否存在
|
||||
Set<Integer> attrValueIds = new HashSet<>();
|
||||
createDTO.getSkus().forEach(productSkuAddDTO -> attrValueIds.addAll(productSkuAddDTO.getAttrValueIds()));
|
||||
List<ProductAttrKeyValueBO> attrKeyValueBOs = productAttrService.validProductAttr(attrValueIds, true);
|
||||
// 校验商品分类是否合法
|
||||
this.checkProductCategory(createDTO.getCid());
|
||||
// 创建商品 SKU 对象,并进行校验
|
||||
List<ProductSkuCreateOrUpdateBO> skus = ProductSpuConvert.INSTANCE.convert(createDTO.getSkus());
|
||||
productSkuService.validProductSku(skus, attrKeyValueBOs);
|
||||
List<ProductSkuCreateOrUpdateBO> skuBOs = ProductSpuConvert.INSTANCE.convert(createDTO.getSkus());
|
||||
this.checkProductAttr(skuBOs);
|
||||
// 插入商品 SPU 记录
|
||||
ProductSpuCreateBO spuCreateBO = ProductSpuConvert.INSTANCE.convert(createDTO).setSort(0);
|
||||
spuCreateBO.setPrice(skus.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateBO::getPrice)).get().getPrice()); // 求最小价格
|
||||
spuCreateBO.setQuantity(skus.stream().mapToInt(ProductSkuCreateOrUpdateBO::getQuantity).sum()); // 求库存之和
|
||||
spuCreateBO.setPrice(skuBOs.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateBO::getPrice)).get().getPrice()); // 求最小价格
|
||||
spuCreateBO.setQuantity(skuBOs.stream().mapToInt(ProductSkuCreateOrUpdateBO::getQuantity).sum()); // 求库存之和
|
||||
ProductSpuBO spuBO = productSpuService.createProductSpu(spuCreateBO);
|
||||
// 从插入商品 SKU 记录
|
||||
productSkuService.createProductSkus(spuBO.getId(), skus);
|
||||
// 插入商品 SKU 记录
|
||||
productSkuService.createProductSkus(spuBO.getId(), skuBOs);
|
||||
return spuBO.getId();
|
||||
}
|
||||
|
||||
@@ -84,8 +70,19 @@ public class ProductSpuManager {
|
||||
*
|
||||
* @param updateDTO 更新商品 SPU DTO
|
||||
*/
|
||||
public void updateProductSpu(ProductSpuUpdateReqDTO updateDTO) {
|
||||
productSpuService.updateProductSpu(ProductSpuConvert.INSTANCE.convert(updateDTO));
|
||||
public void updateProductSpu(ProductSpuAndSkuUpdateReqDTO updateDTO) {
|
||||
// 校验商品分类是否合法
|
||||
this.checkProductCategory(updateDTO.getCid());
|
||||
// 创建商品 SKU 对象,并进行校验
|
||||
List<ProductSkuCreateOrUpdateBO> skuBOs = ProductSpuConvert.INSTANCE.convert02(updateDTO.getSkus());
|
||||
this.checkProductAttr(skuBOs);
|
||||
// 更新商品 SPU 记录
|
||||
ProductSpuUpdateBO spuUpdateBO = ProductSpuConvert.INSTANCE.convert(updateDTO);
|
||||
spuUpdateBO.setPrice(skuBOs.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateBO::getPrice)).get().getPrice()); // 求最小价格
|
||||
spuUpdateBO.setQuantity(skuBOs.stream().mapToInt(ProductSkuCreateOrUpdateBO::getQuantity).sum()); // 求库存之和
|
||||
productSpuService.updateProductSpu(spuUpdateBO);
|
||||
// 更新商品 SKU 记录
|
||||
productSkuService.updateProductSkus(updateDTO.getId(), skuBOs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,4 +118,57 @@ public class ProductSpuManager {
|
||||
return ProductSpuConvert.INSTANCE.convertPage(pageResultBO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加或修改商品 SPU 时,校验商品分类是否合法
|
||||
*
|
||||
* @param cid 商品分类编号
|
||||
* @return 商品分类
|
||||
*/
|
||||
private ProductCategoryBO checkProductCategory(Integer cid) {
|
||||
ProductCategoryBO categoryBO = productCategoryService.getProductCategory(cid);
|
||||
if (categoryBO == null) {
|
||||
// 不存在
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
if (ProductCategoryIdEnum.ROOT.getId().equals(categoryBO.getPid())) {
|
||||
// 商品只能添加到二级分类下
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2);
|
||||
}
|
||||
return categoryBO;
|
||||
}
|
||||
|
||||
private List<ProductAttrKeyValueBO> checkProductAttr(List<ProductSkuCreateOrUpdateBO> skuBOs) {
|
||||
// 第一步,校验 SKU 使用到的规格是否存在
|
||||
Set<Integer> attrValueIds = new HashSet<>();
|
||||
skuBOs.forEach(sku -> attrValueIds.addAll(sku.getAttrValueIds()));
|
||||
List<ProductAttrKeyValueBO> attrKeyValueBOs = productAttrService.validProductAttr(attrValueIds, true);
|
||||
// 第二步,校验 SKU 设置的规格是否合法,例如说数量是否一致,是否重复等等
|
||||
// 创建 ProductAttrDetailBO 的映射。其中,KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号
|
||||
Map<Integer, ProductAttrKeyValueBO> productAttrDetailBOMap = attrKeyValueBOs.stream().collect(
|
||||
Collectors.toMap(ProductAttrKeyValueBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
|
||||
// 1. 先校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId
|
||||
for (ProductSkuCreateOrUpdateBO sku : skuBOs) {
|
||||
Set<Integer> attrIds = sku.getAttrValueIds().stream().map(attrValueId -> productAttrDetailBOMap.get(attrValueId).getAttrKeyId())
|
||||
.collect(Collectors.toSet());
|
||||
if (attrIds.size() != sku.getAttrValueIds().size()) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE);
|
||||
}
|
||||
}
|
||||
// 2. 再校验,每个 Sku 的规格值的数量,是一致的。
|
||||
int attrValueIdsSize = skuBOs.get(0).getAttrValueIds().size();
|
||||
for (int i = 1; i < skuBOs.size(); i++) {
|
||||
if (attrValueIdsSize != skuBOs.get(i).getAttrValueIds().size()) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
|
||||
}
|
||||
}
|
||||
// 3. 最后校验,每个 Sku 之间不是重复的
|
||||
Set<Set<Integer>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
|
||||
for (ProductSkuCreateOrUpdateBO sku : skuBOs) {
|
||||
if (!skuAttrValues.add(new HashSet<>(sku.getAttrValueIds()))) { // 添加失败,说明重复
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SPU_SKU_NOT_DUPLICATE);
|
||||
}
|
||||
}
|
||||
return attrKeyValueBOs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.productservice.manager.spu.ProductSpuManager;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class ProductSpuRpcImpl implements ProductSpuRpc {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateProductSpu(ProductSpuUpdateReqDTO updateDTO) {
|
||||
public CommonResult<Boolean> updateProductSpu(ProductSpuAndSkuUpdateReqDTO updateDTO) {
|
||||
productSpuManager.updateProductSpu(updateDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@@ -1,31 +1,26 @@
|
||||
package cn.iocoder.mall.productservice.service.sku;
|
||||
|
||||
import cn.iocoder.common.framework.enums.CommonStatusEnum;
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||
import cn.iocoder.common.framework.util.StringUtils;
|
||||
import cn.iocoder.mall.productservice.convert.sku.ProductSkuConvert;
|
||||
import cn.iocoder.mall.productservice.dal.mysql.dataobject.spu.ProductSkuDO;
|
||||
import cn.iocoder.mall.productservice.dal.mysql.mapper.sku.ProductSkuMapper;
|
||||
import cn.iocoder.mall.productservice.service.attr.bo.ProductAttrKeyValueBO;
|
||||
import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.*;
|
||||
|
||||
@Service
|
||||
public class ProductSkuService {
|
||||
|
||||
@Autowired
|
||||
private ProductSkuMapper productSkuMapper;
|
||||
|
||||
public void createProductSkus(Integer spuId, List<ProductSkuCreateOrUpdateBO> createBOs) {
|
||||
List<ProductSkuDO> skus = ProductSkuConvert.INSTANCE.convertList(createBOs);
|
||||
public void createProductSkus(Integer spuId, List<ProductSkuCreateOrUpdateBO> createSkuBOs) {
|
||||
List<ProductSkuDO> skus = ProductSkuConvert.INSTANCE.convertList(createSkuBOs);
|
||||
skus.forEach(sku -> {
|
||||
sku.setStatus(CommonStatusEnum.ENABLE.getValue());
|
||||
sku.setSpuId(spuId);
|
||||
@@ -33,42 +28,64 @@ public class ProductSkuService {
|
||||
productSkuMapper.insertList(skus);
|
||||
}
|
||||
|
||||
public void updateProductSkus(Integer spuId, List<ProductSkuCreateOrUpdateBO> createBOs) {
|
||||
|
||||
public void updateProductSkus(Integer spuId, List<ProductSkuCreateOrUpdateBO> skuUpdateBOs) {
|
||||
List<ProductSkuDO> existsSkus = productSkuMapper.selectListBySpuIdAndStatus(spuId,
|
||||
CommonStatusEnum.ENABLE.getValue());
|
||||
List<ProductSkuDO> insertSkus = new ArrayList<>(); // 1、找不到,进行插入
|
||||
List<Integer> deleteSkus = new ArrayList<>(); // 2、多余的,删除
|
||||
List<ProductSkuDO> updateSkus = new ArrayList<>(); // 3、找的到,进行更新。
|
||||
for (ProductSkuCreateOrUpdateBO skuUpdateDTO : skuUpdateBOs) {
|
||||
ProductSkuDO existsSku = findProductSku(skuUpdateDTO.getAttrValueIds(), existsSkus);
|
||||
// 3、找的到,进行更新。
|
||||
if (existsSku != null) {
|
||||
// 移除
|
||||
existsSkus.remove(existsSku);
|
||||
// 创建 ProductSkuDO
|
||||
updateSkus.add(ProductSkuConvert.INSTANCE.convert(skuUpdateDTO).setId(existsSku.getId()));
|
||||
continue;
|
||||
}
|
||||
// 1、找不到,进行插入
|
||||
ProductSkuDO insertSku = ProductSkuConvert.INSTANCE.convert(skuUpdateDTO)
|
||||
.setSpuId(spuId).setStatus(CommonStatusEnum.ENABLE.getValue());
|
||||
insertSkus.add(insertSku);
|
||||
}
|
||||
// 2、多余的,删除
|
||||
if (!existsSkus.isEmpty()) {
|
||||
deleteSkus.addAll(existsSkus.stream().map(ProductSkuDO::getId).collect(Collectors.toList()));
|
||||
}
|
||||
// 执行修改 Sku
|
||||
if (!insertSkus.isEmpty()) {
|
||||
productSkuMapper.insertList(insertSkus);
|
||||
}
|
||||
if (!updateSkus.isEmpty()) {
|
||||
updateSkus.forEach(productSkuDO -> productSkuMapper.updateById(productSkuDO));
|
||||
}
|
||||
if (!deleteSkus.isEmpty()) {
|
||||
productSkuMapper.deleteBatchIds(deleteSkus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 sku 是否合法
|
||||
* 获得 sku 数组中,指定规格的 sku
|
||||
*
|
||||
* @param skuBOs 商品 SKU 添加信息
|
||||
* @param attrKeyValueBOs 商品规格明细数组
|
||||
* @param attrValueIds 指定规格 Value 的编号数组
|
||||
* @param skus sku 数组
|
||||
* @return 符合条件的 sku
|
||||
*/
|
||||
public void validProductSku(List<ProductSkuCreateOrUpdateBO> skuBOs, List<ProductAttrKeyValueBO> attrKeyValueBOs) {
|
||||
// 创建 ProductAttrDetailBO 的映射。其中,KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号
|
||||
Map<Integer, ProductAttrKeyValueBO> productAttrDetailBOMap = attrKeyValueBOs.stream().collect(
|
||||
Collectors.toMap(ProductAttrKeyValueBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
|
||||
// 1. 先校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId
|
||||
for (ProductSkuCreateOrUpdateBO sku : skuBOs) {
|
||||
Set<Integer> attrIds = sku.getAttrValueIds().stream().map(attrValueId -> productAttrDetailBOMap.get(attrValueId).getAttrKeyId())
|
||||
.collect(Collectors.toSet());
|
||||
if (attrIds.size() != sku.getAttrValueIds().size()) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE);
|
||||
}
|
||||
}
|
||||
// 2. 再校验,每个 Sku 的规格值的数量,是一致的。
|
||||
int attrValueIdsSize = skuBOs.get(0).getAttrValueIds().size();
|
||||
for (int i = 1; i < skuBOs.size(); i++) {
|
||||
if (attrValueIdsSize != skuBOs.get(i).getAttrValueIds().size()) {
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
|
||||
}
|
||||
}
|
||||
// 3. 最后校验,每个 Sku 之间不是重复的
|
||||
Set<Set<Integer>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
|
||||
for (ProductSkuCreateOrUpdateBO sku : skuBOs) {
|
||||
if (!skuAttrValues.add(new HashSet<>(sku.getAttrValueIds()))) { // 添加失败,说明重复
|
||||
throw ServiceExceptionUtil.exception(PRODUCT_SPU_SKU_NOT_DUPLICATE);
|
||||
private ProductSkuDO findProductSku(Collection<Integer> attrValueIds, List<ProductSkuDO> skus) {
|
||||
if (CollectionUtils.isEmpty(skus)) {
|
||||
return null;
|
||||
}
|
||||
// 创建成 Set ,方便后面比较
|
||||
attrValueIds = new HashSet<>(attrValueIds);
|
||||
for (ProductSkuDO sku : skus) {
|
||||
Set<Integer> skuAttrValueIds = StringUtils.split(sku.getAttrs(), ",")
|
||||
.stream().map(Integer::parseInt).collect(Collectors.toSet());
|
||||
if (attrValueIds.equals(skuAttrValueIds)) {
|
||||
return sku;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ public class ProductSpuUpdateBO {
|
||||
/**
|
||||
* 排序字段
|
||||
*/
|
||||
@NotNull(message = "排序字段不能为空")
|
||||
private Integer sort;
|
||||
/**
|
||||
* 价格
|
||||
|
||||
Reference in New Issue
Block a user