diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueUpdateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueUpdateReqVO.java index 4a1bc5778..2437600a8 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueUpdateReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueUpdateReqVO.java @@ -12,6 +12,6 @@ public class ProductPropertyValueUpdateReqVO extends ProductPropertyValueBaseVO @ApiModelProperty(value = "主键", required = true, example = "1024") @NotNull(message = "主键不能为空") - private Integer id; + private Long id; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java index d7c43b90f..bba1ba058 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java @@ -55,9 +55,8 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO { } - // TODO @luowenfeng: categoryIds => categoryId,example 也要改下哈 - @ApiModelProperty(value = "分类 id 数组,一直递归到一级父节点", example = "[1,2,4]") - private Long categoryIds; + @ApiModelProperty(value = "分类 id 数组,一直递归到一级父节点", example = "4") + private Long categoryId; // TODO @芋艿:在瞅瞅~ @ApiModelProperty(value = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]") diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java index 697beb22d..890df3477 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java @@ -25,10 +25,9 @@ public interface ProductPropertyMapper extends BaseMapperX { .orderByDesc(ProductPropertyDO::getId)); } - // TODO @luowenfeng: selectByNameLike,这样更清晰哈。 default ProductPropertyDO selectByName(String name) { return selectOne(new LambdaQueryWrapperX() - .likeIfPresent(ProductPropertyDO::getName, name)); + .eqIfPresent(ProductPropertyDO::getName, name)); } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java index 4853afeae..ca9bafab2 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java @@ -17,8 +17,7 @@ import java.util.List; @Mapper public interface ProductPropertyValueMapper extends BaseMapperX { - // TODO @luowenfeng: selectListByPropertyId 是不是就可以啦 - default List selectListByPropertyValueListByPropertyId(List propertyIds) { + default List selectListByPropertyId(List propertyIds) { return selectList(new LambdaQueryWrapperX() .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds)); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java index 17e38fc98..74e370f9c 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java @@ -19,6 +19,7 @@ import javax.annotation.Resource; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_EXISTS; @@ -58,8 +59,8 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { public void updateProperty(ProductPropertyUpdateReqVO updateReqVO) { // 校验存在 this.validatePropertyExists(updateReqVO.getId()); - // TODO @luowenfeng:如果是自己的情况下,名字相同也是 ok 的呀~ - if (productPropertyMapper.selectByName(updateReqVO.getName()) != null) { + ProductPropertyDO productPropertyDO = productPropertyMapper.selectByName(updateReqVO.getName()); + if (productPropertyDO != null && !productPropertyDO.getId().equals(updateReqVO.getId())) { throw exception(PROPERTY_EXISTS); } // 更新 @@ -97,10 +98,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { return ProductPropertyConvert.INSTANCE.convertPage(pageResult); } - private List getPropertyValueListByPropertyId(List propertyIds) { - return productPropertyValueMapper.selectListByPropertyValueListByPropertyId(propertyIds); - } - @Override public ProductPropertyRespVO getProperty(Long id) { ProductPropertyDO property = productPropertyMapper.selectById(id); @@ -117,7 +114,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { List propertyList = getPropertyList(listReqVO); // 查询属性值 - List valueDOList = productPropertyValueMapper.selectListByPropertyValueListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId)); + List valueDOList = productPropertyValueMapper.selectListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId)); Map> valueDOMap = CollectionUtils.convertMultiMap(valueDOList, ProductPropertyValueDO::getPropertyId); return CollectionUtils.convertList(propertyList, m -> { ProductPropertyAndValueRespVO productPropertyAndValueRespVO = ProductPropertyConvert.INSTANCE.convert(m); diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java index 551fb00e3..5addb37e8 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java @@ -14,6 +14,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.util.List; +import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS; @@ -42,8 +43,8 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ @Override public void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO) { - // TODO @luowenfeng:如果是自己的情况下,名字相同也是 ok 的呀~ - if (productPropertyValueMapper.selectByName(updateReqVO.getPropertyId(), updateReqVO.getName()) != null) { + ProductPropertyValueDO productPropertyValueDO = productPropertyValueMapper.selectByName(updateReqVO.getPropertyId(), updateReqVO.getName()); + if (productPropertyValueDO != null && !productPropertyValueDO.getId().equals(updateReqVO.getId())) { throw exception(PROPERTY_VALUE_EXISTS); } ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO); 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 dafa26428..2e6e4b174 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 @@ -162,7 +162,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { }); respVO.setProductPropertyViews(productPropertyViews); } - respVO.setCategoryIds(respVO.getCategoryId()); } return respVO; } 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 8f76cf7b2..cf4c14649 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,8 +1,11 @@ package cn.iocoder.yudao.module.product.service.spu; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; 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.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; @@ -33,10 +36,12 @@ import java.util.*; 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.RandomUtils.randomPojo; // TODO @芋艿:review 下单元测试 + /** * {@link ProductSpuServiceImpl} 的单元测试类 * @@ -67,6 +72,13 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { @MockBean private ProductPropertyValueService productPropertyValueService; + public String generateNo() { + return DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999); + } + + public Long generateId() { + return RandomUtil.randomLong(100000, 999999); + } @Test public void testCreateSpu_success() { @@ -206,34 +218,119 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { Assertions.assertIterableEquals(createReqVO, spuList); } - // TODO @luowenfeng:单测要分情况;类似你这个,可以分 2 个单测;一个是有预存预警的;一个是没库存预警的; - // 然后,参考其它模块的 getPage 类型的方法的单测。 @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); - + void getSpuPage_alarmStock_empty() { // 调用 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); -// productSpuPageReqVO.setTabStatus(2); + productSpuPageReqVO.setAlarmStock(true); PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); - Set resultRemindSpuIds = new HashSet<>(); - resultRemindSpuIds.add(null); - PageResult result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, resultRemindSpuIds)); + PageResult result = PageResult.empty(); Assertions.assertIterableEquals(result.getList(), spuPage.getList()); Assertions.assertEquals(spuPage.getTotal(), result.getTotal()); } + @Test + void getSpuPage_alarmStock() { + // mock 数据 + Long brandId = generateId(); + Long categoryId = generateId(); + String code = generateNo(); + + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o->{ + o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); + o.setTotalStock(500); + o.setMinPrice(1); + o.setMaxPrice(50); + o.setMarketPrice(25); + o.setSpecType(ProductSpuSpecTypeEnum.RECYCLE.getType()); + o.setBrandId(brandId); + o.setCategoryId(categoryId); + o.setClickCount(100); + o.setCode(code); + o.setDescription("测试商品"); + o.setPicUrls(new ArrayList<>()); + o.setName("测试"); + o.setSalesCount(100); + o.setSellPoint("超级加倍"); + o.setShowStock(true); + o.setVideoUrl(""); + }); + productSpuMapper.insert(createReqVO); + + Set alarmStockSpuIds = SetUtils.asSet(createReqVO.getId()); + + List productSpuDOS = Arrays.asList(randomPojo(ProductSkuDO.class, o -> { + o.setSpuId(createReqVO.getId()); + }), randomPojo(ProductSkuDO.class, o -> { + o.setSpuId(createReqVO.getId()); + })); + + Mockito.when(productSkuService.getSkusByAlarmStock()).thenReturn(productSpuDOS); + + // 调用 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); + productSpuPageReqVO.setAlarmStock(true); + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + + PageResult result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds)); + Assertions.assertIterableEquals(result.getList(), spuPage.getList()); + Assertions.assertEquals(spuPage.getTotal(), result.getTotal()); + } + + @Test + void getSpuPage() { + // mock 数据 + Long brandId = generateId(); + Long categoryId = generateId(); + + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o->{ + o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); + o.setTotalStock(1); + o.setMinPrice(1); + o.setMaxPrice(1); + o.setMarketPrice(1); + o.setSpecType(ProductSpuSpecTypeEnum.RECYCLE.getType()); + o.setBrandId(brandId); + o.setCategoryId(categoryId); + o.setClickCount(1); + o.setCode(generateNo()); + o.setDescription("测试商品"); + o.setPicUrls(new ArrayList<>()); + o.setName("测试"); + o.setSalesCount(1); + o.setSellPoint("卖点"); + o.setShowStock(true); + }); + + // 准备参数 + productSpuMapper.insert(createReqVO); + // 测试 status 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus()))); + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setStatus(ProductSpuStatusEnum.RECYCLE.getStatus()))); + // 测试 SpecType 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType()))); + // 测试 BrandId 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setBrandId(generateId()))); + // 测试 CategoryId 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setCategoryId(generateId()))); + + // 调用 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); + productSpuPageReqVO.setAlarmStock(false); + productSpuPageReqVO.setBrandId(brandId); + productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); + productSpuPageReqVO.setCategoryId(categoryId); + + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + + PageResult result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set) null)); + Assertions.assertEquals(result, spuPage); + } + @Test void testGetSpuPage() { // 准备参数 @@ -242,13 +339,6 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { }); 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); diff --git a/yudao-ui-admin/src/router/index.js b/yudao-ui-admin/src/router/index.js index fb38ce0e6..396470587 100644 --- a/yudao-ui-admin/src/router/index.js +++ b/yudao-ui-admin/src/router/index.js @@ -196,6 +196,21 @@ export const constantRoutes = [ meta: {title: '流程详情', activeMenu: '/bpm/task/my'} } ] + }, + { + path: '/order', + component: Layout, + name: '订单管理', + meta: { title: '订单管理' }, + alwaysShow: true, + children: [ + { + path: '/order/goods-order', + name: '商品订单', + meta: { title: '商品订单' }, + component: (resolve) => require(['@/views/order/goodsOrder'], resolve) + } + ] } ] diff --git a/yudao-ui-admin/src/views/mall/product/spu/save.vue b/yudao-ui-admin/src/views/mall/product/spu/save.vue index a819fe144..ca344bf8c 100644 --- a/yudao-ui-admin/src/views/mall/product/spu/save.vue +++ b/yudao-ui-admin/src/views/mall/product/spu/save.vue @@ -453,7 +453,7 @@ export default { this.baseForm.id = data.id; this.baseForm.name = data.name; this.baseForm.sellPoint = data.sellPoint; - this.baseForm.categoryIds = data.categoryIds; + this.baseForm.categoryIds = data.categoryId; this.baseForm.videoUrl = data.videoUrl; this.baseForm.sort = data.sort; this.baseForm.description = data.description; diff --git a/yudao-ui-admin/src/views/order/goodsOrder/index.vue b/yudao-ui-admin/src/views/order/goodsOrder/index.vue new file mode 100644 index 000000000..aa10e6a76 --- /dev/null +++ b/yudao-ui-admin/src/views/order/goodsOrder/index.vue @@ -0,0 +1,458 @@ + + + + +