From 652428a723f44f2823deecdbbc80e08704742ad8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 14 Dec 2022 22:02:07 +0800 Subject: [PATCH] =?UTF-8?q?product=EF=BC=9A=E5=AE=8C=E5=96=84=20App=20?= =?UTF-8?q?=E5=95=86=E5=93=81=E8=AF=A6=E6=83=85=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/enums/ErrorCodeConstants.java | 1 + .../enums/spu/ProductSpuStatusEnum.java | 10 ++ .../admin/spu/ProductSpuController.java | 4 +- .../controller/app/property/package-info.java | 4 + .../property/vo/property/package-info.java | 4 + .../AppProductPropertyValueDetailRespVO.java | 23 +++++ .../app/spu/AppProductSpuController.http | 8 ++ .../app/spu/AppProductSpuController.java | 54 +++++++++-- .../app/spu/vo/AppSpuDetailRespVO.java | 92 +++++++++++++++++++ .../controller/app/spu/vo/AppSpuRespVO.java | 21 ----- .../convert/sku/ProductSkuConvert.java | 16 +++- .../convert/spu/ProductSpuConvert.java | 44 ++++++++- .../dal/mysql/sku/ProductSkuMapper.java | 12 +++ .../service/sku/ProductSkuService.java | 32 ++++--- .../service/sku/ProductSkuServiceImpl.java | 21 +++-- .../service/spu/ProductSpuService.java | 2 +- .../service/spu/ProductSpuServiceImpl.java | 16 ++-- .../spu/ProductSpuServiceImplTest.java | 6 +- 18 files changed, 300 insertions(+), 70 deletions(-) create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuDetailRespVO.java delete mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuRespVO.java 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 b752177e7..4adad0afc 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 @@ -33,6 +33,7 @@ public interface ErrorCodeConstants { // ========== 商品 SPU 1008005000 ========== ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在"); ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1008005001, "商品分类不正确,原因:必须使用第三级的商品分类下"); + ErrorCode SPU_NOT_ENABLE = new ErrorCode(1008005002, "商品 SPU 不处于上架状态"); // ========== 商品 SKU 1008006000 ========== ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品 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 6b7f03ac2..2223cf23d 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 @@ -35,4 +35,14 @@ public enum ProductSpuStatusEnum implements IntArrayValuable { return ARRAYS; } + /** + * 判断是否处于【上架】状态 + * + * @param status 状态 + * @return 是否处于【上架】状态 + */ + public static boolean isEnable(Integer status) { + return ENABLE.getStatus().equals(status); + } + } 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 155fd0265..96aa919ae 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 @@ -66,7 +66,7 @@ public class ProductSpuController { @ApiOperation("获得商品 SPU") @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) @PreAuthorize("@ss.hasPermission('product:spu:query')") - public CommonResult getSpu(@RequestParam("id") Long id) { + public CommonResult getSpu(@RequestParam("id") Long id) { return success(spuService.getSpu(id)); } @@ -75,7 +75,7 @@ public class ProductSpuController { @ApiOperation("获得商品 SPU 列表") @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class) @PreAuthorize("@ss.hasPermission('product:spu:query')") - public CommonResult> getSpuList(@RequestParam("ids") Collection ids) { + public CommonResult> getSpuList(@RequestParam("ids") Collection ids) { List list = spuService.getSpuList(ids); return success(ProductSpuConvert.INSTANCE.convertList(list)); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java new file mode 100644 index 000000000..379e85180 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无时间作用,避免 package 缩进 + */ +package cn.iocoder.yudao.module.product.controller.app.property; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java new file mode 100644 index 000000000..6538bea3c --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无时间作用,避免 package 缩进 + */ +package cn.iocoder.yudao.module.product.controller.app.property.vo.property; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java new file mode 100644 index 000000000..516dd077f --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.product.controller.app.property.vo.value; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel("用户 App - 商品属性值的明细 Response VO") +@Data +public class AppProductPropertyValueDetailRespVO { + + @ApiModelProperty(value = "属性的编号", required = true, example = "1") + private Long propertyId; + + @ApiModelProperty(value = "属性的名称", required = true, example = "颜色") + private String propertyName; + + @ApiModelProperty(value = "属性值的编号", required = true, example = "1024") + private Long valueId; + + @ApiModelProperty(value = "属性值的名称", required = true, example = "红色") + private String valueName; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http new file mode 100644 index 000000000..90bf0a4df --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http @@ -0,0 +1,8 @@ +### 获得订单交易的分页 TODO +GET {{appApi}}/trade/order/page?pageNo=1&pageSize=10 +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### 获得商品 SPU 明细 +GET {{appApi}}/product/spu/get-detail?id=4 +tenant-id: {{appTenentId}} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java index 7e0f912b4..5e64f3583 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java @@ -1,13 +1,22 @@ package cn.iocoder.yudao.module.product.controller.app.spu; -import cn.hutool.core.bean.BeanUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuDetailRespVO; 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.controller.app.spu.vo.AppSpuRespVO; +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.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; +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.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; @@ -17,28 +26,53 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_ENABLE; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; -@Api(tags = "用户 APP - 商品spu") +@Api(tags = "用户 APP - 商品 SPU") @RestController @RequestMapping("/product/spu") @Validated public class AppProductSpuController { @Resource - private ProductSpuService spuService; + private ProductSpuService productSpuService; + @Resource + private ProductSkuService productSkuService; + @Resource + private ProductPropertyValueService productPropertyValueService; @GetMapping("/page") @ApiOperation("获得商品spu分页") public CommonResult> getSpuPage(@Valid AppSpuPageReqVO pageVO) { - return success(spuService.getSpuPage(pageVO)); + return success(productSpuService.getSpuPage(pageVO)); } - @GetMapping("/") - @ApiOperation("获取商品 - 通过商品id") - public CommonResult getSpu(@RequestParam("spuId") Long spuId) { - AppSpuRespVO appSpuRespVO = BeanUtil.toBean(spuService.getSpu(spuId), AppSpuRespVO.class); - return success(appSpuRespVO); + @GetMapping("/get-detail") + @ApiOperation("获得商品 SPU 明细") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + public CommonResult getSpuDetail(@RequestParam("id") Long id) { + // 获得商品 SPU + ProductSpuDO spu = productSpuService.getSpu(id); + if (spu == null) { + throw exception(SPU_NOT_EXISTS); + } + if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { + throw exception(SPU_NOT_ENABLE); + } + + // 查询商品 SKU + List skus = productSkuService.getSkuListBySpuIdAndStatus(spu.getId(), + CommonStatusEnum.ENABLE.getStatus()); + // 查询商品属性 + List propertyValues = productPropertyValueService + .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus)); + // 拼接 + return success(ProductSpuConvert.INSTANCE.convert(spu, skus, propertyValues)); } + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuDetailRespVO.java new file mode 100644 index 000000000..76aed7732 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuDetailRespVO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.product.controller.app.spu.vo; + +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@ApiModel("用户 App - 商品 SPU 明细 Response VO") +@Data +public class AppSpuDetailRespVO { + + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1") + private Long id; + + // ========== 基本信息 ========= + + @ApiModelProperty(value = "商品名称", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "促销语", example = "好吃!") + private String sellPoint; + + @ApiModelProperty(value = "商品详情", required = true, example = "我是商品描述") + private String description; + + @ApiModelProperty(value = "商品分类编号", required = true, example = "1") + private Long categoryId; + + @ApiModelProperty(value = "商品图片的数组", required = true) + private List picUrls; + + @ApiModelProperty(value = "商品视频", required = true) + private String videoUrl; + + // ========== SKU 相关字段 ========= + + @ApiModelProperty(value = "规格类型", required = true, example = "1", notes = "参见 ProductSpuSpecTypeEnum 枚举类") + private Integer specType; + + @ApiModelProperty(value = "是否展示库存", required = true, example = "true") + private Boolean showStock; + + @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024") + private Integer minPrice; + + @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024") + private Integer maxPrice; + + /** + * SKU 数组 + */ + private List skus; + + // ========== 统计相关字段 ========= + + @ApiModelProperty(value = "商品销量", required = true, example = "1024") + private Integer salesCount; + + @ApiModel("用户 App - 商品 SPU 明细的 SKU 信息") + @Data + public static class Sku { + + @ApiModelProperty(value = "商品 SKU 编号", example = "1") + private Long id; + + /** + * 商品属性数组 + */ + private List properties; + + @ApiModelProperty(value = "销售价格,单位:分", required = true, example = "1024", notes = "单位:分") + private Integer price; + + @ApiModelProperty(value = "市场价", example = "1024", notes = "单位:分") + private Integer marketPrice; + + @ApiModelProperty(value = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + @ApiModelProperty(value = "库存", required = true, example = "1") + private Integer stock; + + @ApiModelProperty(value = "商品重量", example = "1", notes = "单位:kg 千克") + private Double weight; + + @ApiModelProperty(value = "商品体积", example = "1024", notes = "单位:m^3 平米") + private Double volume; + } + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuRespVO.java deleted file mode 100644 index b45987370..000000000 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuRespVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.product.controller.app.spu.vo; - -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; -import io.swagger.annotations.ApiModel; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - *

- * - *

- * - * @author LuoWenFeng - */ -@ApiModel("App - 商品spu Response VO") -@Data -@EqualsAndHashCode(callSuper = true) -public class AppSpuRespVO extends ProductSpuRespVO { - - -} 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 ce46bb4fd..00eb9bbff 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,5 +1,6 @@ package cn.iocoder.yudao.module.product.convert.sku; +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.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; @@ -10,9 +11,8 @@ import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @@ -72,4 +72,14 @@ public interface ProductSkuConvert { return spuIdAndStockMap; } + default Collection convertPropertyValueIds(List list) { + if (CollUtil.isEmpty(list)) { + return new HashSet<>(); + } + return list.stream().filter(item -> item.getProperties() != null) + .flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性 + .map(ProductSkuDO.Property::getValueId) // 将每个 Property 转换成对应的 propertyId,最后形成集合 + .collect(Collectors.toSet()); + } + } 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 98b7d8837..b84008314 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,15 +1,25 @@ package cn.iocoder.yudao.module.product.convert.spu; +import cn.hutool.core.collection.CollUtil; 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.property.vo.value.AppProductPropertyValueDetailRespVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuDetailRespVO; 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.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import static cn.hutool.core.util.ObjectUtil.defaultIfNull; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * 商品spu Convert @@ -25,18 +35,46 @@ public interface ProductSpuConvert { ProductSpuDO convert(ProductSpuUpdateReqVO bean); - ProductSpuRespVO convert(ProductSpuDO bean); - - List convertList(List list); + List convertList(List list); PageResult convertPage(PageResult page); ProductSpuPageReqVO convert(AppSpuPageReqVO bean); + // TODO 芋艿:修改下 AppSpuPageRespVO convertAppResp(ProductSpuDO list); List convertList2(List list); List convertList02(List list); + default AppSpuDetailRespVO convert(ProductSpuDO spu, List skus, + List propertyValues) { + AppSpuDetailRespVO spuVO = convert02(spu) + .setSalesCount(spu.getSalesCount() + defaultIfNull(spu.getVirtualSalesCount(), 0)); + spuVO.setSkus(convertList03(skus)); + // 处理商品属性 + Map propertyValueMap = convertMap(propertyValues, ProductPropertyValueDetailRespBO::getValueId); + for (int i = 0; i < skus.size(); i++) { + List properties = skus.get(i).getProperties(); + if (CollUtil.isEmpty(properties)) { + continue; + } + AppSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); + sku.setProperties(new ArrayList<>(properties.size())); + // 遍历每个 properties,设置到 AppSpuDetailRespVO.Sku 中 + properties.forEach(property -> { + ProductPropertyValueDetailRespBO propertyValue = propertyValueMap.get(property.getValueId()); + if (propertyValue == null) { + return; + } + sku.getProperties().add(convert03(propertyValue)); + }); + } + return spuVO; + } + AppSpuDetailRespVO convert02(ProductSpuDO spu); + List convertList03(List skus); + AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue); + } 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 3e5a9ce8f..56bc54499 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 @@ -8,6 +8,7 @@ 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.Collection; import java.util.List; /** @@ -22,6 +23,17 @@ public interface ProductSkuMapper extends BaseMapperX { return selectList(ProductSkuDO::getSpuId, spuId); } + default List selectListBySpuIdAndStatus(Long spuId, + Integer status) { + return selectList(new LambdaQueryWrapperX() + .eq(ProductSkuDO::getSpuId, spuId) + .eqIfPresent(ProductSkuDO::getStatus, status)); + } + + default List selectListBySpuId(Collection spuIds) { + return selectList(ProductSkuDO::getSpuId, spuIds); + } + default void deleteBySpuId(Long spuId) { delete(new LambdaQueryWrapperX().eq(ProductSkuDO::getSpuId, spuId)); } 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 3f9dde1d9..621e12d9f 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 @@ -3,6 +3,7 @@ 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 org.springframework.lang.Nullable; import java.util.Collection; import java.util.List; @@ -49,25 +50,25 @@ public interface ProductSkuService { * * @param list sku组合的集合 */ - void validateSkus(List list, Integer specType); + void validateSkuList(List list, Integer specType); /** * 批量创建 SKU * * @param spuId 商品 SPU 编号 - * @para spuName 商品 SPU 名称 + * @param spuName 商品 SPU 名称 * @param list SKU 对象集合 */ - void createSkus(Long spuId, String spuName, List list); + void createSkuList(Long spuId, String spuName, List list); /** * 根据 SPU 编号,批量更新它的 SKU 信息 * * @param spuId SPU 编码 - * @para spuName 商品 SPU 名称 + * @param spuName 商品 SPU 名称 * @param skus SKU 的集合 */ - void updateSkus(Long spuId, String spuName, List skus); + void updateSkuList(Long spuId, String spuName, List skus); /** * 更新 SKU 库存(增量) @@ -79,20 +80,30 @@ public interface ProductSkuService { void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO); /** - * 获得商品 sku 集合 + * 获得商品 SKU 集合 * * @param spuId spu 编号 * @return 商品sku 集合 */ - List getSkusBySpuId(Long spuId); + List getSkuListBySpuId(Long spuId); /** - * 获得 spu 对应的 sku 集合 + * 基于 SPU 编号和状态,获得商品 SKU 集合 + * + * @param spuId SPU 编号 + * @param status 状态 + * @return 商品 SKU 集合 + */ + List getSkuListBySpuIdAndStatus(Long spuId, + @Nullable Integer status); + + /** + * 获得 spu 对应的 SKU 集合 * * @param spuIds spu 编码集合 * @return 商品 sku 集合 */ - List getSkusBySpuIds(List spuIds); + List getSkuListBySpuId(List spuIds); /** * 通过 spuId 删除 sku 信息 @@ -106,7 +117,6 @@ public interface ProductSkuService { * * @return SKU 数组 */ - List getSkusByAlarmStock(); - + List getSkuListByAlarmStock(); } 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 3ed659f15..9721ac762 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 @@ -78,7 +78,7 @@ public class ProductSkuServiceImpl implements ProductSkuService { } @Override - public void validateSkus(List skus, Integer specType) { + public void validateSkuList(List skus, Integer specType) { // 非多规格,不需要校验 if (ObjectUtil.notEqual(specType, ProductSpuSpecTypeEnum.DISABLE.getType())) { return; @@ -121,7 +121,7 @@ public class ProductSkuServiceImpl implements ProductSkuService { } @Override - public void createSkus(Long spuId, String spuName, List skuCreateReqList) { + public void createSkuList(Long spuId, String spuName, List skuCreateReqList) { // 批量插入 SKU List skuDOList = ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuName); skuDOList.forEach(v -> v.setSpuId(spuId)); @@ -129,13 +129,18 @@ public class ProductSkuServiceImpl implements ProductSkuService { } @Override - public List getSkusBySpuId(Long spuId) { - return productSkuMapper.selectList(ProductSkuDO::getSpuId, spuId); + public List getSkuListBySpuId(Long spuId) { + return productSkuMapper.selectListBySpuId(spuId); } @Override - public List getSkusBySpuIds(List spuIds) { - return productSkuMapper.selectList(ProductSkuDO::getSpuId, spuIds); + public List getSkuListBySpuIdAndStatus(Long spuId, Integer status) { + return productSkuMapper.selectListBySpuIdAndStatus(spuId, status); + } + + @Override + public List getSkuListBySpuId(List spuIds) { + return productSkuMapper.selectListBySpuId(spuIds); } @Override @@ -144,13 +149,13 @@ public class ProductSkuServiceImpl implements ProductSkuService { } @Override - public List getSkusByAlarmStock() { + public List getSkuListByAlarmStock() { return productSkuMapper.selectListByAlarmStock(); } @Override @Transactional - public void updateSkus(Long spuId, String spuName, List skus) { + public void updateSkuList(Long spuId, String spuName, List skus) { // 查询 SPU 下已经存在的 SKU 的集合 List existsSkus = productSkuMapper.selectListBySpuId(spuId); // 构建属性与 SKU 的映射关系; 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 151edbf86..a9a784795 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 @@ -56,7 +56,7 @@ public interface ProductSpuService { * @param id 编号 * @return 商品 SPU */ - ProductSpuRespVO getSpu(Long id); + ProductSpuDO getSpu(Long id); /** * 获得商品 SPU 列表 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 954bafdcd..2a25d96d6 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 @@ -72,7 +72,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { brandService.validateProductBrand(createReqVO.getBrandId()); // 校验SKU List skuCreateReqList = createReqVO.getSkus(); - productSkuService.validateSkus(skuCreateReqList, createReqVO.getSpecType()); + productSkuService.validateSkuList(skuCreateReqList, createReqVO.getSpecType()); // 插入 SPU ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO); spu.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice)); @@ -81,7 +81,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); productSpuMapper.insert(spu); // 插入 SKU - productSkuService.createSkus(spu.getId(), spu.getName(), skuCreateReqList); + productSkuService.createSkuList(spu.getId(), spu.getName(), skuCreateReqList); // 返回 return spu.getId(); } @@ -97,7 +97,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { brandService.validateProductBrand(updateReqVO.getBrandId()); // 校验SKU List skuCreateReqList = updateReqVO.getSkus(); - productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType()); + productSkuService.validateSkuList(skuCreateReqList, updateReqVO.getSpecType()); // 更新 SPU ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO); @@ -107,7 +107,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); productSpuMapper.updateById(updateObj); // 批量更新 SKU - productSkuService.updateSkus(updateObj.getId(), updateObj.getName(), updateReqVO.getSkus()); + productSkuService.updateSkuList(updateObj.getId(), updateObj.getName(), updateReqVO.getSkus()); } /** @@ -146,7 +146,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { ProductSpuDO spu = productSpuMapper.selectById(id); ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class); if (null != spu) { - List skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id)); + List skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkuListBySpuId(id)); respVO.setSkus(skuReqs); // 组合 sku 属性 if (spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) { @@ -181,8 +181,8 @@ public class ProductSpuServiceImpl implements ProductSpuService { } @Override - public ProductSpuRespVO getSpu(Long id) { - return ProductSpuConvert.INSTANCE.convert(productSpuMapper.selectById(id)); + public ProductSpuDO getSpu(Long id) { + return productSpuMapper.selectById(id); } @Override @@ -200,7 +200,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { // 库存告警的 SPU 编号的集合 Set alarmStockSpuIds = null; if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) { - alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkusByAlarmStock(), ProductSkuDO::getSpuId); + alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId); if (CollUtil.isEmpty(alarmStockSpuIds)) { return PageResult.empty(); } 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 dce109048..7c0e6858b 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 @@ -186,7 +186,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { }); - Mockito.when(productSkuService.getSkusBySpuId(createReqVO.getId())).thenReturn(productSkuDOS); + Mockito.when(productSkuService.getSkuListBySpuId(createReqVO.getId())).thenReturn(productSkuDOS); // Mockito.when(productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyValueRespVO); // Mockito.when(productPropertyService.getPropertyVOList(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyRespVOS); // @@ -202,7 +202,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class); productSpuMapper.insert(createReqVO); - ProductSpuRespVO spu = productSpuService.getSpu(createReqVO.getId()); + ProductSpuDO spu = productSpuService.getSpu(createReqVO.getId()); assertPojoEquals(createReqVO, spu); } @@ -267,7 +267,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { o.setSpuId(createReqVO.getId()); })); - Mockito.when(productSkuService.getSkusByAlarmStock()).thenReturn(productSpuDOS); + Mockito.when(productSkuService.getSkuListByAlarmStock()).thenReturn(productSpuDOS); // 调用 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();