初步完成商品CRUD
This commit is contained in:
parent
6428f0fcaf
commit
70816371e5
|
@ -50,4 +50,14 @@ public class ProductSkuBaseVO {
|
|||
|
||||
@Schema(description = "商品体积", example = "1024") // 单位:m^3 平米
|
||||
private Double volume;
|
||||
/**
|
||||
* 一级分销的佣金,单位:分
|
||||
*/
|
||||
@Schema(description = "一级分销的佣金", example = "1024")
|
||||
private Integer subCommissionFirstPrice;
|
||||
/**
|
||||
* 二级分销的佣金,单位:分
|
||||
*/
|
||||
@Schema(description = "二级分销的佣金", example = "1024")
|
||||
private Integer subCommissionSecondPrice;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public class ProductSpuController {
|
|||
@GetMapping("/page")
|
||||
@Operation(summary = "获得商品 SPU 分页")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:query')")
|
||||
public CommonResult<PageResult<ProductSpuRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
|
||||
public CommonResult<PageResult<ProductSpuPageRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
|
||||
return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO)));
|
||||
}
|
||||
|
||||
|
|
|
@ -38,16 +38,11 @@ public class ProductSpuBaseVO {
|
|||
@NotEmpty(message = "商品详情不能为空")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "商品条码(一维码)", required = true, example = "芋道")
|
||||
@NotEmpty(message = "商品条码(一维码)不能为空")
|
||||
private String barCode;
|
||||
|
||||
@Schema(description = "商品分类编号", required = true, example = "芋道")
|
||||
@NotEmpty(message = "商品分类编号不能为空")
|
||||
@NotNull(message = "商品分类编号不能为空")
|
||||
private Long categoryId;
|
||||
|
||||
@Schema(description = "商品品牌编号", required = true, example = "芋道")
|
||||
@NotEmpty(message = "商品品牌编号不能为空")
|
||||
private Long brandId;
|
||||
|
||||
@Schema(description = "商品封面图", required = true, example = "芋道")
|
||||
|
@ -55,99 +50,71 @@ public class ProductSpuBaseVO {
|
|||
private String picUrl;
|
||||
|
||||
@Schema(description = "商品轮播图", required = true)
|
||||
@NotEmpty(message = "商品轮播图不能为空")
|
||||
private List<String> sliderPicUrls;
|
||||
|
||||
@Schema(description = "商品视频")
|
||||
private String videoUrl;
|
||||
|
||||
@Schema(description = "单位", required = true, example = "1")
|
||||
@NotEmpty(message = "商品单位不能为空")
|
||||
@NotNull(message = "商品单位不能为空")
|
||||
private Integer unit;
|
||||
|
||||
@Schema(description = "排序字段", required = true, example = "1")
|
||||
@NotEmpty(message = "商品排序字段不能为空")
|
||||
@NotNull(message = "商品排序字段不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "商品状态", required = true, example = "1")
|
||||
@NotEmpty(message = "商品状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
// ========== SKU 相关字段 =========
|
||||
|
||||
@Schema(description = "规格类型", required = true, example = "true")
|
||||
@NotEmpty(message = "商品规格类型不能为空")
|
||||
@NotNull(message = "商品规格类型不能为空")
|
||||
private Boolean specType;
|
||||
|
||||
@Schema(description = "商品价格", required = true, example = "1212")
|
||||
@NotEmpty(message = "商品价格不能为空")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "市场价", required = true, example = "3")
|
||||
@NotEmpty(message = "商品市场价不能为空")
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "成本价", required = true, example = "12")
|
||||
@NotEmpty(message = "商品成本价不能为空")
|
||||
private Integer costPrice;
|
||||
|
||||
@Schema(description = "库存", required = true, example = "111")
|
||||
@NotEmpty(message = "商品库存不能为空")
|
||||
private Integer stock;
|
||||
|
||||
// ========== 物流相关字段 =========
|
||||
|
||||
@Schema(description = "物流配置模板编号", required = true, example = "111")
|
||||
@NotEmpty(message = "物流配置模板编号不能为空")
|
||||
@NotNull(message = "物流配置模板编号不能为空")
|
||||
private Long deliveryTemplateId;
|
||||
|
||||
// ========== 营销相关字段 =========
|
||||
|
||||
@Schema(description = "是否热卖推荐", required = true, example = "true")
|
||||
@NotEmpty(message = "商品推荐不能为空")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendHot;
|
||||
|
||||
@Schema(description = "是否优惠推荐", required = true, example = "true")
|
||||
@NotEmpty(message = "商品推荐不能为空")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendBenefit;
|
||||
|
||||
@Schema(description = "是否精品推荐", required = true, example = "true")
|
||||
@NotEmpty(message = "商品推荐不能为空")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendBest;
|
||||
|
||||
@Schema(description = "是否新品推荐", required = true, example = "true")
|
||||
@NotEmpty(message = "商品推荐不能为空")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendNew;
|
||||
|
||||
@Schema(description = "是否优品推荐", required = true, example = "true")
|
||||
@NotEmpty(message = "商品推荐不能为空")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendGood;
|
||||
|
||||
@Schema(description = "赠送积分", required = true, example = "111")
|
||||
@NotEmpty(message = "商品赠送积分不能为空")
|
||||
@NotNull(message = "商品赠送积分不能为空")
|
||||
private Integer giveIntegral;
|
||||
|
||||
@Schema(description = "赠送的优惠劵编号的数组")
|
||||
@Schema(description = "赠送的优惠劵编号的数组") // TODO 这块前端还未实现
|
||||
private List<Long> giveCouponTemplateIds;
|
||||
|
||||
@Schema(description = "分销类型")
|
||||
@NotNull(message = "商品分销类型不能为空")
|
||||
private Boolean subCommissionType;
|
||||
|
||||
@Schema(description = "活动展示顺序")
|
||||
@Schema(description = "活动展示顺序") // TODO 这块前端还未实现
|
||||
private List<Integer> activityOrders;
|
||||
|
||||
// ========== 统计相关字段 =========
|
||||
|
||||
@Schema(description = "商品销量", required = true, example = "芋道")
|
||||
@NotEmpty(message = "商品销量不能为空")
|
||||
private Integer salesCount;
|
||||
|
||||
@Schema(description = "虚拟销量", required = true, example = "芋道")
|
||||
@NotEmpty(message = "商品虚拟销量不能为空")
|
||||
private Integer virtualSalesCount;
|
||||
|
||||
@Schema(description = "浏览量", required = true, example = "芋道")
|
||||
@NotEmpty(message = "商品浏览量不能为空")
|
||||
private Integer browseCount;
|
||||
|
||||
}
|
||||
|
|
|
@ -15,31 +15,7 @@ public class ProductSpuPageReqVO extends PageParam {
|
|||
@Schema(description = "商品名称", example = "yutou")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "商品编码", example = "yudaoyuanma")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "分类编号", example = "1")
|
||||
private Long categoryId;
|
||||
|
||||
@Schema(description = "商品品牌编号", example = "1")
|
||||
private Long brandId;
|
||||
|
||||
@Schema(description = "上下架状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "销量最小值", example = "1")
|
||||
private Integer salesCountMin;
|
||||
|
||||
@Schema(description = "销量最大值", example = "1024")
|
||||
private Integer salesCountMax;
|
||||
|
||||
@Schema(description = "市场价最小值", example = "1")
|
||||
private Integer marketPriceMin;
|
||||
|
||||
@Schema(description = "市场价最大值", example = "1024")
|
||||
private Integer marketPriceMax;
|
||||
|
||||
@Schema(description = "是否库存告警", example = "true")
|
||||
private Boolean alarmStock;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 分页 response VO")
|
||||
@Data
|
||||
public class ProductSpuPageRespVO {
|
||||
@Schema(description = "spuId", example = "1")
|
||||
private Long id;
|
||||
@Schema(description = "商品封面图", example = "1")
|
||||
private String picUrl;
|
||||
@Schema(description = "商品名称", example = "1")
|
||||
private String name;
|
||||
@Schema(description = "商品价格", example = "1")
|
||||
private Integer price;
|
||||
@Schema(description = "商品销量", example = "1")
|
||||
private Integer salesCount;
|
||||
@Schema(description = "商品排序", example = "1")
|
||||
private Integer stock;
|
||||
@Schema(description = "商品封面图", example = "1")
|
||||
private Integer sort;
|
||||
@Schema(description = "商品创建时间", example = "1")
|
||||
private LocalDateTime createTime;
|
||||
@Schema(description = "商品状态", example = "1")
|
||||
private Integer status;
|
||||
}
|
|
@ -19,22 +19,4 @@ public class ProductSpuRespVO extends ProductSpuBaseVO {
|
|||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== SKU 相关字段 =========
|
||||
|
||||
@Schema(description = "库存", required = true, example = "true")
|
||||
private Integer totalStock;
|
||||
|
||||
@Schema(description = " 最小价格,单位使用:分", required = true, example = "1024")
|
||||
private Integer minPrice;
|
||||
|
||||
@Schema(description = "最大价格,单位使用:分", required = true, example = "1024")
|
||||
private Integer maxPrice;
|
||||
|
||||
@Schema(description = "商品销量", example = "1024")
|
||||
private Integer salesCount;
|
||||
|
||||
// ========== 统计相关字段 =========
|
||||
|
||||
@Schema(description = "点击量", example = "1024")
|
||||
private Integer clickCount;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,8 @@ public interface ProductSkuConvert {
|
|||
|
||||
List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list);
|
||||
|
||||
default List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId, String spuName) {
|
||||
default List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId) {
|
||||
List<ProductSkuDO> result = convertList06(list);
|
||||
// result.forEach(item -> item.setSpuId(spuId).setSpuName(spuName)); TODO ProductSkuDO中已经没有name相关属性
|
||||
result.forEach(item -> item.setSpuId(spuId));
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public interface ProductSpuConvert {
|
|||
|
||||
List<ProductSpuDO> convertList(List<ProductSpuDO> list);
|
||||
|
||||
PageResult<ProductSpuRespVO> convertPage(PageResult<ProductSpuDO> page);
|
||||
PageResult<ProductSpuPageRespVO> convertPage(PageResult<ProductSpuDO> page);
|
||||
|
||||
ProductSpuPageReqVO convert(AppProductSpuPageReqVO bean);
|
||||
|
||||
|
|
|
@ -116,19 +116,19 @@ public class ProductSpuDO extends TenantBaseDO {
|
|||
/**
|
||||
* 商品价格,单位使用:分
|
||||
*
|
||||
* 基于其对应的 {@link ProductSkuDO#getPrice()} 最小值
|
||||
* 基于其对应的 {@link ProductSkuDO#getPrice()} sku单价最低的商品的
|
||||
*/
|
||||
private Integer price;
|
||||
/**
|
||||
* 市场价,单位使用:分
|
||||
*
|
||||
* 基于其对应的 {@link ProductSkuDO#getMarketPrice()} 最大值 TODO 芋艿:待确定最大还是最小
|
||||
* 基于其对应的 {@link ProductSkuDO#getMarketPrice()} sku单价最低的商品的
|
||||
*/
|
||||
private Integer marketPrice;
|
||||
/**
|
||||
* 成本价,单位使用:分
|
||||
*
|
||||
* 基于其对应的 {@link ProductSkuDO#getCostPrice()} 最大值 TODO 芋艿:待确定最大还是最小
|
||||
* 基于其对应的 {@link ProductSkuDO#getCostPrice()} sku单价最低的商品的
|
||||
*/
|
||||
private Integer costPrice;
|
||||
/**
|
||||
|
|
|
@ -24,11 +24,6 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
|
|||
return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
|
||||
.likeIfPresent(ProductSpuDO::getName, reqVO.getName())
|
||||
.eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
|
||||
.eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
|
||||
.leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
|
||||
.geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
|
||||
.leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
|
||||
.geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
|
||||
.orderByDesc(ProductSpuDO::getSort));
|
||||
}
|
||||
|
||||
|
@ -36,13 +31,7 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
|
|||
return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
|
||||
.likeIfPresent(ProductSpuDO::getName, reqVO.getName())
|
||||
.eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
|
||||
.eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
|
||||
.leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
|
||||
.geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
|
||||
.leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
|
||||
.geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
|
||||
.inIfPresent(ProductSpuDO::getId, alarmStockSpuIds) // 库存告警
|
||||
.eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
|
||||
.orderByDesc(ProductSpuDO::getSort));
|
||||
}
|
||||
|
||||
|
@ -52,8 +41,6 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
|
|||
.eqIfPresent(ProductSpuDO::getStatus, status);
|
||||
// 排序逻辑
|
||||
if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) {
|
||||
// TODO ProductSpuDO 已经没有maxPrice 属性
|
||||
//query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getMaxPrice);
|
||||
} else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) {
|
||||
query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getSalesCount);
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
|||
if (category == null) {
|
||||
throw exception(CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
if (Objects.equals(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
|
||||
if (Objects.equals(category.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||
throw exception(CATEGORY_DISABLED, category.getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,19 +56,17 @@ public interface ProductSkuService {
|
|||
* 批量创建 SKU
|
||||
*
|
||||
* @param spuId 商品 SPU 编号
|
||||
* @param spuName 商品 SPU 名称
|
||||
* @param list SKU 对象集合
|
||||
*/
|
||||
void createSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> list);
|
||||
void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list);
|
||||
|
||||
/**
|
||||
* 根据 SPU 编号,批量更新它的 SKU 信息
|
||||
*
|
||||
* @param spuId SPU 编码
|
||||
* @param spuName 商品 SPU 名称
|
||||
* @param skus SKU 的集合
|
||||
*/
|
||||
void updateSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skus);
|
||||
void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
|
||||
|
||||
/**
|
||||
* 更新 SKU 库存(增量)
|
||||
|
|
|
@ -84,10 +84,17 @@ public class ProductSkuServiceImpl implements ProductSkuService {
|
|||
return;
|
||||
}
|
||||
|
||||
// 0、校验skus是否为空
|
||||
if (CollUtil.isEmpty(skus)){
|
||||
throw exception(SKU_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 1、校验属性项存在
|
||||
Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null)
|
||||
.flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性
|
||||
.map(ProductSkuCreateOrUpdateReqVO.Property::getPropertyId) // 将每个 Property 转换成对应的 propertyId,最后形成集合
|
||||
// 遍历多个 Property 属性
|
||||
.flatMap(p -> p.getProperties().stream())
|
||||
// 将每个 Property 转换成对应的 propertyId,最后形成集合
|
||||
.map(ProductSkuCreateOrUpdateReqVO.Property::getPropertyId)
|
||||
.collect(Collectors.toSet());
|
||||
List<ProductPropertyDO> propertyList = productPropertyService.getPropertyList(propertyIds);
|
||||
if (propertyList.size() != propertyIds.size()) {
|
||||
|
@ -107,22 +114,24 @@ public class ProductSkuServiceImpl implements ProductSkuService {
|
|||
int attrValueIdsSize = skus.get(0).getProperties().size();
|
||||
for (int i = 1; i < skus.size(); i++) {
|
||||
if (attrValueIdsSize != skus.get(i).getProperties().size()) {
|
||||
throw exception(ErrorCodeConstants.SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
|
||||
throw exception(SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 最后校验,每个 Sku 之间不是重复的
|
||||
Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
|
||||
// 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
|
||||
Set<Set<Long>> skuAttrValues = new HashSet<>();
|
||||
for (ProductSkuCreateOrUpdateReqVO sku : skus) {
|
||||
if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuCreateOrUpdateReqVO.Property::getValueId))) { // 添加失败,说明重复
|
||||
throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
|
||||
// 添加失败,说明重复
|
||||
if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuCreateOrUpdateReqVO.Property::getValueId))) {
|
||||
throw exception(SPU_SKU_NOT_DUPLICATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
|
||||
productSkuMapper.insertBatch(ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuId, spuName));
|
||||
public void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
|
||||
productSkuMapper.insertBatch(ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuId));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,7 +161,7 @@ public class ProductSkuServiceImpl implements ProductSkuService {
|
|||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skus) {
|
||||
public void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
|
||||
// 构建属性与 SKU 的映射关系;
|
||||
Map<String, Long> existsSkuMap = convertMap(productSkuMapper.selectListBySpuId(spuId),
|
||||
ProductSkuConvert.INSTANCE::buildPropertyKey, ProductSkuDO::getId);
|
||||
|
@ -160,13 +169,14 @@ public class ProductSkuServiceImpl implements ProductSkuService {
|
|||
// 拆分三个集合,新插入的、需要更新的、需要删除的
|
||||
List<ProductSkuDO> insertSkus = new ArrayList<>();
|
||||
List<ProductSkuDO> updateSkus = new ArrayList<>();
|
||||
List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertList06(skus, null, spuName);
|
||||
List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertList06(skus, null);
|
||||
allUpdateSkus.forEach(sku -> {
|
||||
String propertiesKey = ProductSkuConvert.INSTANCE.buildPropertyKey(sku);
|
||||
// 1、找得到的,进行更新
|
||||
Long existsSkuId = existsSkuMap.remove(propertiesKey);
|
||||
if (existsSkuId != null) {
|
||||
sku.setId(existsSkuId);
|
||||
// TODO 那spuId岂不是为null了
|
||||
updateSkus.add(sku);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
|
|||
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
|
||||
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
|
||||
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
|
||||
import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
|
||||
import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
|
||||
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
|
||||
|
@ -21,10 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
|
@ -54,20 +52,21 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createSpu(ProductSpuCreateReqVO createReqVO) {
|
||||
// 校验分类
|
||||
validateCategory(createReqVO.getCategoryId());
|
||||
// 校验品牌
|
||||
brandService.validateProductBrand(createReqVO.getBrandId());
|
||||
// 校验SKU
|
||||
List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = createReqVO.getSkus();
|
||||
productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());
|
||||
// 校验分类 TODO 暂不清楚为什么只能选择第三层的结点
|
||||
//validateCategory(createReqVO.getCategoryId());
|
||||
// 校验品牌 TODO 暂不校验
|
||||
//brandService.validateProductBrand(createReqVO.getBrandId());
|
||||
|
||||
// 插入 SPU
|
||||
List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = createReqVO.getSkus();
|
||||
// 校验SKU
|
||||
productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());
|
||||
ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
|
||||
// 初始化SPU中SKU相关属性
|
||||
initSpuFromSkus(spu, skuSaveReqList);
|
||||
// 插入 SPU
|
||||
productSpuMapper.insert(spu);
|
||||
// 插入 SKU
|
||||
productSkuService.createSkuList(spu.getId(), spu.getName(), skuSaveReqList);
|
||||
productSkuService.createSkuList(spu.getId(), skuSaveReqList);
|
||||
// 返回
|
||||
return spu.getId();
|
||||
}
|
||||
|
@ -90,7 +89,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
initSpuFromSkus(updateObj, skuSaveReqList);
|
||||
productSpuMapper.updateById(updateObj);
|
||||
// 批量更新 SKU
|
||||
productSkuService.updateSkuList(updateObj.getId(), updateObj.getName(), updateReqVO.getSkus());
|
||||
productSkuService.updateSkuList(updateObj.getId(), updateReqVO.getSkus());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,11 +100,25 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
* @param skus 商品 SKU 数组
|
||||
*/
|
||||
private void initSpuFromSkus(ProductSpuDO spu, List<ProductSkuCreateOrUpdateReqVO> skus) {
|
||||
spu.setMarketPrice(getMaxValue(skus, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
|
||||
// TODO ProductSpuDO中已没有相关属性
|
||||
//spu.setMaxPrice(getMaxValue(skus, ProductSkuCreateOrUpdateReqVO::getPrice));
|
||||
//spu.setMinPrice(getMinValue(skus, ProductSkuCreateOrUpdateReqVO::getPrice));
|
||||
//spu.setTotalStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
|
||||
// 断言,避免告警
|
||||
assert skus.size() > 0;
|
||||
// 获取sku单价最低的商品
|
||||
ProductSkuCreateOrUpdateReqVO vo = skus.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateReqVO::getPrice)).get();
|
||||
// sku单价最低的商品的价格
|
||||
spu.setPrice(vo.getPrice());
|
||||
// sku单价最低的商品的市场价格
|
||||
spu.setMarketPrice(vo.getMarketPrice());
|
||||
// sku单价最低的商品的成本价格
|
||||
spu.setCostPrice(vo.getCostPrice());
|
||||
// sku单价最低的商品的条形码
|
||||
spu.setBarCode(vo.getBarCode());
|
||||
// 默认状态为上架
|
||||
spu.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
|
||||
// TODO 默认商品销量和浏览量为零
|
||||
spu.setSalesCount(0);
|
||||
spu.setBrowseCount(0);
|
||||
// skus库存总数
|
||||
spu.setStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,14 +168,14 @@ public class ProductSpuServiceImpl implements ProductSpuService {
|
|||
|
||||
@Override
|
||||
public PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
|
||||
// 库存告警的 SPU 编号的集合
|
||||
// 库存告警的 SPU 编号的集合 TODO 一个接口一个接口来
|
||||
Set<Long> alarmStockSpuIds = null;
|
||||
if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
|
||||
alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId);
|
||||
if (CollUtil.isEmpty(alarmStockSpuIds)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
}
|
||||
//if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
|
||||
// alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId);
|
||||
// if (CollUtil.isEmpty(alarmStockSpuIds)) {
|
||||
// return PageResult.empty();
|
||||
// }
|
||||
//}
|
||||
// 分页查询
|
||||
return productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds);
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class ProductSkuServiceTest extends BaseDbUnitTest {
|
|||
);
|
||||
|
||||
// 调用
|
||||
productSkuService.updateSkuList(spuId, spuName, skus);
|
||||
productSkuService.updateSkuList(spuId, skus);
|
||||
// 断言
|
||||
List<ProductSkuDO> dbSkus = productSkuMapper.selectListBySpuId(spuId);
|
||||
assertEquals(dbSkus.size(), 2);
|
||||
|
|
|
@ -9,10 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
|
||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
|
||||
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
|
||||
|
@ -37,6 +34,7 @@ import java.util.*;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
|
||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
|
@ -83,21 +81,9 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
// 准备参数
|
||||
ProductSpuCreateReqVO createReqVO = randomPojo(ProductSpuCreateReqVO.class, o -> {
|
||||
o.setSpecType(true);
|
||||
o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
|
||||
});
|
||||
|
||||
// 校验SKU
|
||||
List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
|
||||
|
||||
Long spu = productSpuService.createSpu(createReqVO);
|
||||
ProductSpuDO productSpuDO = productSpuMapper.selectById(spu);
|
||||
|
||||
createReqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
|
||||
// TODO ProductSpuCreateReqVO中已没有相关属性
|
||||
// createReqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
|
||||
// createReqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
|
||||
// createReqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
|
||||
|
||||
assertPojoEquals(createReqVO, productSpuDO);
|
||||
|
||||
}
|
||||
|
@ -111,18 +97,9 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
|
||||
o.setId(createReqVO.getId()); // 设置更新的 ID
|
||||
o.setSpecType(true);
|
||||
o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
|
||||
});
|
||||
// 调用
|
||||
productSpuService.updateSpu(reqVO);
|
||||
|
||||
List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = reqVO.getSkus();
|
||||
reqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
|
||||
// TODO ProductSpuUpdateReqVO中已没有相关属性
|
||||
// reqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
|
||||
// reqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
|
||||
// reqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
|
||||
|
||||
// 校验是否更新正确
|
||||
ProductSpuDO spu = productSpuMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, spu);
|
||||
|
@ -132,7 +109,6 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
public void testValidateSpuExists_exception() {
|
||||
ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
|
||||
o.setSpecType(true);
|
||||
o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
|
||||
});
|
||||
// 调用
|
||||
Assertions.assertThrows(ServiceException.class, () -> productSpuService.updateSpu(reqVO));
|
||||
|
@ -175,7 +151,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
void getSpuPage_alarmStock_empty() {
|
||||
// 调用
|
||||
ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
|
||||
productSpuPageReqVO.setAlarmStock(true);
|
||||
//productSpuPageReqVO.setAlarmStock(true);
|
||||
|
||||
PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
|
||||
|
||||
|
@ -225,10 +201,10 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
|
||||
// 调用
|
||||
ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
|
||||
productSpuPageReqVO.setAlarmStock(true);
|
||||
//productSpuPageReqVO.setAlarmStock(true);
|
||||
PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
|
||||
|
||||
PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
|
||||
PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
|
||||
Assertions.assertIterableEquals(result.getList(), spuPage.getList());
|
||||
assertEquals(spuPage.getTotal(), result.getTotal());
|
||||
}
|
||||
|
@ -273,14 +249,14 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
|
|||
|
||||
// 调用
|
||||
ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
|
||||
productSpuPageReqVO.setAlarmStock(false);
|
||||
productSpuPageReqVO.setBrandId(brandId);
|
||||
productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
|
||||
//productSpuPageReqVO.setAlarmStock(false);
|
||||
//productSpuPageReqVO.setBrandId(brandId);
|
||||
//productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
|
||||
productSpuPageReqVO.setCategoryId(categoryId);
|
||||
|
||||
PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
|
||||
|
||||
PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
|
||||
PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
|
||||
assertEquals(result, spuPage);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue