ids);
+
}
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
similarity index 81%
rename from yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java
rename to yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
index 6d0206b7da..45d42f41be 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
@@ -1,18 +1,21 @@
package cn.iocoder.yudao.module.product.api.spu.dto;
-import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import lombok.Data;
import java.util.List;
+// TODO @LeeYan9: ProductSpuRespDTO
/**
+ * 商品 SPU 信息 Response DTO
+ *
* @author LeeYan9
* @since 2022-08-26
*/
@Data
-public class SpuInfoRespDTO {
+public class ProductSpuRespDTO {
/**
* 商品 SPU 编号,自增
@@ -30,7 +33,7 @@ public class SpuInfoRespDTO {
*/
private String code;
/**
- * 商品卖点
+ * 促销语
*/
private String sellPoint;
/**
@@ -80,25 +83,25 @@ public class SpuInfoRespDTO {
/**
* 最小价格,单位使用:分
*
- * 基于其对应的 {@link SkuInfoRespDTO#getPrice()} 最小值
+ * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最小值
*/
private Integer minPrice;
/**
* 最大价格,单位使用:分
*
- * 基于其对应的 {@link SkuInfoRespDTO#getPrice()} 最大值
+ * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最大值
*/
private Integer maxPrice;
/**
* 市场价,单位使用:分
*
- * 基于其对应的 {@link SkuInfoRespDTO#getMarketPrice()} 最大值
+ * 基于其对应的 {@link ProductSkuRespDTO#getMarketPrice()} 最大值
*/
private Integer marketPrice;
/**
* 总库存
*
- * 基于其对应的 {@link SkuInfoRespDTO#getStock()} 求和
+ * 基于其对应的 {@link ProductSkuRespDTO#getStock()} 求和
*/
private Integer totalStock;
/**
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
index 801e2dd513..86875b119a 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
@@ -24,9 +24,11 @@ public interface ErrorCodeConstants {
// ========== 商品规格名称 1008003000 ==========
ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1008003000, "规格名称不存在");
+ ErrorCode PROPERTY_EXISTS = new ErrorCode(1008003001, "规格名称已存在");
// ========== 规格值 1008004000 ==========
ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1008004000, "规格值不存在");
+ ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1008004001, "规格值已存在");
// ========== 商品 SPU 1008005000 ==========
ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在");
@@ -36,5 +38,6 @@ public interface ErrorCodeConstants {
ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复");
ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其规格数必须一致");
ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复");
+ ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足");
}
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 1757f1e499..6b7f03ac2a 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/api/sku/ProductSkuApiImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
index 22636826bc..89913c70ed 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
@@ -1,26 +1,49 @@
package cn.iocoder.yudao.module.product.api.sku;
-import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
-import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO;
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
+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.service.sku.ProductSkuService;
import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+import javax.annotation.Resource;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
- * todo 注释
+ * TODO LeeYan9: 类注释;
+ * @author LeeYan9
+ * @since 2022-09-06
*/
@Service
+@Validated
public class ProductSkuApiImpl implements ProductSkuApi {
+ @Resource
+ private ProductSkuService productSkuService;
+
@Override
- public List getSkusByIds(Collection skuIds) {
+ public ProductSkuRespDTO getSku(Long id) {
+ // TODO TODO LeeYan9: 需要实现
return null;
}
@Override
- public void decrementStockBatch(SkuDecrementStockBatchReqDTO batchReqDTO) {
+ public List getSkuList(Collection ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return Collections.emptyList();
+ }
+ List skus = productSkuService.getSkuList(ids);
+ return ProductSkuConvert.INSTANCE.convertList04(skus);
+ }
+ @Override
+ public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) {
+ productSkuService.updateSkuStock(updateStockReqDTO);
}
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
index 8f651f3955..4d880e662f 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
@@ -1,20 +1,38 @@
package cn.iocoder.yudao.module.product.api.spu;
-import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
+import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
+import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+import javax.annotation.Resource;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
- * todo 注释
+ * TODO LeeYan9: 类注释;
+ *
+ * @author LeeYan9
+ * @since 2022-09-06
*/
@Service
+@Validated
public class ProductSpuApiImpl implements ProductSpuApi {
- @Override
- public List getSpusByIds(Collection spuIds) {
- return null;
- }
+ @Resource
+ private ProductSpuMapper productSpuMapper;
+ @Override
+ public List getSpuList(Collection spuIds) {
+ // TODO TODO LeeYan9: AllEmpty?
+ if (CollectionUtils.isAnyEmpty(spuIds)) {
+ return Collections.emptyList();
+ }
+ List productSpuDOList = productSpuMapper.selectBatchIds(spuIds);
+ return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList);
+ }
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandPageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandPageReqVO.java
index 3b3d829de6..c5a7b0047a 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandPageReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandPageReqVO.java
@@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
-import java.util.Date;
+import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@@ -26,6 +26,6 @@ public class ProductBrandPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "创建时间")
- private Date[] createTime;
+ private LocalDateTime[] createTime;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandRespVO.java
index f577a6c26f..fb4ce09546 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandRespVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandRespVO.java
@@ -6,7 +6,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
-import java.util.Date;
+import java.time.LocalDateTime;
@ApiModel("管理后台 - 品牌 Response VO")
@Data
@@ -18,6 +18,6 @@ public class ProductBrandRespVO extends ProductBrandBaseVO {
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
- private Date createTime;
+ private LocalDateTime createTime;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryRespVO.java
index 9c3d1b458a..c6fdfcfe1b 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryRespVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryRespVO.java
@@ -1,7 +1,8 @@
package cn.iocoder.yudao.module.product.controller.admin.category.vo;
import lombok.*;
-import java.util.*;
+
+import java.time.LocalDateTime;
import io.swagger.annotations.*;
@ApiModel("管理后台 - 商品分类 Response VO")
@@ -14,6 +15,6 @@ public class ProductCategoryRespVO extends ProductCategoryBaseVO {
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
- private Date createTime;
+ private LocalDateTime createTime;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
index 7401ec7442..9a4c20c58c 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
@@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.product.controller.admin.property;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*;
import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@@ -17,6 +14,8 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
+import java.util.List;
+
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 规格名称")
@@ -56,15 +55,29 @@ public class ProductPropertyController {
@ApiOperation("获得规格名称")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('product:property:query')")
- public CommonResult getProperty(@RequestParam("id") Long id) {
- return success(productPropertyService.getPropertyResp(id));
+ public CommonResult getProperty(@RequestParam("id") Long id) {
+ return success(productPropertyService.getProperty(id));
+ }
+
+ @GetMapping("/list")
+ @ApiOperation("获得规格名称列表")
+ @PreAuthorize("@ss.hasPermission('product:property:query')")
+ public CommonResult> getPropertyList(@Valid ProductPropertyListReqVO listReqVO) {
+ return success(productPropertyService.getPropertyList(listReqVO));
}
@GetMapping("/page")
@ApiOperation("获得规格名称分页")
@PreAuthorize("@ss.hasPermission('product:property:query')")
- public CommonResult> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
- return success(productPropertyService.getPropertyListPage(pageVO));
+ public CommonResult> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
+ return success(productPropertyService.getPropertyPage(pageVO));
+ }
+
+ @GetMapping("/listAndValue")
+ @ApiOperation("获得规格名称列表")
+ @PreAuthorize("@ss.hasPermission('product:property:query')")
+ public CommonResult> getPropertyAndValueList(@Valid ProductPropertyListReqVO listReqVO) {
+ return success(productPropertyService.getPropertyAndValueList(listReqVO));
}
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java
new file mode 100644
index 0000000000..e88c914150
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java
@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.module.product.controller.admin.property;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
+import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Api(tags = "管理后台 - 规格值名称")
+@RestController
+@RequestMapping("/product/property/value")
+@Validated
+public class ProductPropertyValueController {
+
+ @Resource
+ private ProductPropertyValueService productPropertyValueService;
+
+ @PostMapping("/create")
+ @ApiOperation("创建规格名称")
+ @PreAuthorize("@ss.hasPermission('product:property:create')")
+ public CommonResult createProperty(@Valid @RequestBody ProductPropertyValueCreateReqVO createReqVO) {
+ return success(productPropertyValueService.createPropertyValue(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @ApiOperation("更新规格名称")
+ @PreAuthorize("@ss.hasPermission('product:property:update')")
+ public CommonResult updateProperty(@Valid @RequestBody ProductPropertyValueUpdateReqVO updateReqVO) {
+ productPropertyValueService.updatePropertyValue(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @ApiOperation("删除规格名称")
+ @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
+ @PreAuthorize("@ss.hasPermission('product:property:delete')")
+ public CommonResult deleteProperty(@RequestParam("id") Long id) {
+ productPropertyValueService.deletePropertyValue(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @ApiOperation("获得规格名称")
+ @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+ @PreAuthorize("@ss.hasPermission('product:property:query')")
+ public CommonResult getProperty(@RequestParam("id") Long id) {
+ return success(productPropertyValueService.getPropertyValue(id));
+ }
+
+ @GetMapping("/page")
+ @ApiOperation("获得规格名称分页")
+ @PreAuthorize("@ss.hasPermission('product:property:query')")
+ public CommonResult> getPropertyValuePage(@Valid ProductPropertyValuePageReqVO pageVO) {
+ return success(productPropertyValueService.getPropertyValueListPage(pageVO));
+ }
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyAndValueRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyAndValueRespVO.java
index 7684d4ea77..e7b3c352f9 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyAndValueRespVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyAndValueRespVO.java
@@ -7,7 +7,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
-import java.util.Date;
+import java.time.LocalDateTime;
import java.util.List;
@ApiModel("管理后台 - 规格 + 规格值 Response VO")
@@ -20,7 +20,7 @@ public class ProductPropertyAndValueRespVO extends ProductPropertyBaseVO {
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
- private Date createTime;
+ private LocalDateTime createTime;
/**
* 规格值的集合
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java
index c900a727bc..25fc4c01ac 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java
@@ -3,21 +3,25 @@ package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
-import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
/**
-* 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用
-* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
-*/
+ * 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
@Data
public class ProductPropertyBaseVO {
@ApiModelProperty(value = "规格名称", required = true, example = "颜色")
- @NotEmpty(message = "规格名称不能为空")
+ @NotBlank(message = "规格名称不能为空")
private String name;
+ @ApiModelProperty(value = "备注", example = "颜色")
+ private String remark;
+
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
- @NotEmpty(message = "状态不能为空")
+ @NotNull(message = "状态不能为空")
private Integer status;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java
index c0e6b9da26..8dfd58a5d7 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java
@@ -1,11 +1,9 @@
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
-import lombok.*;
-import io.swagger.annotations.*;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
@ApiModel("管理后台 - 规格名称创建 Request VO")
@Data
@@ -13,9 +11,5 @@ import java.util.List;
@ToString(callSuper = true)
public class ProductPropertyCreateReqVO extends ProductPropertyBaseVO {
- // TODO @Luowenfeng:规格值的 CRUD 可以单独;前端 + 后端,改成类似字典类型、字典数据的这种交互;在加一个 ProductPropertyValueController
- @ApiModelProperty(value = "属性值")
- @NotNull(message = "属性值不能为空")
- List propertyValueList;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java
new file mode 100644
index 0000000000..314288ffb9
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.ToString;
+
+@ApiModel("管理后台 - 规格名称 List Request VO")
+@Data
+@ToString(callSuper = true)
+public class ProductPropertyListReqVO {
+
+ @ApiModelProperty(value = "规格名称", example = "颜色")
+ private String name;
+
+ @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
+ private Integer status;
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java
index 1902fb2053..05a67e874a 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java
@@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
-import java.util.Date;
+import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@@ -26,6 +26,6 @@ public class ProductPropertyPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "创建时间")
- private Date[] createTime;
+ private LocalDateTime[] createTime;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java
new file mode 100644
index 0000000000..75a9a5eea1
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@ApiModel("管理后台 - 规格 + 规格值 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ProductPropertyRespVO extends ProductPropertyBaseVO {
+
+ @ApiModelProperty(value = "规格的编号", required = true, example = "1024")
+ private Long id;
+
+ @ApiModelProperty(value = "创建时间", required = true)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java
index f4b9d695a1..f4630d8747 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java
@@ -16,8 +16,4 @@ public class ProductPropertyUpdateReqVO extends ProductPropertyBaseVO {
@NotNull(message = "主键不能为空")
private Long id;
- @ApiModelProperty(value = "属性值")
- @NotNull(message = "属性值不能为空")
- List propertyValueList;
-
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java
index 1e0708009c..142a8e6e22 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java
@@ -22,7 +22,10 @@ public class ProductPropertyValueBaseVO {
private String name;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
- @NotEmpty(message = "状态不能为空")
+ @NotNull(message = "状态不能为空")
private Integer status;
+ @ApiModelProperty(value = "备注", example = "颜色")
+ private String remark;
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java
new file mode 100644
index 0000000000..ae77d822b9
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.Date;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("管理后台 - 规格名称值分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ProductPropertyValuePageReqVO extends PageParam {
+
+ @ApiModelProperty(value = "规格id", example = "1024")
+ private String propertyId;
+
+ @ApiModelProperty(value = "规格值", example = "红色")
+ private String name;
+
+ @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
+ private Integer status;
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java
index 17eedaae94..501afd752b 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java
@@ -6,7 +6,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
-import java.util.Date;
+import java.time.LocalDateTime;
@ApiModel("管理后台 - 规格值 Response VO")
@Data
@@ -18,6 +18,6 @@ public class ProductPropertyValueRespVO extends ProductPropertyValueBaseVO {
private Long id;
@ApiModelProperty(value = "创建时间")
- private Date createTime;
+ private LocalDateTime createTime;
}
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 4a1bc57787..2437600a83 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/sku/ProductSkuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java
index 2081e7da80..ac9713423d 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java
@@ -1,14 +1,57 @@
package cn.iocoder.yudao.module.product.controller.admin.sku;
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO;
+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.spu.ProductSpuDO;
+import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
+import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
@Api(tags = "管理后台 - 商品 sku")
@RestController
@RequestMapping("/product/sku")
@Validated
public class ProductSkuController {
+ @Resource
+ private ProductSkuService productSkuService;
+ @Resource
+ private ProductSpuService productSpuService;
+
+ @GetMapping("/get-option-list")
+ @ApiOperation("获得商品 SKU 选项的列表")
+// @PreAuthorize("@ss.hasPermission('product:sku:query')")
+ public CommonResult> getSkuOptionList() {
+ // 获得 SKU 列表
+ List skus = productSkuService.getSkuList();
+ if (CollUtil.isEmpty(skus)) {
+ return success(Collections.emptyList());
+ }
+
+ // 获得对应的 SPU 映射
+ Map spuMap = productSpuService.getSpuMap(convertSet(skus, ProductSkuDO::getSpuId));
+ // 转换为返回结果
+ List skuVOs = ProductSkuConvert.INSTANCE.convertList05(skus);
+ skuVOs.forEach(sku -> MapUtils.findAndThen(spuMap, sku.getSpuId(),
+ spu -> sku.setSpuId(spu.getId()).setSpuName(spu.getName())));
+ return success(skuVOs);
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
index 43f67ee530..45cb447b80 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
@@ -33,7 +33,7 @@ public class ProductSkuBaseVO {
@ApiModelProperty(value = "条形码", example = "haha")
private String barCode;
- @ApiModelProperty(value = "图片地址")
+ @ApiModelProperty(value = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png")
@NotNull(message = "图片地址不能为空")
private String picUrl;
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java
index 84d71d9b74..6d5ce024d3 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java
@@ -14,8 +14,7 @@ import java.util.List;
@ToString(callSuper = true)
public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO {
- // TODO @Luowenfeng:可以不用哈,如果基于规格匹配
- @ApiModelProperty(value = "商品 id 更新时须有", example = "1")
+ @ApiModelProperty(value = "商品 SKU 编号", example = "1")
private Long id;
/**
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java
new file mode 100644
index 0000000000..0324bdc8d0
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel(value = "管理后台 - 商品 SKU 选项 Response VO", description = "用于前端 SELECT 选项")
+@Data
+public class ProductSkuOptionRespVO {
+
+ @ApiModelProperty(value = "主键", required = true, example = "1024")
+ private Long id;
+
+ @ApiModelProperty(value = "商品 SKU 名字", example = "红色")
+ private String name;
+
+ @ApiModelProperty(value = "销售价格", required = true, example = "100", notes = "单位:分")
+ private String price;
+
+ @ApiModelProperty(value = "库存", required = true, example = "100")
+ private Integer stock;
+
+ // ========== 商品 SPU 信息 ==========
+
+ @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1")
+ private Long spuId;
+
+ @ApiModelProperty(value = "商品 SPU 名字", required = true, example = "iPhone 11")
+ private String spuName;
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java
index 46e76cc63c..1ac29724b1 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java
@@ -6,10 +6,10 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
-import java.util.Date;
+import java.time.LocalDateTime;
import java.util.List;
-@ApiModel("管理后台 - 商品sku Response VO")
+@ApiModel("管理后台 - 商品 SKU Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@@ -19,7 +19,7 @@ public class ProductSkuRespVO extends ProductSkuBaseVO {
private Long id;
@ApiModelProperty(value = "创建时间")
- private Date createTime;
+ private LocalDateTime createTime;
/**
* 规格值数组
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
index ddae45dc25..155fd02653 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
@@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.product.controller.admin.spu;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
-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.ProductSpuPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
@@ -56,6 +53,15 @@ public class ProductSpuController {
return success(true);
}
+ // TODO 芋艿:修改接口
+ @GetMapping("/get/detail")
+ @ApiOperation("获得商品 SPU")
+ @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+ @PreAuthorize("@ss.hasPermission('product:spu:query')")
+ public CommonResult getSpuDetail(@RequestParam("id") Long id) {
+ return success(spuService.getSpuDetail(id));
+ }
+
@GetMapping("/get")
@ApiOperation("获得商品 SPU")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@@ -64,7 +70,6 @@ public class ProductSpuController {
return success(spuService.getSpu(id));
}
- // TODO @luowenfeng:新增 get-detail,返回 SpuDetailRespVO
@GetMapping("/list")
@ApiOperation("获得商品 SPU 列表")
@@ -75,6 +80,14 @@ public class ProductSpuController {
return success(ProductSpuConvert.INSTANCE.convertList(list));
}
+ @GetMapping("/get-simple-list")
+ @ApiOperation("获得商品 SPU 精简列表")
+ @PreAuthorize("@ss.hasPermission('product:spu:query')")
+ public CommonResult> getSpuSimpleList() {
+ List list = spuService.getSpuList();
+ return success(ProductSpuConvert.INSTANCE.convertList02(list));
+ }
+
@GetMapping("/page")
@ApiOperation("获得商品 SPU 分页")
@PreAuthorize("@ss.hasPermission('product:spu:query')")
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
index ec58bab765..54f0986dd8 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
@@ -24,7 +24,7 @@ public class ProductSpuBaseVO {
@ApiModelProperty(value = "商品编码", example = "yudaoyuanma")
private String code;
- @ApiModelProperty(value = "商品卖点", example = "好吃!")
+ @ApiModelProperty(value = "促销语", example = "好吃!")
private String sellPoint;
@ApiModelProperty(value = "商品详情", required = true, example = "我是商品描述")
@@ -67,6 +67,9 @@ public class ProductSpuBaseVO {
@ApiModelProperty(value = "库存", required = true, example = "true")
private Integer totalStock;
+ @ApiModelProperty(value = "市场价", example = "1024")
+ private Integer marketPrice;
+
@ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024")
private Integer minPrice;
@@ -75,10 +78,14 @@ public class ProductSpuBaseVO {
// ========== 统计相关字段 =========
+ @ApiModelProperty(value = "商品销量", example = "1024")
+ private Integer salesCount;
+
@ApiModelProperty(value = "虚拟销量", required = true, example = "1024")
@NotNull(message = "虚拟销量不能为空")
private Integer virtualSalesCount;
@ApiModelProperty(value = "点击量", example = "1024")
private Integer clickCount;
+
}
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 dafb0a6802..de41d14169 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
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -7,7 +8,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
-import java.util.Date;
+import java.time.LocalDateTime;
import java.util.List;
@ApiModel(value = "管理后台 - 商品 SPU 详细 Response VO", description = "包括关联的 SKU 等信息")
@@ -20,7 +21,7 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO {
private Long id;
@ApiModelProperty(value = "创建时间")
- private Date createTime;
+ private LocalDateTime createTime;
/**
* SKU 数组
@@ -54,4 +55,11 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO {
}
+ @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\"}]}]")
+ private List productPropertyViews;
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
index 36a37541bd..8d1bbee5fe 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
@@ -1,12 +1,11 @@
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
-import lombok.*;
-import java.util.*;
-import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
@ApiModel("管理后台 - 商品 SPU 分页 Request VO")
@Data
@@ -14,38 +13,34 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@ToString(callSuper = true)
public class ProductSpuPageReqVO extends PageParam {
- @ApiModelProperty(value = "商品名称")
+ @ApiModelProperty(value = "商品名称", example = "yutou")
private String name;
- @ApiModelProperty(value = "卖点")
- private String sellPoint;
+ @ApiModelProperty(value = "商品编码", example = "yudaoyuanma")
+ private String code;
- @ApiModelProperty(value = "描述")
- private String description;
-
- @ApiModelProperty(value = "分类id")
+ @ApiModelProperty(value = "分类id", example = "1")
private Long categoryId;
- @ApiModelProperty(value = "商品主图地址,* 数组,以逗号分隔,最多上传15张")
- private String picUrls;
+ @ApiModelProperty(value = "商品品牌编号", example = "1")
+ private Long brandId;
- @ApiModelProperty(value = "排序字段")
- private Integer sort;
-
- @ApiModelProperty(value = "点赞初始人数")
- private Integer likeCount;
-
- @ApiModelProperty(value = "价格 单位使用:分")
- private Integer price;
-
- @ApiModelProperty(value = "库存数量")
- private Integer quantity;
-
- @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)")
+ @ApiModelProperty(value = "上下架状态", example = "1", notes = "参见 ProductSpuStatusEnum 枚举值")
private Integer status;
- @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
- @ApiModelProperty(value = "创建时间")
- private Date[] createTime;
+ @ApiModelProperty(value = "销量最小值", example = "1")
+ private Integer salesCountMin;
+
+ @ApiModelProperty(value = "销量最大值", example = "1024")
+ private Integer salesCountMax;
+
+ @ApiModelProperty(value = "市场价最小值", example = "1")
+ private Integer marketPriceMin;
+
+ @ApiModelProperty(value = "市场价最大值", example = "1024")
+ private Integer marketPriceMax;
+
+ @ApiModelProperty(value = "是否库存告警", example = "true")
+ private Boolean alarmStock;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
index 9db319fdc6..a8dca328b6 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
@@ -1,17 +1,14 @@
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
-import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
-import java.util.Date;
+import java.time.LocalDateTime;
import java.util.List;
-// TODO @Luowenfeng:这个类只返回 SPU 相关的信息,删除 skus、categoryIds、productPropertyViews;明细使用 SpuDetailRespVO 替代
@ApiModel("管理后台 - 商品 SPU Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@@ -22,20 +19,6 @@ public class ProductSpuRespVO extends ProductSpuBaseVO {
private Long id;
@ApiModelProperty(value = "创建时间")
- private Date createTime;
-
- /**
- * SKU 数组
- */
- @ApiModelProperty(value = "sku 数组", example = "[{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":10}],\"price\":12,\"originalPrice\":32,\"costPrice\":22,\"barCode\":\"765670123123\",\"picUrl\":\"http://test.yudao.iocoder.cn/72938088f1ca8438837c3b51394aea43.jpg\",\"status\":0,\"id\":7,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":11}],\"price\":13,\"originalPrice\":33,\"costPrice\":23,\"barCode\":\"888788770999\",\"picUrl\":\"http://test.yudao.iocoder.cn/6b902c700e5d32e862b6fd9af2e1c0e4.jpg\",\"status\":0,\"id\":8,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":10}],\"price\":14,\"originalPrice\":34,\"costPrice\":24,\"barCode\":\"9999981212\",\"picUrl\":\"http://test.yudao.iocoder.cn/eddf3c79b1917160d94d05244e1f47da.jpg\",\"status\":0,\"id\":9,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":11}],\"price\":15,\"originalPrice\":35,\"costPrice\":25,\"barCode\":\"4444121212\",\"picUrl\":\"http://test.yudao.iocoder.cn/88ac3eb068ea9cfac4726879b2776ccf.jpg\",\"status\":0,\"id\":10,\"createTime\":1656683270000}]")
- private List skus;
-
- @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]")
- private List categoryIds;
-
- // TODO @芋艿:再琢磨下 这个 VO 类,其实变成 SpuRespVO 内嵌的 VO 类会更好一点;然后把 SpuRespVO 改成 SpuDetailSpuVO
-
- @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\"}]}]")
- private List productPropertyViews;
+ private LocalDateTime createTime;
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java
new file mode 100755
index 0000000000..ea2811f8b8
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@ApiModel("管理后台 - 商品 SPU 精简 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ProductSpuSimpleRespVO extends ProductSpuBaseVO {
+
+ @ApiModelProperty(value = "主键", required = true, example = "1")
+ private Long id;
+
+ @ApiModelProperty(value = "商品名称", required = true, example = "芋道")
+ private String name;
+
+ @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024")
+ private Integer minPrice;
+
+ @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024")
+ private Integer maxPrice;
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
index 52b82a2ea6..91f811ad62 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
@@ -3,8 +3,11 @@ package cn.iocoder.yudao.module.product.convert.property;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
+import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@@ -24,10 +27,12 @@ public interface ProductPropertyConvert {
ProductPropertyDO convert(ProductPropertyUpdateReqVO bean);
- ProductPropertyAndValueRespVO convert(ProductPropertyDO bean);
+ ProductPropertyAndValueRespVO convert(ProductPropertyRespVO bean);
- List convertList(List list);
+ ProductPropertyRespVO convert(ProductPropertyDO bean);
- PageResult convertPage(PageResult page);
+ List convertList(List list);
+
+ PageResult convertPage(PageResult page);
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
index 0ee468d36a..b29d612bec 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
@@ -1,16 +1,23 @@
package cn.iocoder.yudao.module.product.convert.sku;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/**
- * 商品sku Convert
+ * 商品 SKU Convert
*
* @author 芋道源码
*/
@@ -21,11 +28,42 @@ public interface ProductSkuConvert {
ProductSkuDO convert(ProductSkuCreateOrUpdateReqVO bean);
- @Mapping(source = "properties", target = "properties")
ProductSkuRespVO convert(ProductSkuDO bean);
List convertList(List list);
List convertSkuDOList(List list);
+ ProductSkuRespDTO convert02(ProductSkuDO bean);
+
+ List convertList02(List list);
+
+ List convertList03(List list);
+
+ List convertList04(List list);
+
+ List convertList05(List skus);
+
+ /**
+ * 获得 SPU 的库存变化 Map
+ *
+ * @param items SKU 库存变化
+ * @param skus SKU 列表
+ * @return SPU 的库存变化 Map
+ */
+ default Map convertSpuStockMap(List items,
+ List skus) {
+ Map skuIdAndSpuIdMap = convertMap(skus, ProductSkuDO::getId, ProductSkuDO::getSpuId); // SKU 与 SKU 编号的 Map 关系
+ Map spuIdAndStockMap = new HashMap<>(); // SPU 的库存变化 Map 关系
+ items.forEach(item -> {
+ Long spuId = skuIdAndSpuIdMap.get(item.getId());
+ if (spuId == null) {
+ return;
+ }
+ Integer stock = spuIdAndStockMap.getOrDefault(spuId, 0) + item.getIncrCount();
+ spuIdAndStockMap.put(spuId, stock);
+ });
+ return spuIdAndStockMap;
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
index 2fb6639ab4..98b7d88370 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.product.convert.spu;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
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;
@@ -34,4 +35,8 @@ public interface ProductSpuConvert {
AppSpuPageRespVO convertAppResp(ProductSpuDO list);
+ List convertList2(List list);
+
+ List convertList02(List list);
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java
index 6671e9b446..93ec925a97 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java
@@ -64,6 +64,4 @@ public class ProductCategoryDO extends BaseDO {
*/
private Integer status;
- // TODO 芋艿:is_recommend 是否首页推荐:1-是;0-否
-
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java
index 30db12819d..c14808f228 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java
@@ -10,7 +10,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
-import java.util.Date;
+import java.time.LocalDateTime;
import java.util.List;
/**
@@ -117,7 +117,7 @@ public class ProductCommentDO extends BaseDO {
/**
* 商家回复时间
*/
- private Date replyTime;
+ private LocalDateTime replyTime;
/**
* 有用的计数
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
index 608b248fe4..b3831491ec 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
@@ -37,6 +37,10 @@ public class ProductPropertyDO extends BaseDO {
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
+ /**
+ * 备注
+ */
+ private String remark;
// TODO 芋艿:rule;规格属性 (发布商品时,和 SKU 关联);规格参数(搜索商品时,与 Category 关联搜索)
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
index 007b95a4f8..b75f0d5927 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
@@ -44,5 +44,10 @@ public class ProductPropertyValueDO extends BaseDO {
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
+ /**
+ * 备注
+ *
+ */
+ private String remark;
}
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 fc7bbe9ecd..f953534ed3 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,8 @@ public class ProductSkuDO extends BaseDO {
* 商品属性
*/
@Data
+ @NoArgsConstructor
+ @AllArgsConstructor
public static class Property {
/**
@@ -129,19 +131,5 @@ public class ProductSkuDO extends BaseDO {
}
- // TODO ========== 待定字段:yv =========
- // TODO brokerage:一级返佣
- // TODO brokerage_two:二级返佣
- // TODO pink_price:拼团价
- // TODO pink_stock:拼团库存
- // TODO seckill_price:秒杀价
- // TODO seckill_stock:秒杀库存
- // TODO integral:需要积分
-
- // TODO ========== 待定字段:cf =========
- // TODO type 活动显示排序 0=默认 1=秒 2=砍价 3=拼团
- // TODO quota 活动限购数量
- // TODO quota_show 活动限购数量显示
-
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java
index a22b68a2c2..93c47d4aff 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java
@@ -47,7 +47,7 @@ public class ProductSpuDO extends BaseDO {
*/
private String code;
/**
- * 商品卖点
+ * 促销语
*/
private String sellPoint;
/**
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 bd088466f6..890df34771 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
@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.Pro
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
/**
* 规格名称 Mapper
*
@@ -23,4 +25,9 @@ public interface ProductPropertyMapper extends BaseMapperX {
.orderByDesc(ProductPropertyDO::getId));
}
+ default ProductPropertyDO selectByName(String name) {
+ return selectOne(new LambdaQueryWrapperX()
+ .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 6c5fc7570a..ca9bafab26 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
@@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.product.dal.mysql.property;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
import org.apache.ibatis.annotations.Mapper;
@@ -15,18 +17,28 @@ import java.util.List;
@Mapper
public interface ProductPropertyValueMapper extends BaseMapperX {
- // TODO @franky:方法名,selectListByXXX。mapper 的操作都是 crud
- default List getPropertyValueListByPropertyId(List propertyIds){
- // TODO @franky:调用父类的 selectList
+ default List selectListByPropertyId(List propertyIds) {
return selectList(new LambdaQueryWrapperX()
.inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds));
}
- default void deletePropertyValueByPropertyId(Long propertyId){
- // TODO @franky:delete(new ) 即可
- LambdaQueryWrapperX queryWrapperX = new LambdaQueryWrapperX<>();
- queryWrapperX.eq(ProductPropertyValueDO::getPropertyId, propertyId)
- .eq(ProductPropertyValueDO::getDeleted, false);
- delete(queryWrapperX);
+ default ProductPropertyValueDO selectByName(Long propertyId, String name) {
+ return selectOne(new LambdaQueryWrapperX()
+ .eq(ProductPropertyValueDO::getPropertyId, propertyId)
+ .eq(ProductPropertyValueDO::getName, name));
}
+
+ default void deletePropertyValueByPropertyId(Long propertyId) {
+ delete(new LambdaQueryWrapperX().eq(ProductPropertyValueDO::getPropertyId, propertyId)
+ .eq(ProductPropertyValueDO::getDeleted, false));
+ }
+
+ default PageResult selectPage(ProductPropertyValuePageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(ProductPropertyValueDO::getPropertyId, reqVO.getPropertyId())
+ .likeIfPresent(ProductPropertyValueDO::getName, reqVO.getName())
+ .eqIfPresent(ProductPropertyValueDO::getStatus, reqVO.getStatus())
+ .orderByDesc(ProductPropertyValueDO::getId));
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
index cc45e5764e..3e5a9ce8fa 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
@@ -1,8 +1,11 @@
package cn.iocoder.yudao.module.product.dal.mysql.sku;
+import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@@ -15,20 +18,46 @@ import java.util.List;
@Mapper
public interface ProductSkuMapper extends BaseMapperX {
- // TODO @franky:方法名 selectList; 可以直接调用 selectList
- default List selectListBySpuIds(List spuIds) {
- return selectList(ProductSkuDO::getSpuId, spuIds);
- }
-
default List selectListBySpuId(Long spuId) {
return selectList(ProductSkuDO::getSpuId, spuId);
}
default void deleteBySpuId(Long spuId) {
- // TODO @franky:直接 delete(new XXX) 即可,更简洁一些
- LambdaQueryWrapperX lambdaQueryWrapperX = new LambdaQueryWrapperX()
- .eqIfPresent(ProductSkuDO::getSpuId, spuId);
- delete(lambdaQueryWrapperX);
+ delete(new LambdaQueryWrapperX().eq(ProductSkuDO::getSpuId, spuId));
+ }
+
+ /**
+ * 更新 SKU 库存(增加)
+ *
+ * @param id 编号
+ * @param incrCount 增加库存(正数)
+ */
+ default void updateStockIncr(Long id, Integer incrCount) {
+ Assert.isTrue(incrCount > 0);
+ LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper()
+ .setSql(" stock = stock + " + incrCount)
+ .eq(ProductSkuDO::getId, id);
+ update(null, lambdaUpdateWrapper);
+ }
+
+ /**
+ * 更新 SKU 库存(减少)
+ *
+ * @param id 编号
+ * @param incrCount 减少库存(负数)
+ * @return 更新条数
+ */
+ default int updateStockDecr(Long id, Integer incrCount) {
+ Assert.isTrue(incrCount < 0);
+ LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper()
+ .setSql(" stock = stock + " + incrCount) // 负数,所以使用 + 号
+ .eq(ProductSkuDO::getId, id)
+ .ge(ProductSkuDO::getStock, -incrCount); // cas 逻辑
+ return update(null, updateWrapper);
+ }
+
+ default List selectListByAlarmStock(){
+ return selectList(new QueryWrapper().apply("stock <= warn_stock"));
}
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
index 1755695cba..a271b5051e 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
@@ -5,8 +5,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
+import java.util.Set;
+
/**
* 商品spu Mapper
*
@@ -18,12 +21,40 @@ public interface ProductSpuMapper extends BaseMapperX {
default PageResult selectPage(ProductSpuPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX()
.likeIfPresent(ProductSpuDO::getName, reqVO.getName())
- .eqIfPresent(ProductSpuDO::getSellPoint, reqVO.getSellPoint())
.eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
- .eqIfPresent(ProductSpuDO::getPicUrls, reqVO.getPicUrls())
.eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
- .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime())
+ .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
+ .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
+ .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
+ .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
.orderByDesc(ProductSpuDO::getSort));
}
+ default PageResult selectPage(ProductSpuPageReqVO reqVO, Set alarmStockSpuIds) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .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));
+ }
+
+ /**
+ * 更新商品 SPU 库存
+ *
+ * @param id 商品 SPU 编号
+ * @param incrCount 增加的库存数量
+ */
+ default void updateStock(Long id, Integer incrCount) {
+ LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper()
+ .setSql(" total_stock = total_stock +" + incrCount) // 负数,所以使用 + 号
+ .eq(ProductSpuDO::getId, id);
+ update(null, updateWrapper);
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
index ebfe599d66..ffe55e9bfc 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.product.service.category;
-import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryCreateReqVO;
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
@@ -93,35 +92,21 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
@Override
public void validateCategoryLevel(Long id) {
- Integer level = getProductCategoryLevel(id, 1);
- if (level < 3){
+ // TODO @芋艿:在看看,杂能优化下
+ Long parentId = id;
+ int i = 2;
+ for (; i >= 0; --i) {
+ ProductCategoryDO category = productCategoryMapper.selectById(parentId);
+ parentId = category.getParentId();
+ if(Objects.equals(parentId, ProductCategoryDO.PARENT_ID_NULL)){
+ break;
+ }
+ }
+ if (!Objects.equals(parentId, ProductCategoryDO.PARENT_ID_NULL) || i != 0) {
throw exception(CATEGORY_LEVEL_ERROR);
}
}
- // TODO @Luowenfeng:建议使用 for 循环,避免递归
- /**
- * 获得商品分类的级别
- *
- * @param id 商品分类的编号
- * @return 级别
- */
- private Integer getProductCategoryLevel(Long id, int level){
- ProductCategoryDO category = productCategoryMapper.selectById(id);
- if (category == null) {
- throw exception(CATEGORY_NOT_EXISTS);
- }
- // TODO Luowenfeng:去掉是否开启,它不影响级别哈
- if (ObjectUtil.notEqual(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
- throw exception(CATEGORY_DISABLED);
- }
- // TODO Luowenfeng:不使用 0 直接比较哈,使用枚举
- if (category.getParentId() == 0) {
- return level;
- }
- return getProductCategoryLevel(category.getParentId(), ++level);
- }
-
@Override
public ProductCategoryDO getCategory(Long id) {
return productCategoryMapper.selectById(id);
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java
index a87e15d70b..8780c78658 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.product.service.property;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*;
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
@@ -39,44 +39,42 @@ public interface ProductPropertyService {
void deleteProperty(Long id);
/**
- * 获得规格名称
+ * 获得规格名称列表
+ * @param listReqVO 集合查询
+ * @return 规格名称集合
+ */
+ List getPropertyList(ProductPropertyListReqVO listReqVO);
+
+ /**
+ * 获取属性名称分页
+ *
+ * @param pageReqVO 分页条件
+ * @return 规格名称分页
+ */
+ PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO);
+
+ /**
+ * 获得指定编号的规格名称
*
* @param id 编号
* @return 规格名称
*/
- ProductPropertyDO getProperty(Long id);
-
- /**
- * 获得规格名称列表
- *
- * @param ids 编号
- * @return 规格名称列表
- */
- List getPropertyList(Collection ids);
-
- /**
- * 获得规格名称分页
- *
- * @param pageReqVO 分页查询
- * @return 规格名称分页
- */
- PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO);
-
- /**
- * 获取属性及属性值列表 分页
- * @param pageReqVO
- * @return
- */
- PageResult getPropertyListPage(ProductPropertyPageReqVO pageReqVO);
-
- ProductPropertyAndValueRespVO getPropertyResp(Long id);
+ ProductPropertyRespVO getProperty(Long id);
/**
* 根据规格属性编号的集合,获得对应的规格 + 规格值的集合
*
* @param ids 规格编号的集合
- * @return 对应的规格 + 规格值的集合
+ * @return 对应的规格
*/
- List getPropertyAndValueList(Collection ids);
+ List getPropertyList(Collection ids);
+
+ /**
+ * 获得规格名称 + 值的列表
+ *
+ * @param listReqVO 列表查询
+ * @return 规格名称 + 值的列表
+ */
+ List getPropertyAndValueList(ProductPropertyListReqVO listReqVO);
}
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 d48c8b1ff9..74e370f9c1 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
@@ -1,10 +1,10 @@
package cn.iocoder.yudao.module.product.service.property;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
import cn.iocoder.yudao.module.product.convert.property.ProductPropertyConvert;
import cn.iocoder.yudao.module.product.convert.propertyvalue.ProductPropertyValueConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
@@ -16,13 +16,13 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
-import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
+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;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_NOT_EXISTS;
/**
@@ -43,15 +43,13 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long createProperty(ProductPropertyCreateReqVO createReqVO) {
+ // 校验存在
+ if (productPropertyMapper.selectByName(createReqVO.getName()) != null) {
+ throw exception(PROPERTY_EXISTS);
+ }
// 插入
ProductPropertyDO property = ProductPropertyConvert.INSTANCE.convert(createReqVO);
productPropertyMapper.insert(property);
-
- //插入属性值
- List propertyValueList = createReqVO.getPropertyValueList();
- List productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
- productPropertyValueDOList.forEach(x-> x.setPropertyId(property.getId()));
- productPropertyValueMapper.insertBatch(productPropertyValueDOList);
// 返回
return property.getId();
}
@@ -61,15 +59,13 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
public void updateProperty(ProductPropertyUpdateReqVO updateReqVO) {
// 校验存在
this.validatePropertyExists(updateReqVO.getId());
+ ProductPropertyDO productPropertyDO = productPropertyMapper.selectByName(updateReqVO.getName());
+ if (productPropertyDO != null && !productPropertyDO.getId().equals(updateReqVO.getId())) {
+ throw exception(PROPERTY_EXISTS);
+ }
// 更新
ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO);
productPropertyMapper.updateById(updateObj);
- //更新属性值,先删后加
- productPropertyValueMapper.deletePropertyValueByPropertyId(updateReqVO.getId());
- List propertyValueList = updateReqVO.getPropertyValueList();
- List productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
- productPropertyValueDOList.forEach(x-> x.setPropertyId(updateReqVO.getId()));
- productPropertyValueMapper.insertBatch(productPropertyValueDOList);
}
@Override
@@ -89,63 +85,41 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
}
@Override
- public ProductPropertyDO getProperty(Long id) {
- return productPropertyMapper.selectById(id);
+ public List getPropertyList(ProductPropertyListReqVO listReqVO) {
+ return ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectList(new LambdaQueryWrapperX()
+ .likeIfPresent(ProductPropertyDO::getName, listReqVO.getName())
+ .eqIfPresent(ProductPropertyDO::getStatus, listReqVO.getStatus())));
}
@Override
- public List getPropertyList(Collection ids) {
- return productPropertyMapper.selectBatchIds(ids);
- }
-
- @Override
- public PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO) {
- return productPropertyMapper.selectPage(pageReqVO);
- }
-
- @Override
- public PageResult getPropertyListPage(ProductPropertyPageReqVO pageReqVO) {
+ public PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO) {
//获取属性列表
PageResult pageResult = productPropertyMapper.selectPage(pageReqVO);
- PageResult propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
- List propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyAndValueRespVO::getId).collect(Collectors.toList());
+ return ProductPropertyConvert.INSTANCE.convertPage(pageResult);
+ }
- //获取属性值列表
- List productPropertyValueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
- List propertyValueRespVOList = ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueDOList);
- //组装一对多
- propertyRespVOPageResult.getList().forEach(x->{
- Long propertyId = x.getId();
- List valueDOList = propertyValueRespVOList.stream().filter(v -> v.getPropertyId().equals(propertyId)).collect(Collectors.toList());
- x.setValues(valueDOList);
+ @Override
+ public ProductPropertyRespVO getProperty(Long id) {
+ ProductPropertyDO property = productPropertyMapper.selectById(id);
+ return ProductPropertyConvert.INSTANCE.convert(property);
+ }
+
+ @Override
+ public List getPropertyList(Collection ids) {
+ return ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids));
+ }
+
+ @Override
+ public List getPropertyAndValueList(ProductPropertyListReqVO listReqVO) {
+ List propertyList = getPropertyList(listReqVO);
+
+ // 查询属性值
+ 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);
+ productPropertyAndValueRespVO.setValues(ProductPropertyValueConvert.INSTANCE.convertList(valueDOMap.get(m.getId())));
+ return productPropertyAndValueRespVO;
});
- return propertyRespVOPageResult;
- }
-
- private List getPropertyValueListByPropertyId(List propertyIds) {
- return productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
- }
-
- @Override
- public ProductPropertyAndValueRespVO getPropertyResp(Long id) {
- //查询规格
- ProductPropertyDO property = getProperty(id);
- ProductPropertyAndValueRespVO propertyRespVO = ProductPropertyConvert.INSTANCE.convert(property);
- //查询属性值
- List valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(Arrays.asList(id));
- List propertyValueRespVOS = ProductPropertyValueConvert.INSTANCE.convertList(valueDOList);
- //组装
- propertyRespVO.setValues(propertyValueRespVOS);
- return propertyRespVO;
- }
-
- @Override
- public List getPropertyAndValueList(Collection ids) {
- List productPropertyRespVO = ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids));
- //查询属性值
- List valueDOList = productPropertyValueMapper.selectBatchIds(ids);
- Map> propertyValuesMap = valueDOList.stream().collect(Collectors.groupingBy(ProductPropertyValueDO::getPropertyId));
- productPropertyRespVO.forEach(p -> p.setValues(ProductPropertyValueConvert.INSTANCE.convertList(propertyValuesMap.get(p.getId()))));
- return productPropertyRespVO;
}
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java
new file mode 100644
index 0000000000..9dcbd72e7a
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java
@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.product.service.property;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
+
+import java.util.List;
+
+/**
+ *
+ * 规格值 Service 接口
+ *
+ *
+ * @author LuoWenFeng
+ */
+public interface ProductPropertyValueService {
+
+ /**
+ * 创建规格值
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO);
+
+ /**
+ * 更新规格值
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO);
+
+ /**
+ * 删除规格值
+ *
+ * @param id 编号
+ */
+ void deletePropertyValue(Long id);
+
+ /**
+ * 获得规格值
+ *
+ * @param id 编号
+ * @return 规格名称
+ */
+ ProductPropertyValueRespVO getPropertyValue(Long id);
+
+ /**
+ * 获得规格值
+ *
+ * @param id 编号
+ * @return 规格名称
+ */
+ List getPropertyValueListByPropertyId(List id);
+
+ /**
+ * 获取规格值 分页
+ *
+ * @param pageReqVO 查询条件
+ * @return
+ */
+ PageResult getPropertyValueListPage(ProductPropertyValuePageReqVO pageReqVO);
+}
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
new file mode 100644
index 0000000000..5addb37e8a
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java
@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.product.service.property;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
+import cn.iocoder.yudao.module.product.convert.propertyvalue.ProductPropertyValueConvert;
+import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
+import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyValueMapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.stereotype.Service;
+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;
+
+/**
+ * 规格值 Service 实现类
+ *
+ * @author LuoWenFeng
+ */
+@Service
+@Validated
+public class ProductPropertyValueServiceImpl implements ProductPropertyValueService {
+
+ @Resource
+ private ProductPropertyValueMapper productPropertyValueMapper;
+
+ @Override
+ public Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO) {
+ if (productPropertyValueMapper.selectByName(createReqVO.getPropertyId(), createReqVO.getName()) != null) {
+ throw exception(PROPERTY_VALUE_EXISTS);
+ }
+ ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(createReqVO);
+ productPropertyValueMapper.insert(convert);
+ return convert.getId();
+ }
+
+ @Override
+ public void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO) {
+ 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);
+ productPropertyValueMapper.updateById(convert);
+ }
+
+ @Override
+ public void deletePropertyValue(Long id) {
+ productPropertyValueMapper.deleteById(id);
+ }
+
+ @Override
+ public ProductPropertyValueRespVO getPropertyValue(Long id) {
+ ProductPropertyValueDO productPropertyValueDO = productPropertyValueMapper.selectOne(new LambdaQueryWrapper()
+ .eq(ProductPropertyValueDO::getId, id));
+ return ProductPropertyValueConvert.INSTANCE.convert(productPropertyValueDO);
+ }
+
+ @Override
+ public List getPropertyValueListByPropertyId(List id) {
+ return ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueMapper.selectList("property_id", id));
+ }
+
+ @Override
+ public PageResult getPropertyValueListPage(ProductPropertyValuePageReqVO pageReqVO) {
+ return ProductPropertyValueConvert.INSTANCE.convertPage(productPropertyValueMapper.selectPage(pageReqVO));
+ }
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
index 5316f4764d..1036d8348d 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
@@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.product.service.sku;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
-import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
@@ -15,22 +15,29 @@ import java.util.List;
public interface ProductSkuService {
/**
- * 删除商品sku
+ * 删除商品 SKU
*
* @param id 编号
*/
void deleteSku(Long id);
/**
- * 获得商品sku
+ * 获得商品 SKU 信息
*
* @param id 编号
- * @return 商品sku
+ * @return 商品 SKU 信息
*/
ProductSkuDO getSku(Long id);
/**
- * 获得商品sku列表
+ * 获得商品 SKU 列表
+ *
+ * @return 商品sku列表
+ */
+ List getSkuList();
+
+ /**
+ * 获得商品 SKU 列表
*
* @param ids 编号
* @return 商品sku列表
@@ -58,7 +65,16 @@ public interface ProductSkuService {
* @param spuId SPU 编码
* @param skus SKU 的集合
*/
- void updateProductSkus(Long spuId, List skus);
+ void updateSkus(Long spuId, List skus);
+
+ /**
+ * 更新 SKU 库存(增量)
+ *
+ * 如果更新的库存不足,会抛出异常
+ *
+ * @param updateStockReqDTO 更行请求
+ */
+ void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO);
/**
* 获得商品 sku 集合
@@ -83,4 +99,12 @@ public interface ProductSkuService {
*/
void deleteSkuBySpuId(Long spuId);
+ /**
+ * 获得库存预警的 SKU 数组
+ *
+ * @return SKU 数组
+ */
+ List getSkusByAlarmStock();
+
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
index bf8dab778f..2791ae5d3a 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
@@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.product.service.sku;
-import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
+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.ProductSkuBaseVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
@@ -13,6 +13,9 @@ 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.spu.ProductSpuSpecTypeEnum;
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.spu.ProductSpuService;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -22,6 +25,7 @@ import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
/**
@@ -36,13 +40,18 @@ public class ProductSkuServiceImpl implements ProductSkuService {
@Resource
private ProductSkuMapper productSkuMapper;
+ @Resource
+ @Lazy // 循环依赖,避免报错
+ private ProductSpuService productSpuService;
@Resource
private ProductPropertyService productPropertyService;
+ @Resource
+ private ProductPropertyValueService productPropertyValueService;
@Override
public void deleteSku(Long id) {
// 校验存在
- this.validateSkuExists(id);
+ validateSkuExists(id);
// 删除
productSkuMapper.deleteById(id);
}
@@ -58,6 +67,11 @@ public class ProductSkuServiceImpl implements ProductSkuService {
return productSkuMapper.selectById(id);
}
+ @Override
+ public List getSkuList() {
+ return productSkuMapper.selectList();
+ }
+
@Override
public List getSkuList(Collection ids) {
return productSkuMapper.selectBatchIds(ids);
@@ -71,19 +85,17 @@ public class ProductSkuServiceImpl implements ProductSkuService {
}
// 1、校验规格属性存在
- // TODO @Luowenfeng:stream 的写法;不用改哈,就是说下可以酱紫写;
Set propertyIds = skus.stream().filter(p -> p.getProperties() != null).flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性
.map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toSet()); // 将每个 Property 转换成对应的 propertyId,最后形成集合
- List propertyAndValueList = productPropertyService.getPropertyAndValueList(propertyIds);
- if (propertyAndValueList.size() == propertyIds.size()) {
+ List propertyList = productPropertyService.getPropertyList(propertyIds);
+ if (propertyList.size() != propertyIds.size()) {
throw exception(PROPERTY_NOT_EXISTS);
}
// 2. 校验,一个 SKU 下,没有重复的规格。校验方式是,遍历每个 SKU ,看看是否有重复的规格 propertyId
- Map propertyValueMap = propertyAndValueList.stream().filter(p -> p.getValues() != null).flatMap(p -> p.getValues().stream())
- .collect(Collectors.toMap(ProductPropertyValueRespVO::getId, value -> value)); // KEY:规格属性值的编号
+ Map propertyValueMap = CollectionUtils.convertMap(productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(propertyIds)), ProductPropertyValueRespVO::getId);
skus.forEach(sku -> {
- Set skuPropertyIds = CollectionUtils.convertSet(sku.getProperties(), propertyItem -> propertyValueMap.get(propertyItem.getValueId()).getPropertyId());
+ Set skuPropertyIds = convertSet(sku.getProperties(), propertyItem -> propertyValueMap.get(propertyItem.getValueId()).getPropertyId());
if (skuPropertyIds.size() != sku.getProperties().size()) {
throw exception(SKU_PROPERTIES_DUPLICATED);
}
@@ -100,8 +112,7 @@ public class ProductSkuServiceImpl implements ProductSkuService {
// 4. 最后校验,每个 Sku 之间不是重复的
Set> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
for (ProductSkuCreateOrUpdateReqVO sku : skus) {
- // TODO @Luowenfeng:可以使用 CollectionUtils.convertSet(),简化下面的 stream 操作
- if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复
+ if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuBaseVO.Property::getValueId))) { // 添加失败,说明重复
throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
}
}
@@ -117,12 +128,12 @@ public class ProductSkuServiceImpl implements ProductSkuService {
@Override
public List getSkusBySpuId(Long spuId) {
- return productSkuMapper.selectListBySpuIds(Collections.singletonList(spuId));
+ return productSkuMapper.selectList(ProductSkuDO::getSpuId, spuId);
}
@Override
public List getSkusBySpuIds(List spuIds) {
- return productSkuMapper.selectListBySpuIds(spuIds);
+ return productSkuMapper.selectList(ProductSkuDO::getSpuId, spuIds);
}
@Override
@@ -130,41 +141,84 @@ public class ProductSkuServiceImpl implements ProductSkuService {
productSkuMapper.deleteBySpuId(spuId);
}
+ @Override
+ public List getSkusByAlarmStock() {
+ return productSkuMapper.selectListByAlarmStock();
+ }
+
@Override
@Transactional
- public void updateProductSkus(Long spuId, List skus) {
+ public void updateSkus(Long spuId, List skus) {
// 查询 SPU 下已经存在的 SKU 的集合
List existsSkus = productSkuMapper.selectListBySpuId(spuId);
- Map existsSkuMap = CollectionUtils.convertMap(existsSkus, ProductSkuDO::getId);
+ // 构建规格与 SKU 的映射关系;
+ // TODO @luowenfeng: 可以下 existsSkuMap2; 会简洁一点; 另外, 可以考虑抽一个小方法, 用于 Properties 生成一个串; 这样 177 也可以复用了
+ Map existsSkuMap = existsSkus.stream()
+ .map(v -> {
+ String collect = v.getProperties() == null? "null": v.getProperties()
+ .stream()
+ .map(m -> String.valueOf(m.getValueId()))
+ .collect(Collectors.joining());
+ return String.join("-", collect, String.valueOf(v.getId()));
+ })
+ .collect(Collectors.toMap(v -> v.split("-")[0], v -> Long.valueOf(v.split("-")[1])));
// 拆分三个集合,新插入的、需要更新的、需要删除的
List insertSkus = new ArrayList<>();
- List updateSkus = new ArrayList<>(); // TODO Luowenfeng:使用 Long 即可
- List deleteSkus = new ArrayList<>();
+ List updateSkus = new ArrayList<>();
+ List deleteSkus = new ArrayList<>();
- // TODO @Luowenfeng:是不是基于规格匹配会比较好。可以参考下 onemall 的 ProductSpuServiceImpl 的 updateProductSpu 逻辑
List allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus);
allUpdateSkus.forEach(p -> {
- if (p.getId() != null) {
- if (existsSkuMap.containsKey(p.getId())) {
- updateSkus.add(p);
- return;
- }
- deleteSkus.add(p);
+ String propertiesKey = p.getProperties() == null? "null": p.getProperties().stream().map(m -> String.valueOf(m.getValueId())).collect(Collectors.joining());
+ // 1、找得到的,进行更新
+ if (existsSkuMap.containsKey(propertiesKey)) {
+ updateSkus.add(p);
+ existsSkuMap.remove(propertiesKey);
return;
}
+ // 2、找不到,进行插入
p.setSpuId(spuId);
insertSkus.add(p);
});
+ // 3、多余的,删除
+ if(!existsSkuMap.isEmpty()){
+ deleteSkus = new ArrayList<>(existsSkuMap.values());
+ }
- if (CollectionUtil.isNotEmpty(insertSkus)) {
+ // 4、执行修改 Sku
+ if (!insertSkus.isEmpty()) {
productSkuMapper.insertBatch(insertSkus);
}
- if (updateSkus.size() > 0) {
+ if (!updateSkus.isEmpty()) {
updateSkus.forEach(p -> productSkuMapper.updateById(p));
}
- if (deleteSkus.size() > 0) {
- productSkuMapper.deleteBatchIds(deleteSkus.stream().map(ProductSkuDO::getId).collect(Collectors.toList()));
+ if (!deleteSkus.isEmpty()) {
+ productSkuMapper.deleteBatchIds(deleteSkus);
}
}
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) {
+ // 更新 SKU 库存
+ updateStockReqDTO.getItems().forEach(item -> {
+ if (item.getIncrCount() > 0) {
+ productSkuMapper.updateStockIncr(item.getId(), item.getIncrCount());
+ } else if (item.getIncrCount() < 0) {
+ int updateStockIncr = productSkuMapper.updateStockDecr(item.getId(), item.getIncrCount());
+ if (updateStockIncr == 0) {
+ throw exception(SKU_STOCK_NOT_ENOUGH);
+ }
+ }
+ });
+
+ // 更新 SPU 库存
+ List skus = productSkuMapper.selectBatchIds(
+ convertSet(updateStockReqDTO.getItems(), ProductSkuUpdateStockReqDTO.Item::getId));
+ Map spuStockIncrCounts = ProductSkuConvert.INSTANCE.convertSpuStockMap(
+ updateStockReqDTO.getItems(), skus);
+ productSpuService.updateSpuStock(spuStockIncrCounts);
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
index e5affa8d2d..151edbf867 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
@@ -1,10 +1,7 @@
package cn.iocoder.yudao.module.product.service.spu;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
-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.ProductSpuPageReqVO;
+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.dal.dataobject.spu.ProductSpuDO;
@@ -12,6 +9,9 @@ import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/**
* 商品 SPU Service 接口
@@ -36,30 +36,55 @@ public interface ProductSpuService {
void updateSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
/**
- * 删除商品spu
+ * 删除商品 SPU
*
* @param id 编号
*/
void deleteSpu(Long id);
/**
- * 获得商品spu
+ * 获得商品 SPU 详情
*
* @param id 编号
- * @return 商品spu
+ * @return 商品 SPU
+ */
+ ProductSpuDetailRespVO getSpuDetail(Long id);
+
+ /**
+ * 获得商品 SPU
+ *
+ * @param id 编号
+ * @return 商品 SPU
*/
ProductSpuRespVO getSpu(Long id);
/**
- * 获得商品spu列表
+ * 获得商品 SPU 列表
*
- * @param ids 编号
- * @return 商品spu列表
+ * @param ids 编号数组
+ * @return 商品 SPU 列表
*/
List getSpuList(Collection ids);
/**
- * 获得商品spu分页
+ * 获得商品 SPU 映射
+ *
+ * @param ids 编号数组
+ * @return 商品 SPU 映射
+ */
+ default Map getSpuMap(Collection ids) {
+ return convertMap(getSpuList(ids), ProductSpuDO::getId);
+ }
+
+ /**
+ * 获得所有商品 SPU 列表
+ *
+ * @return 商品 SPU 列表
+ */
+ List getSpuList();
+
+ /**
+ * 获得商品 SPU 分页
*
* @param pageReqVO 分页查询
* @return 商品spu分页
@@ -67,12 +92,18 @@ public interface ProductSpuService {
PageResult getSpuPage(ProductSpuPageReqVO pageReqVO);
/**
- * 获得商品spu分页
+ * 获得商品 SPU 分页
*
* @param pageReqVO 分页查询
* @return 商品spu分页
*/
PageResult getSpuPage(AppSpuPageReqVO pageReqVO);
+ /**
+ * 更新商品 SPU 库存(增量)
+ *
+ * @param stockIncrCounts SPU 编号与库存变化(增量)的映射
+ */
+ void updateSpuStock(Map stockIncrCounts);
}
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 847301ba80..4880d4948e 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
@@ -1,28 +1,30 @@
package cn.iocoder.yudao.module.product.service.spu;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
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.property.ProductPropertyAndValueRespVO;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
+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.ProductSkuBaseVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
-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.AppSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
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.ProductSpuSpecTypeEnum;
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.property.ProductPropertyService;
+import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -44,17 +46,18 @@ 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;
@Resource
+ @Lazy // 循环依赖,避免报错
private ProductSkuService productSkuService;
-
@Resource
private ProductPropertyService productPropertyService;
-
+ @Resource
+ private ProductPropertyValueService productPropertyValueService;
@Resource
private ProductBrandService brandService;
@@ -74,7 +77,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);
// 返回
@@ -92,7 +95,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
brandService.validateProductBrand(updateReqVO.getBrandId());
// 校验SKU
List skuCreateReqList = updateReqVO.getSkus();
- // 多规格才需校验
productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType());
// 更新 SPU
@@ -101,9 +103,9 @@ 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());
+ productSkuService.updateSkus(updateObj.getId(), updateReqVO.getSkus());
}
@Override
@@ -112,41 +114,44 @@ 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);
}
}
@Override
// TODO @芋艿:需要再 review 下
- public ProductSpuRespVO getSpu(Long id) {
- ProductSpuDO spu = ProductSpuMapper.selectById(id);
- ProductSpuRespVO spuVO = ProductSpuConvert.INSTANCE.convert(spu);
- if (null != spuVO) {
- List skuReqs = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuId(id));
- spuVO.setSkus(skuReqs);
- List properties = new ArrayList<>();
+ public ProductSpuDetailRespVO getSpuDetail(Long id) {
+ ProductSpuDO spu = productSpuMapper.selectById(id);
+ ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class);
+ if (null != spu) {
+ List skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id));
+ respVO.setSkus(skuReqs);
// 组合 sku 规格属性
- if(spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
- for (ProductSkuRespVO productSkuRespVO : skuReqs) {
+ if (spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
+ List properties = new ArrayList<>();
+ for (ProductSpuDetailRespVO.Sku productSkuRespVO : skuReqs) {
properties.addAll(productSkuRespVO.getProperties());
}
Map> propertyMaps = properties.stream().collect(Collectors.groupingBy(ProductSkuBaseVO.Property::getPropertyId));
- List propertyAndValueList = productPropertyService.getPropertyAndValueList(new ArrayList<>(propertyMaps.keySet()));
+
+ List propertyValueList = productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(propertyMaps.keySet()));
+ List propertyList = productPropertyService.getPropertyList(new ArrayList<>(propertyMaps.keySet()));
// 装载组装过后的属性
List productPropertyViews = new ArrayList<>();
- propertyAndValueList.forEach(p -> {
+ propertyList.forEach(p -> {
ProductPropertyViewRespVO productPropertyViewRespVO = new ProductPropertyViewRespVO();
productPropertyViewRespVO.setPropertyId(p.getId());
productPropertyViewRespVO.setName(p.getName());
List propertyValues = new ArrayList<>();
- Map propertyValueMaps = p.getValues().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv));
+ // 转换成map是为了能快速获取
+ Map propertyValueMaps = CollectionUtils.convertMap(propertyValueList, ProductPropertyValueRespVO::getId);
propertyMaps.get(p.getId()).forEach(pv -> {
ProductPropertyViewRespVO.Tuple2 tuple2 = new ProductPropertyViewRespVO.Tuple2(pv.getValueId(), propertyValueMaps.get(pv.getValueId()).getName());
propertyValues.add(tuple2);
@@ -154,48 +159,47 @@ public class ProductSpuServiceImpl implements ProductSpuService {
productPropertyViewRespVO.setPropertyValues(propertyValues.stream().distinct().collect(Collectors.toList()));
productPropertyViews.add(productPropertyViewRespVO);
});
- spuVO.setProductPropertyViews(productPropertyViews);
- }
- // 组合分类
- if (null != spuVO.getCategoryId()) {
- LinkedList categoryArray = new LinkedList<>();
- Long parentId = spuVO.getCategoryId();
- categoryArray.addFirst(parentId);
- while (parentId != 0) {
- parentId = categoryService.getCategory(parentId).getParentId();
- if (parentId > 0) {
- categoryArray.addFirst(parentId);
- }
- }
- spuVO.setCategoryIds(categoryArray);
+ respVO.setProductPropertyViews(productPropertyViews);
}
}
- return spuVO;
+ return respVO;
+ }
+
+ @Override
+ public ProductSpuRespVO getSpu(Long id) {
+ return ProductSpuConvert.INSTANCE.convert(productSpuMapper.selectById(id));
}
@Override
public List getSpuList(Collection ids) {
- return ProductSpuMapper.selectBatchIds(ids);
+ return productSpuMapper.selectBatchIds(ids);
+ }
+
+ @Override
+ public List getSpuList() {
+ return productSpuMapper.selectList();
}
@Override
public PageResult getSpuPage(ProductSpuPageReqVO pageReqVO) {
- PageResult spuVOs = ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO));
- // 查询 sku 的信息
- List spuIds = spuVOs.getList().stream().map(ProductSpuRespVO::getId).collect(Collectors.toList());
- List skus = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuIds(spuIds));
- // TODO @franky:使用 CollUtil 里的方法替代哈
- // TODO 芋艿:临时注释
-// Map> skuMap = skus.stream().collect(Collectors.groupingBy(ProductSkuRespVO::getSpuId));
-// // 将 spu 和 sku 进行组装
-// spuVOs.getList().forEach(p -> p.setSkus(skuMap.get(p.getId())));
- return spuVOs;
+ // 库存告警的 SPU 编号的集合
+ Set alarmStockSpuIds = null;
+ if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
+ alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkusByAlarmStock(), ProductSkuDO::getSpuId);
+ if (CollUtil.isEmpty(alarmStockSpuIds)) {
+ return PageResult.empty();
+ }
+ }
+ // 分页查询
+ return ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds));
}
@Override
public PageResult getSpuPage(AppSpuPageReqVO pageReqVO) {
- PageResult productSpuDOPageResult = ProductSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO));
+ // TODO 芋艿:貌似实现不太合理
+ PageResult productSpuDOPageResult = productSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO));
PageResult pageResult = new PageResult<>();
+ // TODO @芋艿 这里用convert如何解决
List collect = productSpuDOPageResult.getList()
.stream()
.map(ProductSpuConvert.INSTANCE::convertAppResp)
@@ -205,4 +209,10 @@ public class ProductSpuServiceImpl implements ProductSpuService {
return pageResult;
}
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateSpuStock(Map stockIncrCounts) {
+ stockIncrCounts.forEach((id, incCount) -> productSpuMapper.updateStock(id, incCount));
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java
index 93817d44cf..a6f8132ab3 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java
@@ -12,9 +12,10 @@ import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
-import java.util.Date;
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildLocalDateTime;
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;
@@ -106,7 +107,7 @@ public class ProductBrandServiceImplTest extends BaseDbUnitTest {
ProductBrandDO dbBrand = randomPojo(ProductBrandDO.class, o -> { // 等会查询到
o.setName("芋道源码");
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
- o.setCreateTime(buildTime(2022, 2, 1));
+ o.setCreateTime(buildLocalDateTime(2022, 2, 1));
});
brandMapper.insert(dbBrand);
// 测试 name 不匹配
@@ -114,12 +115,12 @@ public class ProductBrandServiceImplTest extends BaseDbUnitTest {
// 测试 status 不匹配
brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
- brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setCreateTime(buildTime(2022, 3, 1))));
+ brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setCreateTime(buildLocalDateTime(2022, 3, 1))));
// 准备参数
ProductBrandPageReqVO reqVO = new ProductBrandPageReqVO();
reqVO.setName("芋道");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
- reqVO.setCreateTime((new Date[]{buildTime(2022, 1, 1), buildTime(2022, 2, 25)}));
+ reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2022, 1, 1), buildLocalDateTime(2022, 2, 25)}));
// 调用
PageResult pageResult = brandService.getBrandPage(reqVO);
diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java
new file mode 100644
index 0000000000..87ce870151
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java
@@ -0,0 +1,98 @@
+package cn.iocoder.yudao.module.product.service.sku;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
+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.service.property.ProductPropertyService;
+import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
+import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH;
+import static java.util.Collections.singletonList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.verify;
+
+/**
+ * {@link ProductSkuServiceImpl} 的单元测试
+ *
+ * @author 芋道源码
+ */
+@Import(ProductSkuServiceImpl.class)
+public class ProductSkuServiceTest extends BaseDbUnitTest {
+
+ @Resource
+ private ProductSkuService productSkuService;
+
+ @Resource
+ private ProductSkuMapper productSkuMapper;
+
+ @MockBean
+ private ProductSpuService productSpuService;
+ @MockBean
+ private ProductPropertyService productPropertyService;
+ @MockBean
+ private ProductPropertyValueService productPropertyValueService;
+
+ @Test
+ public void testUpdateSkuStock_incrSuccess() {
+ // 准备参数
+ ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO()
+ .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(10)));
+ // mock 数据
+ productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> o.setId(1L).setSpuId(10L).setStock(20)));
+
+ // 调用
+ productSkuService.updateSkuStock(updateStockReqDTO);
+ // 断言
+ ProductSkuDO sku = productSkuMapper.selectById(1L);
+ assertEquals(sku.getStock(), 30);
+ verify(productSpuService).updateSpuStock(argThat(spuStockIncrCounts -> {
+ assertEquals(spuStockIncrCounts.size(), 1);
+ assertEquals(spuStockIncrCounts.get(10L), 10);
+ return true;
+ }));
+ }
+
+ @Test
+ public void testUpdateSkuStock_decrSuccess() {
+ // 准备参数
+ ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO()
+ .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(-10)));
+ // mock 数据
+ productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> o.setId(1L).setSpuId(10L).setStock(20)));
+
+ // 调用
+ productSkuService.updateSkuStock(updateStockReqDTO);
+ // 断言
+ ProductSkuDO sku = productSkuMapper.selectById(1L);
+ assertEquals(sku.getStock(), 10);
+ verify(productSpuService).updateSpuStock(argThat(spuStockIncrCounts -> {
+ assertEquals(spuStockIncrCounts.size(), 1);
+ assertEquals(spuStockIncrCounts.get(10L), -10);
+ return true;
+ }));
+ }
+
+ @Test
+ public void testUpdateSkuStock_decrFail() {
+ // 准备参数
+ ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO()
+ .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(-30)));
+ // mock 数据
+ productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> o.setId(1L).setSpuId(10L).setStock(20)));
+
+ // 调用并断言
+ AssertUtils.assertServiceException(() -> productSkuService.updateSkuStock(updateStockReqDTO),
+ SKU_STOCK_NOT_ENOUGH);
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/SkuServiceImplTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/SkuServiceImplTest.java
index 10ab8a3d12..1f04e9d357 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/SkuServiceImplTest.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/SkuServiceImplTest.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.product.service.sku;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
@@ -13,12 +14,14 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.assertNull;
+// TODO 芋艿:整合到 {@link ProductSkuServiceTest} 中
/**
* {@link ProductSkuServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(ProductSkuServiceImpl.class)
+@Disabled // TODO 芋艿:临时去掉
public class SkuServiceImplTest extends BaseDbUnitTest {
@Resource
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 bb0fa9d328..c6408d9656 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,406 @@
package cn.iocoder.yudao.module.product.service.spu;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+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.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 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.Disabled;
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.*;
+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.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+// TODO @芋艿:review 下单元测试
/**
-* {@link ProductSpuServiceImpl} 的单元测试类
-*
-* @author 芋道源码
-*/
+ * {@link ProductSpuServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
@Import(ProductSpuServiceImpl.class)
+@Disabled // TODO 芋艿:临时去掉
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;
+
+ 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() {
// 准备参数
- 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_alarmStock_empty() {
+ // 调用
+ ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
+ productSpuPageReqVO.setAlarmStock(true);
+
+ PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
+
+ PageResult