feature(uniapp商品): 商品业务代码调整

pull/2/head
luowenfeng 2022-08-24 14:08:32 +08:00
parent c2fd24f597
commit 0bc2ef1d39
6 changed files with 86 additions and 53 deletions

View File

@ -173,6 +173,23 @@ public class CollectionUtils {
return valueFunc.apply(t); return valueFunc.apply(t);
} }
public static <T, V extends Comparable<? super V>> V getMinValue(List<T> from, Function<T, V> valueFunc) {
if (CollUtil.isEmpty(from)) {
return null;
}
assert from.size() > 0; // 断言,避免告警
T t = from.stream().min(Comparator.comparing(valueFunc)).get();
return valueFunc.apply(t);
}
public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc, BinaryOperator<V> accumulator) {
if (CollUtil.isEmpty(from)) {
return null;
}
assert from.size() > 0; // 断言,避免告警
return from.stream().map(valueFunc).reduce(accumulator).get();
}
public static <T> void addIfNotNull(Collection<T> coll, T item) { public static <T> void addIfNotNull(Collection<T> coll, T item) {
if (item == null) { if (item == null) {
return; return;

View File

@ -15,6 +15,7 @@ public interface ErrorCodeConstants {
ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类"); ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类");
ErrorCode PRODUCT_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除"); ErrorCode PRODUCT_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除");
ErrorCode PRODUCT_CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用"); ErrorCode PRODUCT_CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用");
ErrorCode PRODUCT_CATEGORY_LEVEL = new ErrorCode(1008001005, "商品需挂在三级分类下");
// ========== 品牌相关编号 1008002000 ========== // ========== 品牌相关编号 1008002000 ==========
ErrorCode PRODUCT_BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在"); ErrorCode PRODUCT_BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");
@ -31,4 +32,8 @@ public interface ErrorCodeConstants {
// ========== 商品sku 1008006000 ========== // ========== 商品sku 1008006000 ==========
ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品sku不存在"); ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品sku不存在");
ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品sku的属性组合存在重复"); ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品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 ,必须不重复");
} }

View File

