Commit 70816371e51ae57c3b85ee236c28b437dfd65c81

Authored by puhui999
1 parent 6428f0fc

初步完成商品CRUD

Showing 16 changed files with 132 additions and 183 deletions
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
... ... @@ -50,4 +50,14 @@ public class ProductSkuBaseVO {
50 50  
51 51 @Schema(description = "商品体积", example = "1024") // 单位:m^3 平米
52 52 private Double volume;
  53 + /**
  54 + * 一级分销的佣金,单位:分
  55 + */
  56 + @Schema(description = "一级分销的佣金", example = "1024")
  57 + private Integer subCommissionFirstPrice;
  58 + /**
  59 + * 二级分销的佣金,单位:分
  60 + */
  61 + @Schema(description = "二级分销的佣金", example = "1024")
  62 + private Integer subCommissionSecondPrice;
53 63 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
... ... @@ -94,7 +94,7 @@ public class ProductSpuController {
94 94 @GetMapping("/page")
95 95 @Operation(summary = "获得商品 SPU 分页")
96 96 @PreAuthorize("@ss.hasPermission('product:spu:query')")
97   - public CommonResult<PageResult<ProductSpuRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
  97 + public CommonResult<PageResult<ProductSpuPageRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
98 98 return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO)));
99 99 }
100 100  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
... ... @@ -38,16 +38,11 @@ public class ProductSpuBaseVO {
38 38 @NotEmpty(message = "商品详情不能为空")
39 39 private String description;
40 40  
41   - @Schema(description = "商品条码(一维码)", required = true, example = "芋道")
42   - @NotEmpty(message = "商品条码(一维码)不能为空")
43   - private String barCode;
44   -
45 41 @Schema(description = "商品分类编号", required = true, example = "芋道")
46   - @NotEmpty(message = "商品分类编号不能为空")
  42 + @NotNull(message = "商品分类编号不能为空")
47 43 private Long categoryId;
48 44  
49 45 @Schema(description = "商品品牌编号", required = true, example = "芋道")
50   - @NotEmpty(message = "商品品牌编号不能为空")
51 46 private Long brandId;
52 47  
53 48 @Schema(description = "商品封面图", required = true, example = "芋道")
... ... @@ -55,99 +50,71 @@ public class ProductSpuBaseVO {
55 50 private String picUrl;
56 51  
57 52 @Schema(description = "商品轮播图", required = true)
58   - @NotEmpty(message = "商品轮播图不能为空")
59 53 private List<String> sliderPicUrls;
60 54  
61 55 @Schema(description = "商品视频")
62 56 private String videoUrl;
63 57  
64 58 @Schema(description = "单位", required = true, example = "1")
65   - @NotEmpty(message = "商品单位不能为空")
  59 + @NotNull(message = "商品单位不能为空")
66 60 private Integer unit;
67 61  
68 62 @Schema(description = "排序字段", required = true, example = "1")
69   - @NotEmpty(message = "商品排序字段不能为空")
  63 + @NotNull(message = "商品排序字段不能为空")
70 64 private Integer sort;
71 65  
72   - @Schema(description = "商品状态", required = true, example = "1")
73   - @NotEmpty(message = "商品状态不能为空")
74   - private Integer status;
75   -
76 66 // ========== SKU 相关字段 =========
77 67  
78 68 @Schema(description = "规格类型", required = true, example = "true")
79   - @NotEmpty(message = "商品规格类型不能为空")
  69 + @NotNull(message = "商品规格类型不能为空")
80 70 private Boolean specType;
81 71  
82   - @Schema(description = "商品价格", required = true, example = "1212")
83   - @NotEmpty(message = "商品价格不能为空")
84   - private Integer price;
85   -
86   - @Schema(description = "市场价", required = true, example = "3")
87   - @NotEmpty(message = "商品市场价不能为空")
88   - private Integer marketPrice;
89   -
90   - @Schema(description = "成本价", required = true, example = "12")
91   - @NotEmpty(message = "商品成本价不能为空")
92   - private Integer costPrice;
93   -
94   - @Schema(description = "库存", required = true, example = "111")
95   - @NotEmpty(message = "商品库存不能为空")
96   - private Integer stock;
97   -
98 72 // ========== 物流相关字段 =========
99 73  
100 74 @Schema(description = "物流配置模板编号", required = true, example = "111")
101   - @NotEmpty(message = "物流配置模板编号不能为空")
  75 + @NotNull(message = "物流配置模板编号不能为空")
102 76 private Long deliveryTemplateId;
103 77  
104 78 // ========== 营销相关字段 =========
105 79  
106 80 @Schema(description = "是否热卖推荐", required = true, example = "true")
107   - @NotEmpty(message = "商品推荐不能为空")
  81 + @NotNull(message = "商品推荐不能为空")
108 82 private Boolean recommendHot;
109 83  
110 84 @Schema(description = "是否优惠推荐", required = true, example = "true")
111   - @NotEmpty(message = "商品推荐不能为空")
  85 + @NotNull(message = "商品推荐不能为空")
112 86 private Boolean recommendBenefit;
113 87  
114 88 @Schema(description = "是否精品推荐", required = true, example = "true")
115   - @NotEmpty(message = "商品推荐不能为空")
  89 + @NotNull(message = "商品推荐不能为空")
116 90 private Boolean recommendBest;
117 91  
118 92 @Schema(description = "是否新品推荐", required = true, example = "true")
119   - @NotEmpty(message = "商品推荐不能为空")
  93 + @NotNull(message = "商品推荐不能为空")
120 94 private Boolean recommendNew;
121 95  
122 96 @Schema(description = "是否优品推荐", required = true, example = "true")
123   - @NotEmpty(message = "商品推荐不能为空")
  97 + @NotNull(message = "商品推荐不能为空")
124 98 private Boolean recommendGood;
125 99  
126 100 @Schema(description = "赠送积分", required = true, example = "111")
127   - @NotEmpty(message = "商品赠送积分不能为空")
  101 + @NotNull(message = "商品赠送积分不能为空")
128 102 private Integer giveIntegral;
129 103  
130   - @Schema(description = "赠送的优惠劵编号的数组")
  104 + @Schema(description = "赠送的优惠劵编号的数组") // TODO 这块前端还未实现
131 105 private List<Long> giveCouponTemplateIds;
132 106  
133 107 @Schema(description = "分销类型")
  108 + @NotNull(message = "商品分销类型不能为空")
134 109 private Boolean subCommissionType;
135 110  
136   - @Schema(description = "活动展示顺序")
  111 + @Schema(description = "活动展示顺序") // TODO 这块前端还未实现
137 112 private List<Integer> activityOrders;
138 113  
139 114 // ========== 统计相关字段 =========
140 115  
141   - @Schema(description = "商品销量", required = true, example = "芋道")
142   - @NotEmpty(message = "商品销量不能为空")
143   - private Integer salesCount;
144   -
145 116 @Schema(description = "虚拟销量", required = true, example = "芋道")
146   - @NotEmpty(message = "商品虚拟销量不能为空")
147 117 private Integer virtualSalesCount;
148 118  
149   - @Schema(description = "浏览量", required = true, example = "芋道")
150   - @NotEmpty(message = "商品浏览量不能为空")
151   - private Integer browseCount;
152 119  
153 120 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
... ... @@ -15,31 +15,7 @@ public class ProductSpuPageReqVO extends PageParam {
15 15 @Schema(description = "商品名称", example = "yutou")
16 16 private String name;
17 17  
18   - @Schema(description = "商品编码", example = "yudaoyuanma")
19   - private String code;
20   -
21 18 @Schema(description = "分类编号", example = "1")
22 19 private Long categoryId;
23 20  
24   - @Schema(description = "商品品牌编号", example = "1")
25   - private Long brandId;
26   -
27   - @Schema(description = "上下架状态", example = "1")
28   - private Integer status;
29   -
30   - @Schema(description = "销量最小值", example = "1")
31   - private Integer salesCountMin;
32   -
33   - @Schema(description = "销量最大值", example = "1024")
34   - private Integer salesCountMax;
35   -
36   - @Schema(description = "市场价最小值", example = "1")
37   - private Integer marketPriceMin;
38   -
39   - @Schema(description = "市场价最大值", example = "1024")
40   - private Integer marketPriceMax;
41   -
42   - @Schema(description = "是否库存告警", example = "true")
43   - private Boolean alarmStock;
44   -
45 21 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.FieldFill;
  4 +import com.baomidou.mybatisplus.annotation.TableField;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 商品 SPU 分页 response VO")
  11 +@Data
  12 +public class ProductSpuPageRespVO {
  13 + @Schema(description = "spuId", example = "1")
  14 + private Long id;
  15 + @Schema(description = "商品封面图", example = "1")
  16 + private String picUrl;
  17 + @Schema(description = "商品名称", example = "1")
  18 + private String name;
  19 + @Schema(description = "商品价格", example = "1")
  20 + private Integer price;
  21 + @Schema(description = "商品销量", example = "1")
  22 + private Integer salesCount;
  23 + @Schema(description = "商品排序", example = "1")
  24 + private Integer stock;
  25 + @Schema(description = "商品封面图", example = "1")
  26 + private Integer sort;
  27 + @Schema(description = "商品创建时间", example = "1")
  28 + private LocalDateTime createTime;
  29 + @Schema(description = "商品状态", example = "1")
  30 + private Integer status;
  31 +}
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
... ... @@ -19,22 +19,4 @@ public class ProductSpuRespVO extends ProductSpuBaseVO {
19 19 @Schema(description = "创建时间")
20 20 private LocalDateTime createTime;
21 21  
22   - // ========== SKU 相关字段 =========
23   -
24   - @Schema(description = "库存", required = true, example = "true")
25   - private Integer totalStock;
26   -
27   - @Schema(description = " 最小价格,单位使用:分", required = true, example = "1024")
28   - private Integer minPrice;
29   -
30   - @Schema(description = "最大价格,单位使用:分", required = true, example = "1024")
31   - private Integer maxPrice;
32   -
33   - @Schema(description = "商品销量", example = "1024")
34   - private Integer salesCount;
35   -
36   - // ========== 统计相关字段 =========
37   -
38   - @Schema(description = "点击量", example = "1024")
39   - private Integer clickCount;
40 22 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
... ... @@ -35,9 +35,8 @@ public interface ProductSkuConvert {
35 35  
36 36 List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list);
37 37  
38   - default List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId, String spuName) {
  38 + default List<ProductSkuDO> convertList06(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId) {
39 39 List<ProductSkuDO> result = convertList06(list);
40   - // result.forEach(item -> item.setSpuId(spuId).setSpuName(spuName)); TODO ProductSkuDO中已经没有name相关属性
41 40 result.forEach(item -> item.setSpuId(spuId));
42 41 return result;
43 42 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
... ... @@ -38,7 +38,7 @@ public interface ProductSpuConvert {
38 38  
39 39 List<ProductSpuDO> convertList(List<ProductSpuDO> list);
40 40  
41   - PageResult<ProductSpuRespVO> convertPage(PageResult<ProductSpuDO> page);
  41 + PageResult<ProductSpuPageRespVO> convertPage(PageResult<ProductSpuDO> page);
42 42  
43 43 ProductSpuPageReqVO convert(AppProductSpuPageReqVO bean);
44 44  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java
... ... @@ -116,19 +116,19 @@ public class ProductSpuDO extends TenantBaseDO {
116 116 /**
117 117 * 商品价格,单位使用:分
118 118 *
119   - * 基于其对应的 {@link ProductSkuDO#getPrice()} 最小值
  119 + * 基于其对应的 {@link ProductSkuDO#getPrice()} sku单价最低的商品的
120 120 */
121 121 private Integer price;
122 122 /**
123 123 * 市场价,单位使用:分
124 124 *
125   - * 基于其对应的 {@link ProductSkuDO#getMarketPrice()} 最大值 TODO 芋艿:待确定最大还是最小
  125 + * 基于其对应的 {@link ProductSkuDO#getMarketPrice()} sku单价最低的商品的
126 126 */
127 127 private Integer marketPrice;
128 128 /**
129 129 * 成本价,单位使用:分
130 130 *
131   - * 基于其对应的 {@link ProductSkuDO#getCostPrice()} 最大值 TODO 芋艿:待确定最大还是最小
  131 + * 基于其对应的 {@link ProductSkuDO#getCostPrice()} sku单价最低的商品的
132 132 */
133 133 private Integer costPrice;
134 134 /**
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
... ... @@ -24,11 +24,6 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
24 24 return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
25 25 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
26 26 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
27   - .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
28   - .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
29   - .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
30   - .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
31   - .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
32 27 .orderByDesc(ProductSpuDO::getSort));
33 28 }
34 29  
... ... @@ -36,13 +31,7 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
36 31 return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
37 32 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
38 33 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
39   - .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
40   - .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
41   - .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
42   - .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
43   - .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
44 34 .inIfPresent(ProductSpuDO::getId, alarmStockSpuIds) // 库存告警
45   - .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
46 35 .orderByDesc(ProductSpuDO::getSort));
47 36 }
48 37  
... ... @@ -52,8 +41,6 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
52 41 .eqIfPresent(ProductSpuDO::getStatus, status);
53 42 // 排序逻辑
54 43 if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) {
55   - // TODO ProductSpuDO 已经没有maxPrice 属性
56   - //query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getMaxPrice);
57 44 } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) {
58 45 query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getSalesCount);
59 46 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
... ... @@ -100,7 +100,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
100 100 if (category == null) {
101 101 throw exception(CATEGORY_NOT_EXISTS);
102 102 }
103   - if (Objects.equals(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
  103 + if (Objects.equals(category.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
104 104 throw exception(CATEGORY_DISABLED, category.getName());
105 105 }
106 106 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
... ... @@ -56,19 +56,17 @@ public interface ProductSkuService {
56 56 * 批量创建 SKU
57 57 *
58 58 * @param spuId 商品 SPU 编号
59   - * @param spuName 商品 SPU 名称
60 59 * @param list SKU 对象集合
61 60 */
62   - void createSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> list);
  61 + void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list);
63 62  
64 63 /**
65 64 * 根据 SPU 编号,批量更新它的 SKU 信息
66 65 *
67 66 * @param spuId SPU 编码
68   - * @param spuName 商品 SPU 名称
69 67 * @param skus SKU 的集合
70 68 */
71   - void updateSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skus);
  69 + void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
72 70  
73 71 /**
74 72 * 更新 SKU 库存(增量)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
... ... @@ -84,10 +84,17 @@ public class ProductSkuServiceImpl implements ProductSkuService {
84 84 return;
85 85 }
86 86  
  87 + // 0、校验skus是否为空
  88 + if (CollUtil.isEmpty(skus)){
  89 + throw exception(SKU_NOT_EXISTS);
  90 + }
  91 +
87 92 // 1、校验属性项存在
88 93 Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null)
89   - .flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性
90   - .map(ProductSkuCreateOrUpdateReqVO.Property::getPropertyId) // 将每个 Property 转换成对应的 propertyId,最后形成集合
  94 + // 遍历多个 Property 属性
  95 + .flatMap(p -> p.getProperties().stream())
  96 + // 将每个 Property 转换成对应的 propertyId,最后形成集合
  97 + .map(ProductSkuCreateOrUpdateReqVO.Property::getPropertyId)
91 98 .collect(Collectors.toSet());
92 99 List<ProductPropertyDO> propertyList = productPropertyService.getPropertyList(propertyIds);
93 100 if (propertyList.size() != propertyIds.size()) {
... ... @@ -107,22 +114,24 @@ public class ProductSkuServiceImpl implements ProductSkuService {
107 114 int attrValueIdsSize = skus.get(0).getProperties().size();
108 115 for (int i = 1; i < skus.size(); i++) {
109 116 if (attrValueIdsSize != skus.get(i).getProperties().size()) {
110   - throw exception(ErrorCodeConstants.SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
  117 + throw exception(SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
111 118 }
112 119 }
113 120  
114 121 // 4. 最后校验,每个 Sku 之间不是重复的
115   - Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
  122 + // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
  123 + Set<Set<Long>> skuAttrValues = new HashSet<>();
116 124 for (ProductSkuCreateOrUpdateReqVO sku : skus) {
117   - if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuCreateOrUpdateReqVO.Property::getValueId))) { // 添加失败,说明重复
118   - throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
  125 + // 添加失败,说明重复
  126 + if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuCreateOrUpdateReqVO.Property::getValueId))) {
  127 + throw exception(SPU_SKU_NOT_DUPLICATE);
119 128 }
120 129 }
121 130 }
122 131  
123 132 @Override
124   - public void createSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
125   - productSkuMapper.insertBatch(ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuId, spuName));
  133 + public void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
  134 + productSkuMapper.insertBatch(ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuId));
126 135 }
127 136  
128 137 @Override
... ... @@ -152,7 +161,7 @@ public class ProductSkuServiceImpl implements ProductSkuService {
152 161  
153 162 @Override
154 163 @Transactional(rollbackFor = Exception.class)
155   - public void updateSkuList(Long spuId, String spuName, List<ProductSkuCreateOrUpdateReqVO> skus) {
  164 + public void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
156 165 // 构建属性与 SKU 的映射关系;
157 166 Map<String, Long> existsSkuMap = convertMap(productSkuMapper.selectListBySpuId(spuId),
158 167 ProductSkuConvert.INSTANCE::buildPropertyKey, ProductSkuDO::getId);
... ... @@ -160,13 +169,14 @@ public class ProductSkuServiceImpl implements ProductSkuService {
160 169 // 拆分三个集合,新插入的、需要更新的、需要删除的
161 170 List<ProductSkuDO> insertSkus = new ArrayList<>();
162 171 List<ProductSkuDO> updateSkus = new ArrayList<>();
163   - List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertList06(skus, null, spuName);
  172 + List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertList06(skus, null);
164 173 allUpdateSkus.forEach(sku -> {
165 174 String propertiesKey = ProductSkuConvert.INSTANCE.buildPropertyKey(sku);
166 175 // 1、找得到的,进行更新
167 176 Long existsSkuId = existsSkuMap.remove(propertiesKey);
168 177 if (existsSkuId != null) {
169 178 sku.setId(existsSkuId);
  179 + // TODO 那spuId岂不是为null了
170 180 updateSkus.add(sku);
171 181 return;
172 182 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
... ... @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
12 12 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
13 13 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
14 14 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
  15 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
15 16 import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
16 17 import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
17 18 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
... ... @@ -21,10 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
21 22 import org.springframework.validation.annotation.Validated;
22 23  
23 24 import javax.annotation.Resource;
24   -import java.util.Collection;
25   -import java.util.List;
26   -import java.util.Map;
27   -import java.util.Set;
  25 +import java.util.*;
28 26  
29 27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 28 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
... ... @@ -54,20 +52,21 @@ public class ProductSpuServiceImpl implements ProductSpuService {
54 52 @Override
55 53 @Transactional(rollbackFor = Exception.class)
56 54 public Long createSpu(ProductSpuCreateReqVO createReqVO) {
57   - // 校验分类
58   - validateCategory(createReqVO.getCategoryId());
59   - // 校验品牌
60   - brandService.validateProductBrand(createReqVO.getBrandId());
61   - // 校验SKU
  55 + // 校验分类 TODO 暂不清楚为什么只能选择第三层的结点
  56 + //validateCategory(createReqVO.getCategoryId());
  57 + // 校验品牌 TODO 暂不校验
  58 + //brandService.validateProductBrand(createReqVO.getBrandId());
  59 +
62 60 List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = createReqVO.getSkus();
  61 + // 校验SKU
63 62 productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());
64   -
65   - // 插入 SPU
66 63 ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
  64 + // 初始化SPU中SKU相关属性
67 65 initSpuFromSkus(spu, skuSaveReqList);
  66 + // 插入 SPU
68 67 productSpuMapper.insert(spu);
69 68 // 插入 SKU
70   - productSkuService.createSkuList(spu.getId(), spu.getName(), skuSaveReqList);
  69 + productSkuService.createSkuList(spu.getId(), skuSaveReqList);
71 70 // 返回
72 71 return spu.getId();
73 72 }
... ... @@ -90,7 +89,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
90 89 initSpuFromSkus(updateObj, skuSaveReqList);
91 90 productSpuMapper.updateById(updateObj);
92 91 // 批量更新 SKU
93   - productSkuService.updateSkuList(updateObj.getId(), updateObj.getName(), updateReqVO.getSkus());
  92 + productSkuService.updateSkuList(updateObj.getId(), updateReqVO.getSkus());
94 93 }
95 94  
96 95 /**
... ... @@ -101,11 +100,25 @@ public class ProductSpuServiceImpl implements ProductSpuService {
101 100 * @param skus 商品 SKU 数组
102 101 */
103 102 private void initSpuFromSkus(ProductSpuDO spu, List<ProductSkuCreateOrUpdateReqVO> skus) {
104   - spu.setMarketPrice(getMaxValue(skus, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
105   - // TODO ProductSpuDO中已没有相关属性
106   - //spu.setMaxPrice(getMaxValue(skus, ProductSkuCreateOrUpdateReqVO::getPrice));
107   - //spu.setMinPrice(getMinValue(skus, ProductSkuCreateOrUpdateReqVO::getPrice));
108   - //spu.setTotalStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
  103 + // 断言,避免告警
  104 + assert skus.size() > 0;
  105 + // 获取sku单价最低的商品
  106 + ProductSkuCreateOrUpdateReqVO vo = skus.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateReqVO::getPrice)).get();
  107 + // sku单价最低的商品的价格
  108 + spu.setPrice(vo.getPrice());
  109 + // sku单价最低的商品的市场价格
  110 + spu.setMarketPrice(vo.getMarketPrice());
  111 + // sku单价最低的商品的成本价格
  112 + spu.setCostPrice(vo.getCostPrice());
  113 + // sku单价最低的商品的条形码
  114 + spu.setBarCode(vo.getBarCode());
  115 + // 默认状态为上架
  116 + spu.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
  117 + // TODO 默认商品销量和浏览量为零
  118 + spu.setSalesCount(0);
  119 + spu.setBrowseCount(0);
  120 + // skus库存总数
  121 + spu.setStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
109 122 }
110 123  
111 124 /**
... ... @@ -155,14 +168,14 @@ public class ProductSpuServiceImpl implements ProductSpuService {
155 168  
156 169 @Override
157 170 public PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
158   - // 库存告警的 SPU 编号的集合
  171 + // 库存告警的 SPU 编号的集合 TODO 一个接口一个接口来
159 172 Set<Long> alarmStockSpuIds = null;
160   - if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
161   - alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId);
162   - if (CollUtil.isEmpty(alarmStockSpuIds)) {
163   - return PageResult.empty();
164   - }
165   - }
  173 + //if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
  174 + // alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId);
  175 + // if (CollUtil.isEmpty(alarmStockSpuIds)) {
  176 + // return PageResult.empty();
  177 + // }
  178 + //}
166 179 // 分页查询
167 180 return productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds);
168 181 }
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java
... ... @@ -75,7 +75,7 @@ public class ProductSkuServiceTest extends BaseDbUnitTest {
75 75 );
76 76  
77 77 // 调用
78   - productSkuService.updateSkuList(spuId, spuName, skus);
  78 + productSkuService.updateSkuList(spuId, skus);
79 79 // 断言
80 80 List<ProductSkuDO> dbSkus = productSkuMapper.selectListBySpuId(spuId);
81 81 assertEquals(dbSkus.size(), 2);
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
... ... @@ -9,10 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9 9 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
10 10 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
11 11 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
12   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
13   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
14   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO;
15   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO;
  12 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
16 13 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
17 14 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
18 15 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
... ... @@ -37,6 +34,7 @@ import java.util.*;
37 34 import java.util.stream.Collectors;
38 35 import java.util.stream.Stream;
39 36  
  37 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
40 38 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
41 39 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
42 40 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
... ... @@ -83,21 +81,9 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
83 81 // 准备参数
84 82 ProductSpuCreateReqVO createReqVO = randomPojo(ProductSpuCreateReqVO.class, o -> {
85 83 o.setSpecType(true);
86   - o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
87 84 });
88   -
89   - // 校验SKU
90   - List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
91   -
92 85 Long spu = productSpuService.createSpu(createReqVO);
93 86 ProductSpuDO productSpuDO = productSpuMapper.selectById(spu);
94   -
95   - createReqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
96   - // TODO ProductSpuCreateReqVO中已没有相关属性
97   -// createReqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
98   -// createReqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
99   -// createReqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
100   -
101 87 assertPojoEquals(createReqVO, productSpuDO);
102 88  
103 89 }
... ... @@ -111,18 +97,9 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
111 97 ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
112 98 o.setId(createReqVO.getId()); // 设置更新的 ID
113 99 o.setSpecType(true);
114   - o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
115 100 });
116 101 // 调用
117 102 productSpuService.updateSpu(reqVO);
118   -
119   - List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = reqVO.getSkus();
120   - reqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
121   - // TODO ProductSpuUpdateReqVO中已没有相关属性
122   -// reqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
123   -// reqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
124   -// reqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
125   -
126 103 // 校验是否更新正确
127 104 ProductSpuDO spu = productSpuMapper.selectById(reqVO.getId()); // 获取最新的
128 105 assertPojoEquals(reqVO, spu);
... ... @@ -132,7 +109,6 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
132 109 public void testValidateSpuExists_exception() {
133 110 ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
134 111 o.setSpecType(true);
135   - o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
136 112 });
137 113 // 调用
138 114 Assertions.assertThrows(ServiceException.class, () -> productSpuService.updateSpu(reqVO));
... ... @@ -175,7 +151,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
175 151 void getSpuPage_alarmStock_empty() {
176 152 // 调用
177 153 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
178   - productSpuPageReqVO.setAlarmStock(true);
  154 + //productSpuPageReqVO.setAlarmStock(true);
179 155  
180 156 PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
181 157  
... ... @@ -225,10 +201,10 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
225 201  
226 202 // 调用
227 203 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
228   - productSpuPageReqVO.setAlarmStock(true);
  204 + //productSpuPageReqVO.setAlarmStock(true);
229 205 PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
230 206  
231   - PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
  207 + PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
232 208 Assertions.assertIterableEquals(result.getList(), spuPage.getList());
233 209 assertEquals(spuPage.getTotal(), result.getTotal());
234 210 }
... ... @@ -273,14 +249,14 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
273 249  
274 250 // 调用
275 251 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
276   - productSpuPageReqVO.setAlarmStock(false);
277   - productSpuPageReqVO.setBrandId(brandId);
278   - productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
  252 + //productSpuPageReqVO.setAlarmStock(false);
  253 + //productSpuPageReqVO.setBrandId(brandId);
  254 + //productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
279 255 productSpuPageReqVO.setCategoryId(categoryId);
280 256  
281 257 PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
282 258  
283   - PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
  259 + PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
284 260 assertEquals(result, spuPage);
285 261 }
286 262  
... ...