From da162853ec245d4261a2a6a3c9536dca81ba1b24 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 30 Apr 2023 20:32:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=95=86=E5=9F=8E=EF=BC=9A=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=B4=AD=E7=89=A9=E8=BD=A6=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/core/mapper/BaseMapperX.java | 12 ++ .../api/sku/dto/ProductSkuRespDTO.java | 12 +- .../api/spu/dto/ProductSpuRespDTO.java | 55 +++---- .../product/api/sku/ProductSkuApiImpl.java | 7 +- .../spu/vo/AppProductSpuPageItemRespVO.java | 3 + .../dal/dataobject/sku/ProductSkuDO.java | 21 ++- .../property/ProductPropertyServiceImpl.java | 1 + .../ProductPropertyValueServiceImpl.java | 1 + .../service/sku/ProductSkuServiceTest.java | 6 +- .../app/base/spu/AppProductSpuBaseRespVO.java | 2 +- .../app/cart/TradeCartController.http | 30 ++-- .../app/cart/TradeCartController.java | 47 +++--- ...ntReqVO.java => AppTradeCartAddReqVO.java} | 6 +- .../app/cart/vo/AppTradeCartDetailRespVO.java | 117 -------------- .../app/cart/vo/AppTradeCartListRespVO.java | 45 ++++++ ...eqVO.java => AppTradeCartUpdateReqVO.java} | 10 +- .../trade/convert/cart/TradeCartConvert.java | 65 ++++---- ...{TradeCartItemDO.java => TradeCartDO.java} | 52 +++--- .../dal/mysql/cart/TradeCartItemMapper.java | 47 ------ .../trade/dal/mysql/cart/TradeCartMapper.java | 56 +++++++ .../trade/service/cart/TradeCartService.java | 32 ++-- .../service/cart/TradeCartServiceImpl.java | 152 +++++++----------- 22 files changed, 349 insertions(+), 430 deletions(-) rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/{AppTradeCartItemAddCountReqVO.java => AppTradeCartAddReqVO.java} (75%) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/{AppTradeCartItemUpdateCountReqVO.java => AppTradeCartUpdateReqVO.java} (60%) rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/{TradeCartItemDO.java => TradeCartDO.java} (61%) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java index 9819bf551..87cf0dddc 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java @@ -46,6 +46,18 @@ public interface BaseMapperX extends MPJBaseMapper { return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2)); } + default T selectOne(SFunction field1, Object value1, SFunction field2, Object value2, + SFunction field3, Object value3) { + return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2) + .eq(field3, value3)); + } + + default T selectOne(SFunction field1, Object value1, SFunction field2, Object value2, + SFunction field3, Object value3, SFunction field4, Object value4) { + return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2) + .eq(field3, value3).eq(field4, value4)); + } + default Long selectCount() { return selectCount(new QueryWrapper()); } diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java index aaaf767f2..9197c6147 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java @@ -28,7 +28,7 @@ public class ProductSkuRespDTO { private String spuName; /** - * 属性数组,JSON 格式 + * 属性数组 */ private List properties; /** @@ -84,12 +84,20 @@ public class ProductSkuRespDTO { * 属性编号 */ private Long propertyId; + /** + * 属性名字 + */ + private String propertyName; + /** * 属性值编号 */ private Long valueId; + /** + * 属性值名字 + */ + private String valueName; } - } diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java index 5c4ee9bb7..acce738a7 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java @@ -29,17 +29,23 @@ public class ProductSpuRespDTO { */ private String name; /** - * 商品编码 + * 关键字 */ - private String code; + private String keyword; /** - * 促销语 + * 商品简介 */ - private String sellPoint; + private String introduction; /** * 商品详情 */ private String description; + // TODO @芋艿:是不是要删除 + /** + * 商品条码(一维码) + */ + private String barCode; + /** * 商品分类编号 */ @@ -49,13 +55,13 @@ public class ProductSpuRespDTO { */ private Long brandId; /** - * 商品图片的数组 - *

- * 1. 第一张图片将作为商品主图,支持同时上传多张图; - * 2. 建议使用尺寸 800x800 像素以上、大小不超过 1M 的正方形图片; - * 3. 至少 1 张,最多上传 10 张 + * 商品封面图 */ - private List picUrls; + private String picUrl; + /** + * 商品轮播图 + */ + private List sliderPicUrls; /** * 商品视频 */ @@ -76,38 +82,27 @@ public class ProductSpuRespDTO { /** * 规格类型 - *

- * 枚举 {@link ProductSpuSpecTypeEnum} + * + * false - 单规格 + * true - 多规格 */ private Boolean specType; /** - * 最小价格,单位使用:分 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最小值 + * 商品价格,单位使用:分 */ - private Integer minPrice; - /** - * 最大价格,单位使用:分 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最大值 - */ - private Integer maxPrice; + private Integer price; /** * 市场价,单位使用:分 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getMarketPrice()} 最大值 */ private Integer marketPrice; /** - * 总库存 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getStock()} 求和 + * 成本价,单位使用:分 */ - private Integer totalStock; + private Integer costPrice; /** - * 是否展示库存 + * 库存 */ - private Boolean showStock; + private Integer stock; // ========== 统计相关字段 ========= diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java index 89913c70e..6bec2a74c 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java @@ -15,7 +15,8 @@ import java.util.Collections; import java.util.List; /** - * TODO LeeYan9: 类注释; + * 商品 SKU API 实现类 + * * @author LeeYan9 * @since 2022-09-06 */ @@ -28,8 +29,8 @@ public class ProductSkuApiImpl implements ProductSkuApi { @Override public ProductSkuRespDTO getSku(Long id) { - // TODO TODO LeeYan9: 需要实现 - return null; + ProductSkuDO sku = productSkuService.getSku(id); + return ProductSkuConvert.INSTANCE.convert02(sku); } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java index 97513c3bc..68812b754 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java @@ -26,6 +26,9 @@ public class AppProductSpuPageItemRespVO { // ========== SKU 相关字段 ========= + @Schema(description = "规格类型", required = true, example = "true") + private Boolean specType; + @Schema(description = "商品价格,单位使用:分", required = true, example = "1024") private Integer price; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java index a9488563a..b759ae5ee 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java @@ -109,12 +109,29 @@ public class ProductSkuDO extends BaseDO { * 关联 {@link ProductPropertyDO#getId()} */ private Long propertyId; + /** + * 属性名字 + * + * 冗余 {@link ProductPropertyDO#getName()} + * + * 注意:每次属性名字发生变化时,需要更新该冗余 + */ + private String propertyName; + /** * 属性值编号 * * 关联 {@link ProductPropertyValueDO#getId()} */ private Long valueId; + /** + * 属性值名字 + * + * 冗余 {@link ProductPropertyValueDO#getName()} + * + * 注意:每次属性值名字发生变化时,需要更新该冗余 + */ + private String valueName; } @@ -139,9 +156,5 @@ public class ProductSkuDO extends BaseDO { // TODO 芋艿:pinkStock from y // TODO 芋艿:seckillStock from y - // TODO 芋艿:quota from c - // TODO 芋艿:quotaShow from c - // TODO 芋艿:attrValue from c - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java index 328c343d6..3468f2d60 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java @@ -67,6 +67,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { // 更新 ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO); productPropertyMapper.updateById(updateObj); + // TODO 芋艿:更新时,需要看看 sku 表 } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java index e5bc6874b..231b79b68 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java @@ -68,6 +68,7 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ // 更新 ProductPropertyValueDO updateObj = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO); productPropertyValueMapper.updateById(updateObj); + // TODO 芋艿:更新时,需要看看 sku 表 } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java index ec088cfdd..2e8ade7fc 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java +++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java @@ -54,12 +54,14 @@ public class ProductSkuServiceTest extends BaseDbUnitTest { // mock 数据 ProductSkuDO sku01 = randomPojo(ProductSkuDO.class, o -> { // 测试更新 o.setSpuId(1L); - o.setProperties(singletonList(new ProductSkuDO.Property(10L, 20L))); + o.setProperties(singletonList(new ProductSkuDO.Property( + 10L, "颜色", 20L, "红色"))); }); productSkuMapper.insert(sku01); ProductSkuDO sku02 = randomPojo(ProductSkuDO.class, o -> { // 测试删除 o.setSpuId(1L); - o.setProperties(singletonList(new ProductSkuDO.Property(10L, 30L))); + o.setProperties(singletonList(new ProductSkuDO.Property( + 10L, "颜色", 30L, "蓝色"))); }); productSkuMapper.insert(sku02); // 准备参数 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java index b73be6e0c..04359c810 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java @@ -20,6 +20,6 @@ public class AppProductSpuBaseRespVO { private String name; @Schema(description = "商品主图地址", example = "https://www.iocoder.cn/xx.png") - private List picUrls; + private String picUrl; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http index 3ce8797fc..ead0fa72f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http @@ -1,38 +1,28 @@ -### 请求 /trade/cart/add-count 接口 => 成功 -POST {{appApi}}/trade/cart/add-count +### 请求 /trade/cart/add 接口 => 成功 +POST {{appApi}}/trade/cart/add tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} Content-Type: application/json { "skuId": 1, - "count": 1 + "count": 10, + "addStatus": true } -### 请求 /trade/cart/update-count 接口 => 成功 -PUT {{appApi}}/trade/cart/update-count +### 请求 /trade/cart/update 接口 => 成功 +PUT {{appApi}}/trade/cart/update tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} Content-Type: application/json { - "skuId": 1, + "id": 35, "count": 5 } -### 请求 /trade/cart/update-selected 接口 => 成功 -PUT {{appApi}}/trade/cart/update-selected -tenant-id: {{appTenentId}} -Authorization: Bearer {{appToken}} -Content-Type: application/json - -{ - "skuIds": [1], - "selected": false -} - ### 请求 /trade/cart/delete 接口 => 成功 -DELETE {{appApi}}/trade/cart/delete?skuIds=1 +DELETE {{appApi}}/trade/cart/delete?ids=1 tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} @@ -41,7 +31,7 @@ GET {{appApi}}/trade/cart/get-count tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} -### 请求 /trade/cart/get-detail 接口 => 成功 -GET {{appApi}}/trade/cart/get-detail +### 请求 /trade/cart/list 接口 => 成功 +GET {{appApi}}/trade/cart/list tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java index 46512a959..d00c2b0f3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java @@ -2,10 +2,9 @@ package cn.iocoder.yudao.module.trade.controller.app.cart; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -33,37 +32,27 @@ public class TradeCartController { @Resource private TradeCartService cartService; - @PostMapping("/add-count") - @Operation(summary = "添加商品到购物车") + @PostMapping("/add") + @Operation(summary = "添加购物车商品") @PreAuthenticated - public CommonResult addCartItemCount(@Valid @RequestBody AppTradeCartItemAddCountReqVO addCountReqVO) { - cartService.addCartItemCount(getLoginUserId(), addCountReqVO); - return success(true); + public CommonResult addCart(@Valid @RequestBody AppTradeCartAddReqVO addCountReqVO) { + return success(cartService.addCart(getLoginUserId(), addCountReqVO)); } - @PutMapping("update-count") - @Operation(summary = "更新购物车商品数量") + @PutMapping("/update") + @Operation(summary = "更新购物车商品") @PreAuthenticated - public CommonResult updateCartItemQuantity(@Valid @RequestBody AppTradeCartItemUpdateCountReqVO updateCountReqVO) { - cartService.updateCartItemCount(getLoginUserId(), updateCountReqVO); - return success(true); - } - - @PutMapping("update-selected") - @Operation(summary = "更新购物车商品是否选中") - @PreAuthenticated - public CommonResult updateCartItemSelected(@Valid @RequestBody AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { - cartService.updateCartItemSelected(getLoginUserId(), updateSelectedReqVO); - // 获得目前购物车明细 + public CommonResult updateCartItemQuantity(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) { + cartService.updateCart(getLoginUserId(), updateReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "删除购物车商品") - @Parameter(name = "skuIds", description = "商品 SKU 编号的数组", required = true, example = "1024,2048") + @Parameter(name = "ids", description = "购物车商品编号", required = true, example = "1024,2048") @PreAuthenticated - public CommonResult deleteCartItem(@RequestParam("skuIds") List skuIds) { - cartService.deleteCartItems(getLoginUserId(), skuIds); + public CommonResult deleteCart(@RequestParam("ids") List ids) { + cartService.deleteCart(getLoginUserId(), ids); return success(true); } @@ -74,11 +63,11 @@ public class TradeCartController { return success(cartService.getCartCount(getLoginUserId())); } - @GetMapping("/get-detail") - @Operation(summary = "查询用户的购物车的详情") + @GetMapping("/list") + @Operation(summary = "查询用户的购物车列表") @PreAuthenticated - public CommonResult getCartDetail() { - return success(cartService.getCartDetail(getLoginUserId())); + public CommonResult getCartList() { + return success(cartService.getCartList(getLoginUserId())); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java similarity index 75% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java index 9b4ba6929..c1e3ebd2f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java @@ -8,7 +8,7 @@ import javax.validation.constraints.NotNull; @Schema(description = "用户 App - 购物车添加购物项 Request VO") @Data -public class AppTradeCartItemAddCountReqVO { +public class AppTradeCartAddReqVO { @Schema(description = "商品 SKU 编号", required = true,example = "1024") @NotNull(message = "商品 SKU 编号不能为空") @@ -19,4 +19,8 @@ public class AppTradeCartItemAddCountReqVO { @Min(message = "数量必须大于 0", value = 1L) private Integer count; + @Schema(description = "是否添加到购物车", required = true, example = "true") + @NotNull(message = "是否添加购物车不能为空") + private Boolean addStatus; + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java deleted file mode 100644 index 769418528..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java +++ /dev/null @@ -1,117 +0,0 @@ -package cn.iocoder.yudao.module.trade.controller.app.cart.vo; - -import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.util.List; - -@Schema(description = "用户 App - 用户的购物车明细 Response VO") -@Data -public class AppTradeCartDetailRespVO { - - /** - * 商品分组数组 - */ - private List itemGroups; - - /** - * 费用 - */ - private Order order; - - @Schema(description = "商品分组") // 多个商品,参加同一个活动,从而形成分组 - @Data - public static class ItemGroup { - - /** - * 商品数组 - */ - private List items; - /** - * 营销活动,订单级别 - */ - private Promotion promotion; - - } - - @Schema(description = "商品 SKU") - @Data - public static class Sku extends AppProductSkuBaseRespVO { - - /** - * SPU 信息 - */ - private AppProductSkuBaseRespVO spu; - - // ========== 购物车相关的字段 ========== - - @Schema(description = "商品数量", required = true, example = "1") - private Integer count; - @Schema(description = "是否选中", required = true, example = "true") - private Boolean selected; - - // ========== 价格相关的字段,对应 PriceCalculateRespDTO.OrderItem 的属性 ========== - - // TODO 芋艿:后续可以去除一些无用的字段 - - @Schema(description = "商品原价(单)", required = true, example = "100") - private Integer originalPrice; - @Schema(description = "商品原价(总)", required = true, example = "200") - private Integer totalOriginalPrice; - @Schema(description = "商品级优惠(总)", required = true, example = "300") - private Integer totalPromotionPrice; - @Schema(description = "最终购买金额(总)", required = true, example = "400") - private Integer totalPresentPrice; - @Schema(description = "最终购买金额(单)", required = true, example = "500") - private Integer presentPrice; - @Schema(description = "应付金额(总)", required = true, example = "600") - private Integer totalPayPrice; - - // ========== 营销相关的字段 ========== - /** - * 营销活动,商品级别 - */ - private Promotion promotion; - - } - - @Schema(description = "订单") // 对应 PriceCalculateRespDTO.Order 类,用于费用(合计) - @Data - public static class Order { - - // TODO 芋艿:后续可以去除一些无用的字段 - - @Schema(description = "商品原价(总)", required = true, example = "100") - private Integer skuOriginalPrice; - @Schema(description = "商品优惠(总)", required = true, example = "200") - private Integer skuPromotionPrice; - @Schema(description = "订单优惠(总)", required = true, example = "300") - private Integer orderPromotionPrice; - @Schema(description = "运费金额", required = true, example = "400") - private Integer deliveryPrice; - @Schema(description = "应付金额(总)", required = true, example = "500") - private Integer payPrice; - - } - - @Schema(description = "营销活动") // 对应 PriceCalculateRespDTO.Promotion 类的属性 - @Data - public static class Promotion { - - @Schema(description = "营销编号", required = true, example = "1024") // 营销活动的编号、优惠劵的编号 - private Long id; - @Schema(description = "营销名字", required = true, example = "xx 活动") - private String name; - @Schema(description = "营销类型", required = true, example = "1") - private Integer type; - - // ========== 匹配情况 ========== - @Schema(description = "是否满足优惠条件", required = true, example = "true") - private Boolean meet; - @Schema(description = "满足条件的提示", required = true, example = "圣诞价:省 150.00 元") - private String meetTip; - - } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java new file mode 100644 index 000000000..5f33ece55 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.base.spu.AppProductSpuBaseRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 用户的购物列表 Response VO") +@Data +public class AppTradeCartListRespVO { + + /** + * 有效的购物项数组 + */ + private List validList; + + /** + * 无效的购物项数组 + */ + private List invalidList; + + @Schema(description = "购物项") + @Data + public static class Cart { + + @Schema(description = "购物项的编号", required = true, example = "1024") + private Long id; + + @Schema(description = "商品数量", required = true, example = "1") + private Integer count; + + /** + * 商品 SPU + */ + private AppProductSpuBaseRespVO spu; + /** + * 商品 SKU + */ + private AppProductSkuBaseRespVO sku; + + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartUpdateReqVO.java similarity index 60% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartUpdateReqVO.java index d3d12487e..4cf72bbf1 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartUpdateReqVO.java @@ -6,13 +6,13 @@ import lombok.Data; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; -@Schema(description = "用户 App - 购物车更新数量 Request VO") +@Schema(description = "用户 App - 购物车更新 Request VO") @Data -public class AppTradeCartItemUpdateCountReqVO { +public class AppTradeCartUpdateReqVO { - @Schema(description = "商品 SKU 编号", required = true, example = "1024") - @NotNull(message = "商品 SKU 编号不能为空") - private Long skuId; + @Schema(description = "编号", required = true, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; @Schema(description = "商品数量", required = true, example = "1") @NotNull(message = "数量不能为空") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java index eb696ae30..c40ce377f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java @@ -1,45 +1,52 @@ package cn.iocoder.yudao.module.trade.convert.cart; -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.base.spu.AppProductSpuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; +import java.util.Map; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @Mapper public interface TradeCartConvert { TradeCartConvert INSTANCE = Mappers.getMapper(TradeCartConvert.class); - default AppTradeCartDetailRespVO buildEmptyAppTradeCartDetailRespVO() { - return new AppTradeCartDetailRespVO().setItemGroups(Collections.emptyList()) - .setOrder(new AppTradeCartDetailRespVO.Order().setSkuOriginalPrice(0).setSkuPromotionPrice(0) - .setOrderPromotionPrice(0).setDeliveryPrice(0).setPayPrice(0)); + default AppTradeCartListRespVO convertList(List carts, + List spus, List skus) { + Map spuMap = convertMap(spus, ProductSpuRespDTO::getId); + Map skuMap = convertMap(skus, ProductSkuRespDTO::getId); + // 遍历,开始转换 + List validList = new ArrayList<>(carts.size()); + List invalidList = new ArrayList<>(); + carts.forEach(cart -> { + AppTradeCartListRespVO.Cart cartVO = new AppTradeCartListRespVO.Cart(); + cartVO.setId(cart.getId()).setCount(cart.getCount()); + ProductSpuRespDTO spu = spuMap.get(cart.getSpuId()); + ProductSkuRespDTO sku = skuMap.get(cart.getSkuId()); + cartVO.setSpu(convert(spu)).setSku(convert(sku)); + // 如果 spu 或 sku 不存在,或者 spu 被禁用,说明是非法的,或者 sku 库存不足 + if (spu == null + || sku == null + || !ProductSpuStatusEnum.isEnable(spu.getStatus()) + || sku.getStock() <= 0) { + invalidList.add(cartVO); + } else { + validList.add(cartVO); + } + }); + return new AppTradeCartListRespVO().setValidList(validList).setValidList(invalidList); } - - default PriceCalculateReqDTO convert(Long userId, List cartItems) { - return new PriceCalculateReqDTO().setUserId(userId) - .setItems(convertList(cartItems, cartItem -> new PriceCalculateReqDTO.Item().setSkuId(cartItem.getSkuId()) - .setCount(cartItem.getSelected() ? cartItem.getCount() : 0))); - } - - // ========== AppTradeCartDetailRespVO 相关 ========== - - AppTradeCartDetailRespVO.Promotion convert(PriceCalculateRespDTO.Promotion bean); - - @Mappings({ - @Mapping(source = "cartItem.count", target = "count") - }) - AppTradeCartDetailRespVO.Sku convert(PriceCalculateRespDTO.OrderItem orderItem, TradeCartItemDO cartItem); - - AppTradeCartDetailRespVO.Order convert(PriceCalculateRespDTO.Order bean); + AppProductSpuBaseRespVO convert(ProductSpuRespDTO spu); + AppProductSkuBaseRespVO convert(ProductSkuRespDTO sku); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartDO.java similarity index 61% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartDO.java index 05fbb801d..d9d9697ae 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartDO.java @@ -9,13 +9,15 @@ import lombok.experimental.Accessors; /** * 购物车的商品信息 DO * + * 每个商品,对应一条记录,通过 {@link #spuId} 和 {@link #skuId} 关联 + * * @author 芋道源码 */ -@TableName("trade_cart_item") +@TableName("trade_cart") @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) -public class TradeCartItemDO extends BaseDO { +public class TradeCartDO extends BaseDO { // ========= 基础字段 BEGIN ========= @@ -23,14 +25,6 @@ public class TradeCartItemDO extends BaseDO { * 编号,唯一自增 */ private Long id; - /** - * 是否选中 - */ - private Boolean selected; - - // ========= 基础字段 END ========= - - // ========= 买家信息 BEGIN ========= /** * 用户编号 @@ -39,7 +33,25 @@ public class TradeCartItemDO extends BaseDO { */ private Long userId; - // ========= 买家信息 END ========= + /** + * 是否添加到购物车 + * + * false - 未添加:用户点击【立即购买】 + * true - 已添加:用户点击【添加购物车】 + * + * 为什么要设计这个字段? + * 配合 orderStatus 字段,可以知道有多少商品,用户点击了【立即购买】,最终多少【确认下单】 + */ + private Boolean addStatus; + /** + * 是否提交订单 + * + * false - 未下单:立即购买,或者添加到购物车,此时设置为 false + * true - 已下单:确认下单,此时设置为 true + */ + private Boolean orderStatus; + + // ========= 基础字段 END ========= // ========= 商品信息 BEGIN ========= @@ -64,27 +76,11 @@ public class TradeCartItemDO extends BaseDO { // ========= 优惠信息 BEGIN ========= -// /** -// * 商品营销活动编号 -// */ -// private Long activityId; // discount_id -// /** -// * 商品营销活动类型 -// */ -// private Integer activityType; // TODO 芋艿:combination_id 拼团 ID // TODO 芋艿:seckill_id 秒杀产品 ID // TODO 芋艿:bargain_id 砍价 ID + // TODO 芋艿:pinkId 团长拼团 ID // ========= 优惠信息 END ========= - // TODO 待确定字段:mf - // TODO 芋艿:distribution_card_no 推广员 - // TODO 芋艿:is_pay 未购买、已购买 - // TODO 芋艿:is_new 是否立即购买 - - // TODO 待确定字段: yv - // TODO isPay: 是否购买 - // TODO isNew:是否立即购买 - } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java deleted file mode 100644 index fa6adbf41..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.yudao.module.trade.dal.mysql.cart; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -@Mapper -public interface TradeCartItemMapper extends BaseMapperX { - - default TradeCartItemDO selectByUserIdAndSkuId(Long userId, Long skuId) { - return selectOne(TradeCartItemDO::getUserId, userId, - TradeCartItemDO::getSkuId, skuId); - } - - default List selectListByUserIdAndSkuIds(Long userId, Collection skuIds) { - return selectList(new LambdaQueryWrapper().eq(TradeCartItemDO::getUserId, userId) - .in(TradeCartItemDO::getSkuId, skuIds)); - } - - default void updateByIds(Collection ids, TradeCartItemDO updateObject) { - update(updateObject, new LambdaQueryWrapper().in(TradeCartItemDO::getId, ids)); - } - - default Integer selectSumByUserId(Long userId) { - // SQL sum 查询 - List> result = selectMaps(new QueryWrapper() - .select("SUM(count) AS sumCount") - .eq("user_id", userId)); - // 获得数量 - return CollUtil.isNotEmpty(result) ? MapUtil.getInt(result.get(0), "sumCount") : 0; - } - - default List selectListByUserId(Long userId, Boolean selected) { - return selectList(new LambdaQueryWrapperX().eq(TradeCartItemDO::getUserId, userId) - .eqIfPresent(TradeCartItemDO::getSelected, selected)); - } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java new file mode 100644 index 000000000..b1a834c38 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.cart; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Mapper +public interface TradeCartMapper extends BaseMapperX { + + default TradeCartDO selectByUserIdAndSkuId(Long userId, Long skuId, + Boolean addStatus, Boolean orderStatus) { + return selectOne(TradeCartDO::getUserId, userId, + TradeCartDO::getSkuId, skuId, + TradeCartDO::getAddStatus, addStatus, + TradeCartDO::getOrderStatus, orderStatus); + } + + default Integer selectSumByUserId(Long userId) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .eq("user_id", userId) + .eq("add_status", true) // 只计算添加到购物车中的 + .eq("order_status", false)); // 必须未下单 + // 获得数量 + return CollUtil.getFirst(result) != null ? MapUtil.getInt(result.get(0), "sumCount") : 0; + } + + default TradeCartDO selectById(Long id, Long userId) { + return selectOne(TradeCartDO::getId, id, + TradeCartDO::getUserId, userId); + } + + default List selectListByIds(Collection ids, Long userId) { + return selectList(new LambdaQueryWrapper() + .in(TradeCartDO::getId, ids) + .eq(TradeCartDO::getUserId, userId)); + } + + default List selectListByUserId(Long userId) { + return selectList(TradeCartDO::getUserId, userId); + } + + default void updateByIds(Collection ids, TradeCartDO updateObject) { + update(updateObject, new LambdaQueryWrapper().in(TradeCartDO::getId, ids)); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java index 3f46f5102..bb06374b6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java @@ -1,9 +1,8 @@ package cn.iocoder.yudao.module.trade.service.cart; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import javax.validation.Valid; import java.util.Collection; @@ -19,9 +18,10 @@ public interface TradeCartService { * 添加商品到购物车 * * @param userId 用户编号 - * @param addCountReqVO 添加信息 + * @param addReqVO 添加信息 + * @return 购物项的编号 */ - void addCartItemCount(Long userId, @Valid AppTradeCartItemAddCountReqVO addCountReqVO); + Long addCart(Long userId, @Valid AppTradeCartAddReqVO addReqVO); /** * 更新购物车商品数量 @@ -29,23 +29,15 @@ public interface TradeCartService { * @param userId 用户编号 * @param updateCountReqVO 更新信息 */ - void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO); - - /** - * 更新购物车商品是否选中 - * - * @param userId 用户编号 - * @param updateSelectedReqVO 更新信息 - */ - void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO); + void updateCart(Long userId, AppTradeCartUpdateReqVO updateCountReqVO); /** * 删除购物车商品 * * @param userId 用户编号 - * @param skuIds SKU 编号的数组 + * @param ids 购物项的编号 */ - void deleteCartItems(Long userId, Collection skuIds); + void deleteCart(Long userId, Collection ids); /** * 查询用户在购物车中的商品数量 @@ -56,11 +48,11 @@ public interface TradeCartService { Integer getCartCount(Long userId); /** - * 查询用户的购物车详情 + * 查询用户的购物车列表 * * @param userId 用户编号 - * @return 购物车详情 + * @return 购物车列表 */ - AppTradeCartDetailRespVO getCartDetail(Long userId); + AppTradeCartListRespVO getCartList(Long userId); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java index ae0301e83..9539a19c5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java @@ -1,39 +1,38 @@ package cn.iocoder.yudao.module.trade.service.cart; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.promotion.api.price.PriceApi; -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import cn.iocoder.yudao.module.trade.convert.cart.TradeCartConvert; -import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; -import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartItemMapper; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; +import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartMapper; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.List; -import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.CARD_ITEM_NOT_FOUND; +import static java.util.Collections.emptyList; /** * 购物车 Service 实现类 * + * // TODO 芋艿:秒杀、拼团、砍价对购物车的影响 + * // TODO 芋艿:未来优化:购物车的价格计算,支持营销信息 + * * @author 芋道源码 */ @Service @@ -41,123 +40,92 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.CARD_ITEM_N public class TradeCartServiceImpl implements TradeCartService { @Resource - private TradeCartItemMapper cartItemMapper; + private TradeCartMapper cartMapper; + @Resource + private ProductSpuApi productSpuApi; @Resource private ProductSkuApi productSkuApi; - @Resource - private PriceApi priceApi; @Override - public void addCartItemCount(Long userId, AppTradeCartItemAddCountReqVO addCountReqVO) { - Long skuId = addCountReqVO.getSkuId(); - Integer count = addCountReqVO.getCount(); - // 查询 CartItemDO - TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, addCountReqVO.getSkuId()); + public Long addCart(Long userId, AppTradeCartAddReqVO addReqVO) { + // 查询 TradeCartDO + TradeCartDO cart = cartMapper.selectByUserIdAndSkuId(userId, addReqVO.getSkuId(), + addReqVO.getAddStatus(), false); + // 校验 SKU + Integer count = cart != null && addReqVO.getAddStatus() ? + cart.getCount() + addReqVO.getCount() : addReqVO.getCount(); + ProductSkuRespDTO sku = checkProductSku(addReqVO.getSkuId(), count); - // 存在,则进行数量更新 - if (tradeItem != null) { - checkProductSku(skuId, tradeItem.getCount() + count); - cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()) - .setSelected(true).setCount(tradeItem.getCount() + count)); - return; + // 情况一:存在,则进行数量更新 + if (cart != null) { + cartMapper.updateById(new TradeCartDO().setId(cart.getId()).setCount(count)); + return cart.getId(); + // 情况二:不存在,则进行插入 + } else { + cart = new TradeCartDO().setUserId(userId) + .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count) + .setAddStatus(addReqVO.getAddStatus()).setOrderStatus(false); + cartMapper.insert(cart); } - - // 不存在,则进行插入 - ProductSkuRespDTO sku = checkProductSku(skuId, count); - cartItemMapper.insert(new TradeCartItemDO().setUserId(userId).setSpuId(sku.getSpuId()).setSkuId(sku.getId()) - .setSelected(true).setCount(count)); + return cart.getId(); } @Override - public void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO) { - // 校验 TradeCartItemDO 存在 - TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, updateCountReqVO.getSkuId()); - if (tradeItem == null) { + public void updateCart(Long userId, AppTradeCartUpdateReqVO updateReqVO) { + // 校验 TradeCartDO 存在 + TradeCartDO cart = cartMapper.selectById(updateReqVO.getId(), userId); + if (cart == null) { throw exception(CARD_ITEM_NOT_FOUND); } // 校验商品 SKU - checkProductSku(updateCountReqVO.getSkuId(), updateCountReqVO.getCount()); + checkProductSku(cart.getSkuId(), updateReqVO.getCount()); // 更新数量 - cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()).setCount(updateCountReqVO.getCount())); - } - - @Override - public void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { - // 查询 CartItemDO 列表 - List cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, updateSelectedReqVO.getSkuIds()); - if (CollUtil.isEmpty(cartItems)) { - return; - } - - // 更新选中 - cartItemMapper.updateByIds(CollectionUtils.convertList(cartItems, TradeCartItemDO::getId), - new TradeCartItemDO().setSelected(updateSelectedReqVO.getSelected())); + cartMapper.updateById(new TradeCartDO().setId(cart.getId()) + .setCount(updateReqVO.getCount())); } /** * 购物车删除商品 * * @param userId 用户编号 - * @param skuIds 商品 SKU 编号的数组 + * @param ids 商品 SKU 编号的数组 */ @Override - public void deleteCartItems(Long userId, Collection skuIds) { - // 查询 CartItemDO 列表 - List cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, skuIds); - if (CollUtil.isEmpty(cartItems)) { + public void deleteCart(Long userId, Collection ids) { + // 查询 TradeCartDO 列表 + List carts = cartMapper.selectListByIds(ids, userId); + if (CollUtil.isEmpty(carts)) { return; } // 批量标记删除 - cartItemMapper.deleteBatchIds(CollectionUtils.convertSet(cartItems, TradeCartItemDO::getId)); + cartMapper.deleteBatchIds(ids); } @Override public Integer getCartCount(Long userId) { - return cartItemMapper.selectSumByUserId(userId); + return cartMapper.selectSumByUserId(userId); } @Override - public AppTradeCartDetailRespVO getCartDetail(Long userId) { + public AppTradeCartListRespVO getCartList(Long userId) { // 获得购物车的商品 - List cartItems = cartItemMapper.selectListByUserId(userId, null); + List carts = cartMapper.selectListByUserId(userId); + carts.sort(Comparator.comparing(TradeCartDO::getId).reversed()); // 如果未空,则返回空结果 - if (CollUtil.isEmpty(cartItems)) { - return TradeCartConvert.INSTANCE.buildEmptyAppTradeCartDetailRespVO(); + if (CollUtil.isEmpty(carts)) { + return new AppTradeCartListRespVO().setValidList(emptyList()) + .setInvalidList(emptyList()); } - // 调用价格服务,计算价格 - PriceCalculateRespDTO priceCalculate = priceApi.calculatePrice(TradeCartConvert.INSTANCE.convert(userId, cartItems)); + // 查询 SPU、SKU 列表 + List spus = productSpuApi.getSpuList(convertSet(carts, TradeCartDO::getSpuId)); + List skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSpuId)); - // 转换返回 - Map cartItemMap = convertMap(cartItems, TradeCartItemDO::getSkuId); - Map orderItemMap = convertMap(priceCalculate.getOrder().getItems(), - PriceCalculateRespDTO.OrderItem::getSkuId); - List itemGroups = new ArrayList<>(cartItems.size()); - // ① 场景一,营销活动,订单级别 TODO 芋艿:待测试 - priceCalculate.getPromotions().stream().filter(promotion -> PromotionLevelEnum.ORDER.getLevel().equals(promotion.getLevel())) - .forEach(promotion -> { - AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>()) - .setPromotion(TradeCartConvert.INSTANCE.convert(promotion)); - itemGroups.add(itemGroup); - promotion.getItems().forEach(promotionItem -> { - PriceCalculateRespDTO.OrderItem orderItem = orderItemMap.remove(promotionItem.getSkuId()); - Assert.notNull(orderItem, "商品 SKU({}) 对应的订单项不能为空", promotionItem.getSkuId()); - TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); - itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu - }); - }); - // ② 场景二,营销活动,商品级别 - orderItemMap.values().forEach(orderItem -> { - AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>(1)).setPromotion(null); - itemGroups.add(itemGroup); - TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); - itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu - }); - return new AppTradeCartDetailRespVO().setItemGroups(itemGroups) - .setOrder(TradeCartConvert.INSTANCE.convert(priceCalculate.getOrder())); + // 拼接数据 + return TradeCartConvert.INSTANCE.convertList(carts, spus, skus); } /**