@ -93,6 +93,14 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
@Override @Override
public void validateProductCategory(Long id) { public void validateProductCategory(Long id) {
Integer level = categoryLevel(id, 1);
if(level < 3){
throw exception(PRODUCT_CATEGORY_LEVEL);
}
}
// 校验分类级别
private Integer categoryLevel(Long id, int level){
ProductCategoryDO category = productCategoryMapper.selectById(id); ProductCategoryDO category = productCategoryMapper.selectById(id);
if (category == null) { if (category == null) {
throw exception(PRODUCT_CATEGORY_NOT_EXISTS); throw exception(PRODUCT_CATEGORY_NOT_EXISTS);
@ -100,6 +108,10 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
if (ObjectUtil.notEqual(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { if (ObjectUtil.notEqual(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
throw exception(PRODUCT_CATEGORY_DISABLED); throw exception(PRODUCT_CATEGORY_DISABLED);
} }
if(category.getParentId() == 0) {
return level;
}
return categoryLevel(category.getParentId(), ++level);
} }
@Override @Override

View File

@ -68,14 +68,14 @@ public interface ProductSkuService {
* *
* @param list sku * @param list sku
*/ */
void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list); void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType);
/** /**
* SKU * SKU
* *
* @param list SKU * @param list SKU
*/ */
void createProductSkus(List<ProductSkuDO> list); void createProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId);
/** /**
* SPU SKU * SPU SKU

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.product.service.sku; package cn.iocoder.yudao.module.product.service.sku;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.ProductPropertyRespVO;
import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO; 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.ProductSkuBaseVO;
@ -11,6 +12,7 @@ import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper; import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -86,45 +88,52 @@ public class ProductSkuServiceImpl implements ProductSkuService {
return productSkuMapper.selectPage(pageReqVO); return productSkuMapper.selectPage(pageReqVO);
} }
// TODO luowenfeng参考下 yudao-cloud 的 checkProductAttr 方法,重构下
@Override @Override
public void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list) { public void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType) {
List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> Optional.of(p.getProperties()).orElse(new ArrayList<>()).stream()).collect(Collectors.toList()); // 多规格才需校验
// 校验规格属性存在 if(specType.equals(ProductSpuSpecTypeEnum.DISABLE.getType())){
// TODO @luowenfeng使用 CollectionUtils.convert List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> Optional.of(p.getProperties()).orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
List<Long> propertyIds = skuPropertyList.stream().map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toList()); // 1、校验规格属性存在
List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(propertyIds); List<Long> propertyIds = CollectionUtils.convertList(skuPropertyList, ProductSkuBaseVO.Property::getPropertyId);
// TODO @luowenfeng校验数量一致 List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(propertyIds);
if (propertyAndValueList.isEmpty()) { if (propertyAndValueList.size() == propertyIds.size()){
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 exception(PROPERTY_NOT_EXISTS); throw exception(PROPERTY_NOT_EXISTS);
} }
// 判断改属性名对应的属性值是否存在,不存在,给出提示 // 2. 校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId
if (!productPropertyRespVO.getPropertyValueList().stream().map(ProductPropertyValueRespVO::getId).collect(Collectors.toSet()).contains(p.getValueId())) { List<ProductPropertyValueRespVO> collect = propertyAndValueList.stream()
throw exception(ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS); .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);
}
});
// 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);
}
} }
});
// 校验是否有重复的sku组合 // 4. 最后校验,每个 Sku 之间不是重复的
List<List<ProductSkuBaseVO.Property>> skuProperties = list.stream().map(ProductSkuBaseVO::getProperties).collect(Collectors.toList()); Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
Set<String> skuPropertiesConvertSet = new HashSet<>(); for (ProductSkuCreateOrUpdateReqVO sku : list) {
skuProperties.forEach(p -> { if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复
// 组合属性值id为 1~2~3.... 形式的字符串通过set的特性判断是否有重复的组合 throw exception(ErrorCodeConstants.PRODUCT_SPU_SKU_NOT_DUPLICATE);
if (!skuPropertiesConvertSet.add(p.stream().map(pr -> String.valueOf(pr.getValueId())).sorted().collect(Collectors.joining("")))) { }
throw exception(ErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
} }
}); }
} }
@Override @Override
public void createProductSkus(List<ProductSkuDO> skuDOList) { public void createProductSkus(List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList, Long spuId) {
// 批量插入 SKU
List<ProductSkuDO> skuDOList = ProductSkuConvert.INSTANCE.convertSkuDOList(skuCreateReqList);
skuDOList.forEach(v->v.setSpuId(spuId));
productSkuMapper.insertBatch(skuDOList); productSkuMapper.insertBatch(skuDOList);
} }

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.product.service.spu; package cn.iocoder.yudao.module.product.service.spu;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.ProductPropertyRespVO;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO; 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.propertyvalue.vo.ProductPropertyValueRespVO;
@ -58,31 +59,23 @@ public class ProductSpuServiceImpl implements ProductSpuService {
@Transactional @Transactional
public Long createProductSpu(ProductSpuCreateReqVO createReqVO) { public Long createProductSpu(ProductSpuCreateReqVO createReqVO) {
// 校验分类 // 校验分类
// TODO @luowenfeng可以在这个类里加个方法校验分类商品必须挂在三级分类下
categoryService.validateProductCategory(createReqVO.getCategoryId()); categoryService.validateProductCategory(createReqVO.getCategoryId());
// TODO @luowenfeng校验品牌 // TODO @luowenfeng校验品牌
// 校验SKU // 校验SKU
List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus(); List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
// 多规格才需校验 productSkuService.validateProductSkus(skuCreateReqList, createReqVO.getSpecType());
// TODO @luowenfeng可以把 type 传递到 productSkuService 里,通过它统一判断处理
if(Objects.equals(createReqVO.getSpecType(), ProductSpuSpecTypeEnum.DISABLE.getType())) {
productSkuService.validateProductSkus(skuCreateReqList);
}
// 插入 SPU // 插入 SPU
ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO); ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
// TODO @luowenfeng可以在 CollectionUtils 增加 getMaxValue 方法,增加一个 defaultValue 方法,如果为空,则返回 defaultValue spu.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
spu.setMarketPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getMarketPrice).max(Integer::compare).orElse(0)); spu.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
spu.setMaxPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getPrice).max(Integer::compare).orElse(0)); spu.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
spu.setMinPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getPrice).min(Integer::compare).orElse(0)); spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
// TODO @luowenfeng库存求和
ProductSpuMapper.insert(spu); ProductSpuMapper.insert(spu);
// 批量插入 SKU // 插入 SKU
// TODO @luowenfengconvert 逻辑,交给 createProductSkus 一起处理 productSkuService.createProductSkus(skuCreateReqList, spu.getId());
List<ProductSkuDO> skuDOList = ProductSkuConvert.INSTANCE.convertSkuDOList(skuCreateReqList);
skuDOList.forEach(v->v.setSpuId(spu.getId()));
productSkuService.createProductSkus(skuDOList);
// 返回 // 返回
return spu.getId(); return spu.getId();
} }
@ -98,10 +91,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 校验SKU // 校验SKU
List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus(); List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
// 多规格才需校验 // 多规格才需校验
// TODO @luowenfeng可以把 type 传递到 productSkuService 里,通过它统一判断处理 productSkuService.validateProductSkus(skuCreateReqList, updateReqVO.getSpecType());
if(updateReqVO.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
productSkuService.validateProductSkus(skuCreateReqList);
}
// 更新 SPU // 更新 SPU
ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO); ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);