From aea763e96eff6f838a77bce02c9c177ba903c377 Mon Sep 17 00:00:00 2001 From: luowenfeng <1092164058@qq.com> Date: Sat, 22 Oct 2022 17:51:26 +0800 Subject: [PATCH] =?UTF-8?q?feature(=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95):?= =?UTF-8?q?=20ProductSpuServiceImpl=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/optional/mall/mall.sql | 2 +- .../enums/spu/ProductSpuStatusEnum.java | 4 +- .../dal/dataobject/sku/ProductSkuDO.java | 1 + .../service/spu/ProductSpuServiceImpl.java | 40 +- .../spu/ProductSpuServiceImplTest.java | 350 ++++++++++++------ .../src/test/resources/sql/clean.sql | 4 +- .../src/test/resources/sql/create_tables.sql | 82 ++-- 7 files changed, 318 insertions(+), 165 deletions(-) diff --git a/sql/optional/mall/mall.sql b/sql/optional/mall/mall.sql index 486b6f2fc..757993400 100644 --- a/sql/optional/mall/mall.sql +++ b/sql/optional/mall/mall.sql @@ -248,7 +248,7 @@ DROP TABLE IF EXISTS `product_spu`; CREATE TABLE `product_spu` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号', - `brand_id` int DEFAULT NULL COMMENT '商品品牌编号', + `brand_id` bigint DEFAULT NULL COMMENT '商品品牌编号', `category_id` bigint NOT NULL COMMENT '分类id', `spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格', `code` varchar(128) DEFAULT NULL COMMENT '商品编码', diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java index 1757f1e49..6b7f03ac2 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java @@ -19,12 +19,12 @@ public enum ProductSpuStatusEnum implements IntArrayValuable { DISABLE(0, "下架"), ENABLE(1, "上架"),; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuStatusEnum::getStyle).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuStatusEnum::getStatus).toArray(); /** * 状态 */ - private final Integer style; + private final Integer status; /** * 状态名 */ diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java index fc7bbe9ec..25b91525c 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java @@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO { * 商品属性 */ @Data + @AllArgsConstructor public static class Property { /** diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 9b714fef7..6cdebdee4 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -28,7 +28,10 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -44,7 +47,7 @@ import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_E public class ProductSpuServiceImpl implements ProductSpuService { @Resource - private ProductSpuMapper ProductSpuMapper; + private ProductSpuMapper productSpuMapper; @Resource private ProductCategoryService categoryService; @@ -77,7 +80,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { spu.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); spu.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); - ProductSpuMapper.insert(spu); + productSpuMapper.insert(spu); // 插入 SKU productSkuService.createSkus(spu.getId(), skuCreateReqList); // 返回 @@ -95,7 +98,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { brandService.validateProductBrand(updateReqVO.getBrandId()); // 校验SKU List skuCreateReqList = updateReqVO.getSkus(); - // 多规格才需校验 productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType()); // 更新 SPU @@ -104,7 +106,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { updateObj.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); updateObj.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); - ProductSpuMapper.updateById(updateObj); + productSpuMapper.updateById(updateObj); // 批量更新 SKU productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus()); } @@ -115,13 +117,13 @@ public class ProductSpuServiceImpl implements ProductSpuService { // 校验存在 validateSpuExists(id); // 删除 SPU - ProductSpuMapper.deleteById(id); + productSpuMapper.deleteById(id); // 删除关联的 SKU productSkuService.deleteSkuBySpuId(id); } private void validateSpuExists(Long id) { - if (ProductSpuMapper.selectById(id) == null) { + if (productSpuMapper.selectById(id) == null) { throw exception(SPU_NOT_EXISTS); } } @@ -129,7 +131,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { @Override // TODO @芋艿:需要再 review 下 public ProductSpuDetailRespVO getSpuDetail(Long id) { - ProductSpuDO spu = ProductSpuMapper.selectById(id); + ProductSpuDO spu = productSpuMapper.selectById(id); ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class); if (null != spu) { List skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id)); @@ -162,19 +164,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { }); respVO.setProductPropertyViews(productPropertyViews); } - // 组合分类 -// if (null != respVO.getCategoryId()) { -// LinkedList categoryArray = new LinkedList<>(); -// Long parentId = respVO.getCategoryId(); -// categoryArray.addFirst(parentId); -// while (parentId != 0) { -// parentId = categoryService.getCategory(parentId).getParentId(); -// if (parentId > 0) { -// categoryArray.addFirst(parentId); -// } -// } -// -// } respVO.setCategoryIds(respVO.getCategoryId()); } return respVO; @@ -182,12 +171,12 @@ public class ProductSpuServiceImpl implements ProductSpuService { @Override public ProductSpuRespVO getSpu(Long id) { - return ProductSpuConvert.INSTANCE.convert(ProductSpuMapper.selectById(id)); + return ProductSpuConvert.INSTANCE.convert(productSpuMapper.selectById(id)); } @Override public List getSpuList(Collection ids) { - return ProductSpuMapper.selectBatchIds(ids); + return productSpuMapper.selectBatchIds(ids); } @Override @@ -199,13 +188,14 @@ public class ProductSpuServiceImpl implements ProductSpuService { remindSpuIds.add(null); } } - return ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO, remindSpuIds)); + return ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(pageReqVO, remindSpuIds)); } @Override public PageResult getSpuPage(AppSpuPageReqVO pageReqVO) { - PageResult productSpuDOPageResult = ProductSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO)); + PageResult productSpuDOPageResult = productSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO)); PageResult pageResult = new PageResult<>(); + // TODO @芋艿 这里用convert如何解决 List collect = productSpuDOPageResult.getList() .stream() .map(ProductSpuConvert.INSTANCE::convertAppResp) diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java index bb0fa9d32..899138f72 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java +++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java @@ -1,163 +1,301 @@ package cn.iocoder.yudao.module.product.service.spu; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -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.property.vo.property.ProductPropertyRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; +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.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 org.junit.jupiter.api.Disabled; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.product.service.brand.ProductBrandServiceImpl; +import cn.iocoder.yudao.module.product.service.category.ProductCategoryServiceImpl; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuServiceImpl; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; -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.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; -import static org.junit.jupiter.api.Assertions.*; /** -* {@link ProductSpuServiceImpl} 的单元测试类 -* -* @author 芋道源码 -*/ + * {@link ProductSpuServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ @Import(ProductSpuServiceImpl.class) public class ProductSpuServiceImplTest extends BaseDbUnitTest { @Resource - private ProductSpuServiceImpl spuService; + private ProductSpuServiceImpl productSpuService; @Resource - private ProductSpuMapper ProductSpuMapper; + private ProductSpuMapper productSpuMapper; + + + @MockBean + private ProductSkuServiceImpl productSkuService; + + @MockBean + private ProductCategoryServiceImpl categoryService; + + @MockBean + private ProductBrandServiceImpl brandService; + + @MockBean + private ProductPropertyService productPropertyService; + + @MockBean + private ProductPropertyValueService productPropertyValueService; + @Test public void testCreateSpu_success() { // 准备参数 - ProductSpuCreateReqVO reqVO = randomPojo(ProductSpuCreateReqVO.class); + ProductSpuCreateReqVO createReqVO = randomPojo(ProductSpuCreateReqVO.class, o -> { + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType()); + o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); + }); + + // 校验SKU + List skuCreateReqList = createReqVO.getSkus(); + + Long spu = productSpuService.createSpu(createReqVO); + ProductSpuDO productSpuDO = productSpuMapper.selectById(spu); + + createReqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice)); + 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); - // 调用 - Long spuId = spuService.createSpu(reqVO); - // 断言 - assertNotNull(spuId); - // 校验记录的属性是否正确 - ProductSpuDO spu = ProductSpuMapper.selectById(spuId); - assertPojoEquals(reqVO, spu); } @Test public void testUpdateSpu_success() { - // mock 数据 - ProductSpuDO dbSpu = randomPojo(ProductSpuDO.class); - ProductSpuMapper.insert(dbSpu);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class); + productSpuMapper.insert(createReqVO); // 准备参数 ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> { - o.setId(dbSpu.getId()); // 设置更新的 ID + o.setId(createReqVO.getId()); // 设置更新的 ID + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType()); + o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus()); }); - // 调用 - spuService.updateSpu(reqVO); + productSpuService.updateSpu(reqVO); + + List skuCreateReqList = reqVO.getSkus(); + reqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice)); + 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()); // 获取最新的 + ProductSpuDO spu = productSpuMapper.selectById(reqVO.getId()); // 获取最新的 assertPojoEquals(reqVO, spu); } @Test - public void testUpdateSpu_notExists() { - // 准备参数 - ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> spuService.updateSpu(reqVO), SPU_NOT_EXISTS); + public void testValidateSpuExists_exception() { + ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> { + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType()); + o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus()); + }); + // 调用 + Assertions.assertThrows(ServiceException.class, () -> productSpuService.updateSpu(reqVO)); } @Test - public void testDeleteSpu_success() { - // mock 数据 - ProductSpuDO dbSpu = randomPojo(ProductSpuDO.class); - ProductSpuMapper.insert(dbSpu);// @Sql: 先插入出一条存在的数据 + void deleteSpu() { // 准备参数 - Long id = dbSpu.getId(); + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class); + productSpuMapper.insert(createReqVO); // 调用 - spuService.deleteSpu(id); - // 校验数据不存在了 - assertNull(ProductSpuMapper.selectById(id)); + productSpuService.deleteSpu(createReqVO.getId()); + + Assertions.assertNull(productSpuMapper.selectById(createReqVO.getId())); } @Test - public void testDeleteSpu_notExists() { + void getSpuDetail() { + // 准备spu参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o -> { + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType()); + }); + productSpuMapper.insert(createReqVO); + + // 创建两个属性 + ArrayList productPropertyRespVOS = Lists.newArrayList( + randomPojo(ProductPropertyRespVO.class), + randomPojo(ProductPropertyRespVO.class)); + + // 所有属性值 + ArrayList productPropertyValueRespVO = new ArrayList<>(); + + // 每个属性创建属性值 + productPropertyRespVOS.forEach(v -> { + ProductPropertyValueRespVO productPropertyValueRespVO1 = randomPojo(ProductPropertyValueRespVO.class, o -> o.setPropertyId(v.getId())); + productPropertyValueRespVO.add(productPropertyValueRespVO1); + }); + + // 属性值建立笛卡尔积 + Map> collect = productPropertyValueRespVO.stream().collect(Collectors.groupingBy(ProductPropertyValueRespVO::getPropertyId)); + List> lists = cartesianProduct(Lists.newArrayList(collect.values())); + + // 准备sku参数 + ArrayList productSkuDOS = Lists.newArrayList(); + lists.forEach(pp -> { + List property = pp.stream().map(ppv -> new ProductSkuDO.Property(ppv.getPropertyId(), ppv.getId())).collect(Collectors.toList()); + ProductSkuDO productSkuDO = randomPojo(ProductSkuDO.class, o -> { + o.setProperties(property); + }); + productSkuDOS.add(productSkuDO); + + }); + + Mockito.when(productSkuService.getSkusBySpuId(createReqVO.getId())).thenReturn(productSkuDOS); + Mockito.when(productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyValueRespVO); + Mockito.when(productPropertyService.getPropertyList(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyRespVOS); + + // 调用 + ProductSpuDetailRespVO spuDetail = productSpuService.getSpuDetail(createReqVO.getId()); + + assertPojoEquals(createReqVO, spuDetail); + } + + @Test + void getSpu() { // 准备参数 - Long id = 1L; + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class); + productSpuMapper.insert(createReqVO); - // 调用, 并断言异常 - assertServiceException(() -> spuService.deleteSpu(id), SPU_NOT_EXISTS); + ProductSpuRespVO spu = productSpuService.getSpu(createReqVO.getId()); + assertPojoEquals(createReqVO, spu); } @Test - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 - public void testGetSpuPage() { - // mock 数据 - ProductSpuDO dbSpu = randomPojo(ProductSpuDO.class, o -> { // 等会查询到 - o.setName(null); - o.setSellPoint(null); - o.setDescription(null); - o.setCategoryId(null); - o.setPicUrls(null); - o.setSort(null); -// o.setLikeCount(null); -// o.setPrice(null); -// o.setQuantity(null); - o.setStatus(null); - o.setCreateTime(null); - }); - ProductSpuMapper.insert(dbSpu); - // 测试 name 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setName(null))); - // 测试 sellPoint 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setSellPoint(null))); - // 测试 description 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setDescription(null))); - // 测试 categoryId 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setCategoryId(null))); - // 测试 picUrls 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setPicUrls(null))); - // 测试 sort 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setSort(null))); - // 测试 likeCount 不匹配 -// ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setLikeCount(null))); - // 测试 price 不匹配 -// ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setPrice(null))); - // 测试 quantity 不匹配 -// ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setQuantity(null))); - // 测试 status 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setStatus(null))); - // 测试 createTime 不匹配 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setCreateTime(null))); - // 准备参数 - ProductSpuPageReqVO reqVO = new ProductSpuPageReqVO(); - reqVO.setName(null); - reqVO.setSellPoint(null); - reqVO.setDescription(null); - reqVO.setCategoryId(null); - reqVO.setPicUrls(null); - reqVO.setSort(null); - reqVO.setLikeCount(null); - reqVO.setPrice(null); - reqVO.setQuantity(null); - reqVO.setStatus(null); - reqVO.setCreateTime(null); + void getSpuList() { + // 准备参数 + ArrayList createReqVO = Lists.newArrayList(randomPojo(ProductSpuDO.class), randomPojo(ProductSpuDO.class)); + productSpuMapper.insertBatch(createReqVO); - // 调用 - PageResult pageResult = spuService.getSpuPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbSpu, pageResult.getList().get(0)); + // 调用 + List spuList = productSpuService.getSpuList(createReqVO.stream().map(ProductSpuDO::getId).collect(Collectors.toList())); + Assertions.assertIterableEquals(createReqVO, spuList); + } + + @Test + void getSpuPage() { + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class); + productSpuMapper.insert(createReqVO); + + ArrayList remindSpuIds = Lists.newArrayList( +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())), +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())) + ); + + Mockito.when(productSkuService.getRemindSpuIds()).thenReturn(remindSpuIds); + + // 调用 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); + productSpuPageReqVO.setTabStatus(2); + + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + + ArrayList resultRemindSpuIds = new ArrayList<>(); + resultRemindSpuIds.add(null); + PageResult result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, resultRemindSpuIds)); + Assertions.assertIterableEquals(result.getList(), spuPage.getList()); + Assertions.assertEquals(spuPage.getTotal(), result.getTotal()); + } + + @Test + void testGetSpuPage() { +// 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o -> { + o.setCategoryId(2L); + }); + productSpuMapper.insert(createReqVO); + + ArrayList remindSpuIds = Lists.newArrayList( +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())), +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())) + ); + + Mockito.when(productSkuService.getRemindSpuIds()).thenReturn(remindSpuIds); + + // 调用 + AppSpuPageReqVO appSpuPageReqVO = new AppSpuPageReqVO(); + appSpuPageReqVO.setCategoryId(2L); + + PageResult spuPage = productSpuService.getSpuPage(appSpuPageReqVO); + + PageResult result = productSpuMapper.selectPage( + ProductSpuConvert.INSTANCE.convert(appSpuPageReqVO)); + + List collect = result.getList() + .stream() + .map(ProductSpuConvert.INSTANCE::convertAppResp) + .collect(Collectors.toList()); + + Assertions.assertIterableEquals(collect, spuPage.getList()); + Assertions.assertEquals(spuPage.getTotal(), result.getTotal()); + } + + + /** + * 生成笛卡尔积 + * + * @param data 数据 + * @return 笛卡尔积 + */ + public static List> cartesianProduct(List> data) { + List> res = null; // 结果集(当前为第N个List,则该处存放的就为前N-1个List的笛卡尔积集合) + for (List list : data) { // 遍历数据 + List> temp = new ArrayList<>(); // 临时结果集,存放本次循环后生成的笛卡尔积集合 + if (res == null) { // 结果集为null表示第一次循环既list为第一个List + for (T t : list) { // 便利第一个List + // 利用stream生成List,第一个List的笛卡尔积集合约等于自己本身(需要创建一个List并把对象添加到当中),存放到临时结果集 + temp.add(Stream.of(t).collect(Collectors.toList())); + } + res = temp; // 将临时结果集赋值给结果集 + continue; // 跳过本次循环 + } + // 不为第一个List,计算前面的集合(笛卡尔积)和当前List的笛卡尔积集合 + for (T t : list) { // 便利 + for (List rl : res) { // 便利前面的笛卡尔积集合 + // 利用stream生成List + temp.add(Stream.concat(rl.stream(), Stream.of(t)).collect(Collectors.toList())); + } + } + res = temp; // 将临时结果集赋值给结果集 + } + // 返回结果 + return res; } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql b/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql index d9a04afed..aad191337 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql @@ -1,3 +1,3 @@ -DELETE FROM "product_category"; +DELETE FROM "product_sku"; -DELETE FROM "product_brand"; \ No newline at end of file +DELETE FROM "product_spu"; \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql index 37fc0ff21..828f8e745 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql @@ -1,30 +1,54 @@ -CREATE TABLE IF NOT EXISTS "product_category" ( - "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "parent_id" bigint(20) NOT NULL, - "name" varchar(255) NOT NULL, - "pic_url" varchar(255) NOT NULL, - "sort" int(11) NOT NULL, - "description" varchar(1024) NOT NULL, - "status" tinyint(4) NOT NULL, - "creator" varchar(64) DEFAULT '', - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updater" varchar(64) DEFAULT '', - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - "deleted" bit NOT NULL DEFAULT FALSE, - PRIMARY KEY ("id") -) COMMENT '商品分类'; +CREATE TABLE IF NOT EXISTS `product_sku` ( +`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', +`spu_id` bigint NOT NULL COMMENT 'spu编号', +`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号', +`name` varchar(128) DEFAULT NULL COMMENT '商品 SKU 名字', +`properties` varchar(128) DEFAULT NULL COMMENT '规格值数组-json格式, [{propertId: , valueId: }, {propertId: , valueId: }]', +`price` int NOT NULL DEFAULT '-1' COMMENT '销售价格,单位:分', +`market_price` int DEFAULT NULL COMMENT '市场价', +`cost_price` int NOT NULL DEFAULT '-1' COMMENT '成本价,单位: 分', +`pic_url` varchar(128) NOT NULL COMMENT '图片地址', +`stock` int DEFAULT NULL COMMENT '库存', +`warn_stock` int DEFAULT NULL COMMENT '预警库存', +`volume` double DEFAULT NULL COMMENT '商品体积', +`weight` double DEFAULT NULL COMMENT '商品重量', +`bar_code` varchar(64) DEFAULT NULL COMMENT '条形码', +`status` tinyint DEFAULT NULL COMMENT '状态: 0-正常 1-禁用', +`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', +`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', +`creator` varchar(64) DEFAULT NULL COMMENT '创建人', +`updater` double DEFAULT NULL COMMENT '更新人', +`deleted` bit(1) NOT NULL DEFAULT 0 COMMENT '是否删除', +PRIMARY KEY (`id`) +) COMMENT '商品sku'; -CREATE TABLE IF NOT EXISTS "product_brand" ( - "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "name" varchar(255) NOT NULL, - "pic_url" varchar(255) NOT NULL, - "sort" int(11), - "description" varchar(1024), - "status" tinyint(4) NOT NULL, - "creator" varchar(64) DEFAULT '', - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updater" varchar(64) DEFAULT '', - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - "deleted" bit NOT NULL DEFAULT FALSE, - PRIMARY KEY ("id") -) COMMENT '商品品牌'; + +CREATE TABLE IF NOT EXISTS `product_spu` ( +`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', +`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号', +`brand_id` bigint DEFAULT NULL COMMENT '商品品牌编号', +`category_id` bigint NOT NULL COMMENT '分类id', +`spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格', +`code` varchar(128) DEFAULT NULL COMMENT '商品编码', +`name` varchar(128) NOT NULL COMMENT '商品名称', +`sell_point` varchar(128) DEFAULT NULL COMMENT '卖点', +`description` text COMMENT '描述', +`pic_urls` varchar(1024) DEFAULT '' COMMENT '商品轮播图地址数组,以逗号分隔最多上传15张', +`video_url` varchar(128) DEFAULT NULL COMMENT '商品视频', +`market_price` int DEFAULT NULL COMMENT '市场价,单位使用:分', +`min_price` int DEFAULT NULL COMMENT '最小价格,单位使用:分', +`max_price` int DEFAULT NULL COMMENT '最大价格,单位使用:分', +`total_stock` int NOT NULL DEFAULT '0' COMMENT '总库存', +`show_stock` int DEFAULT '0' COMMENT '是否展示库存', +`sales_count` int DEFAULT '0' COMMENT '商品销量', +`virtual_sales_count` int DEFAULT '0' COMMENT '虚拟销量', +`click_count` int DEFAULT '0' COMMENT '商品点击量', +`status` bit(1) DEFAULT NULL COMMENT '上下架状态: 0 上架(开启) 1 下架(禁用)-1 回收', +`sort` int NOT NULL DEFAULT '0' COMMENT '排序字段', +`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', +`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', +`creator` varchar(64) DEFAULT NULL COMMENT '创建人', +`updater` varchar(64) DEFAULT NULL COMMENT '更新人', +`deleted` bit(1) NOT NULL DEFAULT 0 COMMENT '是否删除', +PRIMARY KEY (`id`) +) COMMENT '商品spu';