Commit c62da6a056331a8202c4d46d90a29a98ebc4f139

Authored by YunaiV
1 parent fb7915c9

mall:review 商品接口

Showing 23 changed files with 83 additions and 80 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/DictTypeConstants.java
... ... @@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.product.enums;
2 2  
3 3 /**
4 4 * product 字典类型的枚举类
  5 + *
5 6 * @author HUIHUI
6 7 */
7 8 public interface DictTypeConstants {
  9 +
8 10 String PRODUCT_UNIT = "product_unit"; // 商品单位
9 11 String PRODUCT_SPU_STATUS = "product_spu_status"; // 商品 SPU 状态
  12 +
10 13 }
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ProductConstants.java
... ... @@ -5,8 +5,9 @@ package cn.iocoder.yudao.module.product.enums;
5 5 *
6 6 * @author HUIHUI
7 7 */
8   -
9 8 public interface ProductConstants {
  9 +
  10 + // TODO @puhui999:这个变量,可以放到 CategoryDO 的实体里
10 11 /**
11 12 * 父分类编号 - 根分类
12 13 */
... ... @@ -15,14 +16,18 @@ public interface ProductConstants {
15 16 * 限定分类层级
16 17 */
17 18 int CATEGORY_LEVEL = 2;
  19 +
  20 + // TODO @puhui999:这个变量,必要项不大哈
18 21 /**
19 22 * SPU 分页 tab 个数
20 23 */
21 24 int SPU_TAB_COUNTS = 5;
  25 +
22 26 /**
23 27 * 警戒库存 TODO 警戒库存暂时为 10,后期需要使用常量或者数据库配置替换
24 28 */
25 29 int ALERT_STOCK = 10;
  30 +
26 31 /**
27 32 * 默认商品销量 TODO 默认商品销量为零
28 33 */
... ... @@ -31,4 +36,5 @@ public interface ProductConstants {
31 36 * 默认善品浏览量 TODO 默认浏览量为零
32 37 */
33 38 Integer BROWSE_COUNT = 0;
  39 +
34 40 }
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuPageTabEnum.java
... ... @@ -6,7 +6,7 @@ import lombok.Getter;
6 6  
7 7 import java.util.Arrays;
8 8  
9   -// TODO @puhui999:中英文之间要有空格; 商品 spu Tab 标签枚举;这个类可以改成 ProductSpuPageTabEnum 会更好一点哈;分页 Tab 的意思;
  9 +// TODO @puhui999:这种非关键的枚举,要不直接写在 ProductSpuPageReqVO 里。类似 public static final Integer TAB_TYPE_FOR_SALE = 0; // 出售中商品
10 10 /**
11 11 * 商品 spu Tabs 标签枚举类型
12 12 *
... ... @@ -21,6 +21,7 @@ public enum ProductSpuPageTabEnum implements IntArrayValuable {
21 21 SOLD_OUT(2,"已售空商品"),
22 22 ALERT_STOCK(3,"警戒库存"),
23 23 RECYCLE_BIN(4,"商品回收站");
  24 +
24 25 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuPageTabEnum::getType).toArray();
25 26 /**
26 27 * 状态
... ... @@ -35,4 +36,5 @@ public enum ProductSpuPageTabEnum implements IntArrayValuable {
35 36 public int[] array() {
36 37 return ARRAYS;
37 38 }
  39 +
38 40 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/ProductBrandController.java
... ... @@ -61,7 +61,7 @@ public class ProductBrandController {
61 61 public CommonResult<ProductBrandRespVO> getBrand(@RequestParam("id") Long id) {
62 62 ProductBrandDO brand = brandService.getBrand(id);
63 63 return success(ProductBrandConvert.INSTANCE.convert(brand));
64   - }
  64 + } // TODO @puhui999:方法和方法之间,要有空行。
65 65 @GetMapping("/list-all-simple")
66 66 @Operation(summary = "获取品牌精简信息列表", description = "主要用于前端的下拉选项")
67 67 public CommonResult<List<ProductBrandSimpleRespVO>> getSimpleUserList() {
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandSimpleRespVO.java
... ... @@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
5 5 import lombok.Data;
6 6 import lombok.NoArgsConstructor;
7 7  
  8 +// TODO @puhui999:class 类的开始和结束,都要有一个空行哈。
8 9 @Schema(description = "管理后台 - 品牌精简信息 Response VO")
9 10 @Data
10 11 @NoArgsConstructor
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
2 2  
3   -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
4   -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
5 3 import io.swagger.v3.oas.annotations.media.Schema;
6 4 import lombok.AllArgsConstructor;
7 5 import lombok.Data;
... ... @@ -57,6 +55,7 @@ public class ProductSkuBaseVO {
57 55 @Schema(description = "二级分销的佣金,单位:分", example = "1024")
58 56 private Integer subCommissionSecondPrice;
59 57  
  58 + // TODO @puhui999:这里要写 swagger 注解哈
60 59 /**
61 60 * 商品属性
62 61 */
... ... @@ -67,27 +66,19 @@ public class ProductSkuBaseVO {
67 66  
68 67 /**
69 68 * 属性编号
70   - * 关联 {@link ProductPropertyDO#getId()}
71 69 */
72 70 private Long propertyId;
73 71 /**
74 72 * 属性名字
75   - * 冗余 {@link ProductPropertyDO#getName()}
76   - *
77   - * 注意:每次属性名字发生变化时,需要更新该冗余
78 73 */
79 74 private String propertyName;
80 75  
81 76 /**
82 77 * 属性值编号
83   - * 关联 {@link ProductPropertyValueDO#getId()}
84 78 */
85 79 private Long valueId;
86 80 /**
87 81 * 属性值名字
88   - * 冗余 {@link ProductPropertyValueDO#getName()}
89   - *
90   - * 注意:每次属性值名字发生变化时,需要更新该冗余
91 82 */
92 83 private String valueName;
93 84  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
5 7  
6   -import javax.validation.constraints.NotNull;
7 8 import java.util.List;
8 9  
9 10 @Schema(description = "管理后台 - 商品 SKU 创建/更新 Request VO")
... ... @@ -12,6 +13,7 @@ import java.util.List;
12 13 @ToString(callSuper = true)
13 14 public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO {
14 15  
  16 + // TODO @puhui999:是不是可以抽到父类里?
15 17 /**
16 18 * 属性数组
17 19 */
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
... ... @@ -2,14 +2,11 @@ package cn.iocoder.yudao.module.product.controller.admin.spu;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
6 5 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
7 6 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
8 7 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
9 8 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
10 9 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
11   -import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
12   -import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
13 10 import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
14 11 import io.swagger.v3.oas.annotations.Operation;
15 12 import io.swagger.v3.oas.annotations.Parameter;
... ... @@ -22,14 +19,10 @@ import javax.annotation.Resource;
22 19 import javax.servlet.http.HttpServletResponse;
23 20 import javax.validation.Valid;
24 21 import java.io.IOException;
25   -import java.util.ArrayList;
26   -import java.util.Collection;
27 22 import java.util.List;
28 23 import java.util.Map;
29 24  
30 25 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
31   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
32   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
33 26 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
34 27  
35 28 /**
... ... @@ -101,7 +94,7 @@ public class ProductSpuController {
101 94 return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO)));
102 95 }
103 96  
104   - // TODO @tuihui999:get-count;另外,url 使用 - 拆分 fix
  97 + // TODO @puhui999:方法名改成 getSpuCount,只是用于 tab 哈,这样更抽象一点。
105 98 @GetMapping("/get-count")
106 99 @Operation(summary = "获得商品 SPU 分页 tab count")
107 100 @PreAuthorize("@ss.hasPermission('product:spu:query')")
... ... @@ -110,7 +103,7 @@ public class ProductSpuController {
110 103 }
111 104  
112 105 @GetMapping("/export")
113   - @Operation(summary = "导出用户")
  106 + @Operation(summary = "导出商品")
114 107 @PreAuthorize("@ss.hasPermission('product:spu:export')")
115 108 @OperateLog(type = EXPORT)
116 109 public void exportUserList(@Validated ProductSpuExportReqVO reqVO,
... ... @@ -118,6 +111,7 @@ public class ProductSpuController {
118 111 List<ProductSpuDO> spuList = productSpuService.getSpuList(reqVO);
119 112 // 导出 Excel
120 113 List<ProductSpuExcelVO> datas = ProductSpuConvert.INSTANCE.convertList03(spuList);
121   - ExcelUtils.write(response, "商品spu.xls", "数据", ProductSpuExcelVO.class, datas);
  114 + ExcelUtils.write(response, "商品列表.xls", "数据", ProductSpuExcelVO.class, datas);
122 115 }
  116 +
123 117 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
2 2  
3   -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
4 3 import io.swagger.v3.oas.annotations.media.Schema;
5 4 import lombok.Data;
6 5  
... ... @@ -97,14 +96,14 @@ public class ProductSpuBaseVO {
97 96 @NotNull(message = "商品赠送积分不能为空")
98 97 private Integer giveIntegral;
99 98  
100   - @Schema(description = "赠送的优惠劵编号的数组") // TODO 这块前端还未实现
  99 + @Schema(description = "赠送的优惠劵编号的数组", example = "[1, 10]") // TODO 这块前端还未实现
101 100 private List<Long> giveCouponTemplateIds;
102 101  
103   - @Schema(description = "分销类型", example = "true")
  102 + @Schema(description = "分销类型", required = true, example = "true")
104 103 @NotNull(message = "商品分销类型不能为空")
105 104 private Boolean subCommissionType;
106 105  
107   - @Schema(description = "活动展示顺序", example = "[1、3、2、4、5]") // TODO 这块前端还未实现
  106 + @Schema(description = "活动展示顺序", example = "[1, 3, 2, 4, 5]") // TODO 这块前端还未实现
108 107 private List<Integer> activityOrders;
109 108  
110 109 // ========== 统计相关字段 =========
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java
... ... @@ -6,7 +6,6 @@ import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
8 8  
9   -import java.time.LocalDateTime;
10 9 import java.util.List;
11 10  
12 11 /**
... ... @@ -21,7 +20,9 @@ import java.util.List;
21 20 @ToString(callSuper = true)
22 21 public class ProductSpuDetailRespVO extends ProductSpuBaseVO {
23 22  
24   - @Schema(description = "spuId")
  23 + // TODO @puhui999:swagger 的 required 和 example 写下
  24 +
  25 + @Schema(description = "商品 SPU 编号")
25 26 private Long id;
26 27  
27 28 @Schema(description = "商品销量")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuExportReqVO.java
... ... @@ -11,11 +11,13 @@ import org.springframework.format.annotation.DateTimeFormat;
11 11 import java.time.LocalDateTime;
12 12  
13 13 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
14 15 @Schema(description = "管理后台 - 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的")
15 16 @Data
16 17 @NoArgsConstructor
17 18 @AllArgsConstructor
18 19 public class ProductSpuExportReqVO {
  20 +
19 21 @Schema(description = "商品名称", example = "yutou")
20 22 private String name;
21 23  
... ... @@ -29,4 +31,5 @@ public class ProductSpuExportReqVO {
29 31 @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
30 32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
31 33 private LocalDateTime[] createTime;
  34 +
32 35 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
2 2  
3   -import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
4 3 import io.swagger.v3.oas.annotations.media.Schema;
5 4 import lombok.Data;
6 5 import lombok.EqualsAndHashCode;
... ... @@ -19,6 +18,8 @@ import java.time.LocalDateTime;
19 18 @ToString(callSuper = true)
20 19 public class ProductSpuRespVO extends ProductSpuBaseVO {
21 20  
  21 + // TODO @puhui999:swagger 的 required 和 example 写下
  22 +
22 23 @Schema(description = "spuId")
23 24 private Long id;
24 25  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
2 2  
3   -import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
4 3 import io.swagger.v3.oas.annotations.media.Schema;
5 4 import lombok.Data;
6   -import lombok.EqualsAndHashCode;
7 5 import lombok.ToString;
8 6  
9 7 /**
... ... @@ -16,6 +14,8 @@ import lombok.ToString;
16 14 @ToString(callSuper = true)
17 15 public class ProductSpuSimpleRespVO {
18 16  
  17 + // TODO @puhui999:swagger 的 required 和 example 写下
  18 +
19 19 @Schema(description = "主键")
20 20 private Long id;
21 21  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateReqVO.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
5   -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuPageTabEnum;
6 5 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
7 6 import io.swagger.v3.oas.annotations.media.Schema;
8 7 import lombok.Data;
... ... @@ -11,7 +10,6 @@ import lombok.ToString;
11 10  
12 11 import javax.validation.Valid;
13 12 import javax.validation.constraints.NotNull;
14   -import java.time.LocalDateTime;
15 13 import java.util.List;
16 14  
17 15 /**
... ... @@ -25,6 +23,8 @@ import java.util.List;
25 23 @ToString(callSuper = true)
26 24 public class ProductSpuUpdateReqVO extends ProductSpuBaseVO {
27 25  
  26 + // TODO @puhui999:swagger 的 required 和 example 写下
  27 +
28 28 @Schema(description = "商品编号", required = true, example = "1")
29 29 @NotNull(message = "商品编号不能为空")
30 30 private Long id;
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/brand/ProductBrandConvert.java
... ... @@ -26,7 +26,9 @@ public interface ProductBrandConvert {
26 26 ProductBrandDO convert(ProductBrandUpdateReqVO bean);
27 27  
28 28 ProductBrandRespVO convert(ProductBrandDO bean);
  29 +
29 30 List<ProductBrandSimpleRespVO> convertList1(List<ProductBrandDO> list);
  31 +
30 32 List<ProductBrandRespVO> convertList(List<ProductBrandDO> list);
31 33  
32 34 PageResult<ProductBrandRespVO> convertPage(PageResult<ProductBrandDO> page);
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
1 1 package cn.iocoder.yudao.module.product.convert.spu;
2   -import java.time.LocalDateTime;
3 2  
4 3 import cn.hutool.core.collection.CollUtil;
5 4 import cn.hutool.core.util.StrUtil;
... ... @@ -10,8 +9,8 @@ import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
10 9 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
11 10 import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
12 11 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
13   -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
14 12 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO;
  13 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
15 14 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
16 15 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
17 16 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
... ... @@ -52,6 +51,8 @@ public interface ProductSpuConvert {
52 51 List<ProductSpuRespDTO> convertList2(List<ProductSpuDO> list);
53 52  
54 53 List<ProductSpuSimpleRespVO> convertList02(List<ProductSpuDO> list);
  54 +
  55 + // TODO @puhui999:部分属性,可以通过 mapstruct 的 @Mapping(source = , target = , ) 映射转换,可以查下文档
55 56 default List<ProductSpuExcelVO> convertList03(List<ProductSpuDO> list){
56 57 ArrayList<ProductSpuExcelVO> spuExcelVOs = new ArrayList<>();
57 58 list.forEach((spu)->{
... ... @@ -95,6 +96,7 @@ public interface ProductSpuConvert {
95 96 }
96 97 ProductSpuDetailRespVO convert03(ProductSpuDO spu);
97 98  
  99 + // TODO @puhui999:下面两个没用到,是不是删除呀?
98 100 List<ProductSkuRespVO> convertList04(List<ProductSkuDO> skus);
99 101  
100 102 ProductPropertyValueDetailRespVO convert04(ProductPropertyValueDetailRespBO propertyValue);
... ... @@ -142,11 +144,13 @@ public interface ProductSpuConvert {
142 144  
143 145 AppProductPropertyValueDetailRespVO convertForGetSpuDetail(ProductPropertyValueDetailRespBO propertyValue);
144 146  
145   - default ProductSpuDetailRespVO convertForSpuDetailRespVO(ProductSpuDO spu, List<ProductSkuDO> skus, Function<Set<Long>, List<ProductPropertyValueDetailRespBO>> func) {
  147 + default ProductSpuDetailRespVO convertForSpuDetailRespVO(ProductSpuDO spu, List<ProductSkuDO> skus,
  148 + Function<Set<Long>, List<ProductPropertyValueDetailRespBO>> func) {
146 149 ProductSpuDetailRespVO productSpuDetailRespVO = convert03(spu);
  150 + // TODO @puhui999:if return 哈,减少嵌套层数。
147 151 if (CollUtil.isNotEmpty(skus)) {
148 152 List<ProductSkuRespVO> skuVOs = ProductSkuConvert.INSTANCE.convertList(skus);
149   - // fix:统一模型,即使是单规格,也查询下,如若Properties为空报错则为单属性不做处理
  153 + // fix:统一模型,即使是单规格,也查询下,如若 Properties 为空报错则为单属性不做处理
150 154 try {
151 155 // 获取所有的属性值 id
152 156 Set<Long> valueIds = skus.stream().flatMap(p -> p.getProperties().stream())
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/ProductBrandMapper.java
... ... @@ -31,6 +31,7 @@ public interface ProductBrandMapper extends BaseMapperX&lt;ProductBrandDO&gt; {
31 31 return selectOne(ProductBrandDO::getName, name);
32 32 }
33 33  
  34 + // TODO @puhui999:) { 中间要有空格哈。
34 35 default List<ProductBrandDO> selectListByStatus(Integer status){
35 36 return selectList(ProductBrandDO::getStatus,status);
36 37 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
... ... @@ -10,13 +10,10 @@ import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReq
10 10 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
11 11 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
12 12 import cn.iocoder.yudao.module.product.enums.ProductConstants;
13   -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
14 13 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuPageTabEnum;
15   -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  14 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
16 15 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
17   -import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
18 16 import org.apache.ibatis.annotations.Mapper;
19   -import org.apache.poi.ss.formula.functions.T;
20 17  
21 18 import java.util.List;
22 19 import java.util.Objects;
... ... @@ -26,7 +23,7 @@ import java.util.Set;
26 23 public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
27 24  
28 25 /**
29   - * 获取 商品 SPU 分页列表数据
  26 + * 获取商品 SPU 分页列表数据
30 27 *
31 28 * @param reqVO 分页请求参数
32 29 * @return 商品 SPU 分页列表数据
... ... @@ -43,11 +40,14 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
43 40 }
44 41  
45 42 /**
46   - * 获取库存小于value且状态不等于status的的个数
  43 + * 获取库存小于 value ,且状态不等于 status 的的个数
  44 + *
  45 + * @return 个数
47 46 */
48 47 default Long selectCountByStockAndStatus() {
49 48 LambdaQueryWrapperX<ProductSpuDO> queryWrapper = new LambdaQueryWrapperX<>();
50 49 queryWrapper.le(ProductSpuDO::getStock, ProductConstants.ALERT_STOCK)
  50 + // TODO @puhui999:IN 另外两个状态,会不会好点哈。尽量不用 !=
51 51 // 如果库存触发警戒库存且状态为回收站的话则不计入触发警戒库存的个数
52 52 .and(q -> q.ne(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()));
53 53 return selectCount(queryWrapper);
... ... @@ -111,6 +111,7 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
111 111 return selectList(queryWrapper);
112 112 }
113 113  
  114 + // TODO @puhui999:应该不太适合 validate 验证,应该是补充条件,例如说 appendTabQuery
114 115 /**
115 116 * 验证选项卡类型构建条件
116 117 *
... ... @@ -118,8 +119,8 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
118 119 * @param queryWrapper 查询条件
119 120 */
120 121 static void validateTabType(Integer tabType, LambdaQueryWrapperX<ProductSpuDO> queryWrapper) {
  122 + // 出售中商品 TODO puhui999:这样好点
121 123 if (ObjectUtil.equals(ProductSpuPageTabEnum.FOR_SALE.getType(), tabType)) {
122   - // 出售中商品
123 124 queryWrapper.eqIfPresent(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus());
124 125 }
125 126 if (ObjectUtil.equals(ProductSpuPageTabEnum.IN_WAREHOUSE.getType(), tabType)) {
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
... ... @@ -111,6 +111,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
111 111 if (Objects.equals(id, ProductConstants.PARENT_ID_NULL)) {
112 112 return 0;
113 113 }
  114 + // TODO @puhui999:for 的原因,是因为避免脏数据,导致可能的死循环。一般不会超过 100 层哈
114 115 int level = 1;
115 116 // fix: 循环次数不确定改为while循环
116 117 while (true){
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
1 1 package cn.iocoder.yudao.module.product.service.spu;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.util.ObjectUtil;
5 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8   -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
9 7 import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
10 8 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
11   -import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
12 9 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
13 10 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
14   -import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
15 11 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
16 12 import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
17 13 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
18 14 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
19 15 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
20 16 import cn.iocoder.yudao.module.product.enums.ProductConstants;
21   -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
22 17 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuPageTabEnum;
  18 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
23 19 import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
24 20 import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
25 21 import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
26   -import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
27 22 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
28 23 import org.springframework.context.annotation.Lazy;
29 24 import org.springframework.stereotype.Service;
... ... @@ -32,7 +27,6 @@ import org.springframework.validation.annotation.Validated;
32 27  
33 28 import javax.annotation.Resource;
34 29 import java.util.*;
35   -import java.util.stream.Collectors;
36 30  
37 31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
38 32 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
... ... @@ -63,11 +57,11 @@ public class ProductSpuServiceImpl implements ProductSpuService {
63 57 @Override
64 58 @Transactional(rollbackFor = Exception.class)
65 59 public Long createSpu(ProductSpuCreateReqVO createReqVO) {
66   - // 校验分类 TODO puhui999:暂不清楚为什么只能选择第三层的结点;芋艿:改成二级分类,因为商品只能放在叶子节点级别;fix
  60 + // 校验分类、品牌
67 61 validateCategory(createReqVO.getCategoryId());
68 62 brandService.validateProductBrand(createReqVO.getBrandId());
69   - List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = createReqVO.getSkus();
70 63 // 校验 SKU
  64 + List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = createReqVO.getSkus();
71 65 productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());
72 66 ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
73 67 // 初始化 SPU 中 SKU 相关属性
... ... @@ -86,13 +80,13 @@ public class ProductSpuServiceImpl implements ProductSpuService {
86 80 public void updateSpu(ProductSpuUpdateReqVO updateReqVO) {
87 81 // 校验 SPU 是否存在
88 82 validateSpuExists(updateReqVO.getId());
89   - // 校验分类
  83 + // 校验分类、品牌
90 84 validateCategory(updateReqVO.getCategoryId());
91   - // 校验品牌
92 85 brandService.validateProductBrand(updateReqVO.getBrandId());
93 86 // 校验SKU
94 87 List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = updateReqVO.getSkus();
95 88 productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType());
  89 + // TODO @puhui999:可以校验逻辑,和更新逻辑,中间有个空行,这样会发现,哟 这里到了关键逻辑啦,更有层次感
96 90 // 更新 SPU
97 91 ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);
98 92 initSpuFromSkus(updateObj, skuSaveReqList);
... ... @@ -111,17 +105,19 @@ public class ProductSpuServiceImpl implements ProductSpuService {
111 105 private void initSpuFromSkus(ProductSpuDO spu, List<ProductSkuCreateOrUpdateReqVO> skus) {
112 106 // 断言,避免告警
113 107 assert skus.size() > 0;
114   - // 获取sku单价最低的商品
  108 + // 获取 sku 单价最低的商品
  109 + // TODO @puhui999:vo 改成 sku 会更好。vo dto 只是我们用来区分的,如果能区分的情况下,用更明确的名字会更好。
  110 +// CollectionUtils.getMinValue(); TODO @puhui999:可以用这个方法,常见的 stream 操作,封装成方法,让逻辑更简洁
115 111 ProductSkuCreateOrUpdateReqVO vo = skus.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateReqVO::getPrice)).get();
116   - // sku单价最低的商品的价格
  112 + // sku 单价最低的商品的价格
117 113 spu.setPrice(vo.getPrice());
118   - // sku单价最低的商品的市场价格
  114 + // sku 单价最低的商品的市场价格
119 115 spu.setMarketPrice(vo.getMarketPrice());
120 116 // sku单价最低的商品的成本价格
121 117 spu.setCostPrice(vo.getCostPrice());
122 118 // sku单价最低的商品的条形码
123 119 spu.setBarCode(vo.getBarCode());
124   - // skus库存总数
  120 + // skus 库存总数
125 121 spu.setStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
126 122 // 若是 spu 已有状态则不处理
127 123 if (spu.getStatus() == null) {
... ... @@ -233,6 +229,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
233 229 }
234 230 // 查询商品 SKU
235 231 List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
  232 + // TODO @puhui999:感觉还是查询好 productPropertyValueService,然后 propertyId 可以交给 convert 处理下即可。
236 233 return ProductSpuConvert.INSTANCE.convertForSpuDetailRespVO(spu, skus, productPropertyValueService::getPropertyValueDetailList);
237 234 }
238 235  
... ... @@ -249,7 +246,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
249 246  
250 247 @Override
251 248 public Map<Integer, Long> getTabsCount() {
252   - // TODO @puhui999:map =》;尽量避免出现 map 这种命名,无命名含义哈 fix
253 249 Map<Integer, Long> counts = new HashMap<>(ProductConstants.SPU_TAB_COUNTS);
254 250 // 查询销售中的商品数量
255 251 counts.put(ProductSpuPageTabEnum.FOR_SALE.getType(), productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()));
... ... @@ -258,8 +254,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
258 254 // 查询售空的商品数量
259 255 counts.put(ProductSpuPageTabEnum.SOLD_OUT.getType(), productSpuMapper.selectCount(ProductSpuDO::getStock, 0));
260 256 // 查询触发警戒库存的商品数量
261   - // TODO @puhui999:要有空格;, productSpuMapper fix
262   - // TODO @puhui999:Service 不要有 Mapper 的逻辑;想想咋抽象一下哈 fix:调整为在 productSpuMapper 中书写逻辑
263 257 counts.put(ProductSpuPageTabEnum.ALERT_STOCK.getType(), productSpuMapper.selectCountByStockAndStatus());
264 258 // 查询回收站中的商品数量
265 259 counts.put(ProductSpuPageTabEnum.RECYCLE_BIN.getType(), productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()));
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImplTest.java
... ... @@ -40,10 +40,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
40 40 @Test
41 41 public void testCreateCategory_success() {
42 42 // 准备参数
43   - ProductCategoryCreateReqVO reqVO = randomPojo(ProductCategoryCreateReqVO.class,o -> {
44   - // 设置PC端图片可为空 TODO 数据库没有这个字段
45   - //o.setBigPicUrl(null);
46   - });
  43 + ProductCategoryCreateReqVO reqVO = randomPojo(ProductCategoryCreateReqVO.class);
47 44  
48 45 // mock 父类
49 46 ProductCategoryDO parentProductCategory = randomPojo(ProductCategoryDO.class, o -> {
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java
1 1 package cn.iocoder.yudao.module.product.service.sku;
2 2  
3 3 import cn.hutool.core.util.RandomUtil;
4   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
6 5 import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
7 6 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
... ... @@ -50,6 +49,7 @@ public class ProductSkuServiceTest extends BaseDbUnitTest {
50 49 @MockBean
51 50 private ProductPropertyValueService productPropertyValueService;
52 51  
  52 + // TODO @puhui999:是不是可以删除这 2 方法
53 53 public Long generateId() {
54 54 return RandomUtil.randomLong(100000, 999999);
55 55 }
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
... ... @@ -6,13 +6,12 @@ import cn.hutool.core.util.RandomUtil;
6 6 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 8 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
9   -import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryCreateReqVO;
10 9 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
11   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
12   -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
  10 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
  11 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
  12 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO;
  13 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO;
13 14 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
14   -import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
15   -import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
16 15 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
17 16 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
18 17 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuPageTabEnum;
... ... @@ -23,21 +22,20 @@ import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
23 22 import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
24 23 import cn.iocoder.yudao.module.product.service.sku.ProductSkuServiceImpl;
25 24 import com.google.common.collect.Lists;
26   -import org.apache.poi.ss.formula.functions.T;
27 25 import org.junit.jupiter.api.Assertions;
28   -import org.junit.jupiter.api.Disabled;
29 26 import org.junit.jupiter.api.Test;
30   -import org.mockito.Mockito;
31 27 import org.springframework.boot.test.mock.mockito.MockBean;
32 28 import org.springframework.context.annotation.Import;
33 29  
34 30 import javax.annotation.Resource;
35 31 import java.math.RoundingMode;
36   -import java.util.*;
  32 +import java.util.ArrayList;
  33 +import java.util.Date;
  34 +import java.util.List;
  35 +import java.util.Map;
37 36 import java.util.stream.Collectors;
38 37 import java.util.stream.Stream;
39 38  
40   -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
41 39 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
42 40 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
43 41 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
... ... @@ -83,6 +81,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
83 81  
84 82 public int generaInt(){return RandomUtil.randomInt(1,9999999);}
85 83  
  84 + // TODO @芋艿:单测后续 review 哈
  85 +
86 86 @Test
87 87 public void testCreateSpu_success() {
88 88 // 准备参数
... ...