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 9197c6147..7f5e7aed8 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
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.product.api.sku.dto;
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import lombok.Data;
import java.util.List;
@@ -22,10 +21,6 @@ public class ProductSkuRespDTO {
* SPU 编号
*/
private Long spuId;
- /**
- * SPU 名字
- */
- private String spuName;
/**
* 属性数组
@@ -51,12 +46,6 @@ public class ProductSkuRespDTO {
* 图片地址
*/
private String picUrl;
- /**
- * SKU 状态
- *
- * 枚举 {@link CommonStatusEnum}
- */
- private Integer status;
/**
* 库存
*/
diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
index af387ab85..d6c314147 100644
--- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
+++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
@@ -14,7 +14,6 @@ public interface ErrorCodeConstants {
// ========== Order 模块 1-011-000-000 ==========
ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品 SKU 不存在");
ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1011000002, "商品 SPU 不可售卖");
- ErrorCode ORDER_CREATE_SKU_NOT_SALE = new ErrorCode(1011000003, "商品 SKU 不可售卖");
ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品 SKU 库存不足");
ErrorCode ORDER_CREATE_SPU_NOT_FOUND = new ErrorCode(1011000005, "商品 SPU 不可售卖");
ErrorCode ORDER_CREATE_ADDRESS_NOT_FOUND = new ErrorCode(1011000006, "收货地址不存在");
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java
index 053e329b4..bb2c60482 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java
@@ -17,12 +17,12 @@ public class AppProductSkuBaseRespVO {
@Schema(description = "主键", required = true, example = "1024")
private Long id;
- @Schema(description = "商品 SKU 名字", required = true, example = "芋道")
- private String name;
-
@Schema(description = "图片地址", example = "https://www.iocoder.cn/xx.png")
private String picUrl;
+ @Schema(description = "销售价格,单位:分", required = true, example = "100")
+ private Integer price;
+
@Schema(description = "库存", required = true, example = "1")
private Integer stock;
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 d00c2b0f3..79105ced6 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
@@ -4,6 +4,7 @@ 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.AppTradeCartListRespVO;
import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO;
+import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO;
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;
@@ -42,11 +43,19 @@ public class TradeCartController {
@PutMapping("/update")
@Operation(summary = "更新购物车商品")
@PreAuthenticated
- public CommonResult updateCartItemQuantity(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) {
+ public CommonResult updateCart(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) {
cartService.updateCart(getLoginUserId(), updateReqVO);
return success(true);
}
+ @PutMapping("/reset")
+ @Operation(summary = "重置购物车商品")
+ @PreAuthenticated
+ public CommonResult resetCart(@Valid @RequestBody AppTradeCartResetReqVO updateReqVO) {
+ cartService.resetCart(getLoginUserId(), updateReqVO);
+ return success(true);
+ }
+
@DeleteMapping("/delete")
@Operation(summary = "删除购物车商品")
@Parameter(name = "ids", description = "购物车商品编号", required = true, example = "1024,2048")
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java
deleted file mode 100644
index 62327f320..000000000
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.trade.controller.app.cart.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import java.util.Collection;
-
-@Schema(description = "用户 App - 购物车更新是否选中 Request VO")
-@Data
-public class AppTradeCartItemUpdateSelectedReqVO {
-
- @Schema(description = "商品 SKU 编号列表", required = true, example = "1024,2048")
- @NotNull(message = "商品 SKU 编号列表不能为空")
- private Collection skuIds;
-
- @Schema(description = "是否选中", required = true, example = "true")
- @NotNull(message = "是否选中不能为空")
- private Boolean selected;
-
-}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartResetReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartResetReqVO.java
new file mode 100644
index 000000000..eb8a81c80
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartResetReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.trade.controller.app.cart.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "用户 App - 购物车重置 Request VO")
+@Data
+public class AppTradeCartResetReqVO {
+
+ @Schema(description = "编号", required = true, example = "1024")
+ @NotNull(message = "编号不能为空")
+ private Long id;
+
+ @Schema(description = "商品 SKU 编号", required = true,example = "1024")
+ @NotNull(message = "商品 SKU 编号不能为空")
+ private Long skuId;
+
+ @Schema(description = "商品数量", required = true, example = "1")
+ @NotNull(message = "数量不能为空")
+ @Min(message = "数量必须大于 0", value = 1L)
+ private Integer count;
+
+}
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 c40ce377f..519b82fc9 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
@@ -34,17 +34,17 @@ public interface TradeCartConvert {
ProductSpuRespDTO spu = spuMap.get(cart.getSpuId());
ProductSkuRespDTO sku = skuMap.get(cart.getSkuId());
cartVO.setSpu(convert(spu)).setSku(convert(sku));
- // 如果 spu 或 sku 不存在,或者 spu 被禁用,说明是非法的,或者 sku 库存不足
+ // 如果 SPU 不存在,或者下架,或者库存不足,说明是无效的
if (spu == null
- || sku == null
|| !ProductSpuStatusEnum.isEnable(spu.getStatus())
- || sku.getStock() <= 0) {
+ || spu.getStock() <= 0) {
invalidList.add(cartVO);
} else {
+ // 虽然 SKU 可能也会不存在,但是可以通过购物车重新选择
validList.add(cartVO);
}
});
- return new AppTradeCartListRespVO().setValidList(validList).setValidList(invalidList);
+ return new AppTradeCartListRespVO().setValidList(validList).setInvalidList(invalidList);
}
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/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
index b1a834c38..6c44dc279 100644
--- 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
@@ -45,8 +45,11 @@ public interface TradeCartMapper extends BaseMapperX {
.eq(TradeCartDO::getUserId, userId));
}
- default List selectListByUserId(Long userId) {
- return selectList(TradeCartDO::getUserId, userId);
+ default List selectListByUserId(Long userId, Boolean addStatus, Boolean orderStatus) {
+ return selectList(new LambdaQueryWrapper()
+ .eq(TradeCartDO::getUserId, userId)
+ .eq(TradeCartDO::getAddStatus, addStatus)
+ .eq(TradeCartDO::getOrderStatus, orderStatus));
}
default void updateByIds(Collection ids, TradeCartDO updateObject) {
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 bb06374b6..9b87762c9 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,7 +1,8 @@
package cn.iocoder.yudao.module.trade.service.cart;
-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.AppTradeCartListRespVO;
+import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO;
import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO;
import javax.validation.Valid;
@@ -31,6 +32,16 @@ public interface TradeCartService {
*/
void updateCart(Long userId, AppTradeCartUpdateReqVO updateCountReqVO);
+ /**
+ * 重置购物车商品
+ *
+ * 使用场景:在一个购物车项对应的商品失效(例如说 SPU 被下架),可以重新选择对应的 SKU
+ *
+ * @param userId 用户编号
+ * @param updateReqVO 重置信息
+ */
+ void resetCart(Long userId, AppTradeCartResetReqVO updateReqVO);
+
/**
* 删除购物车商品
*
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 9539a19c5..ffd75a07a 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,18 +1,19 @@
package cn.iocoder.yudao.module.trade.service.cart;
import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
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.AppTradeCartResetReqVO;
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.TradeCartDO;
import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartMapper;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@@ -86,6 +87,28 @@ public class TradeCartServiceImpl implements TradeCartService {
.setCount(updateReqVO.getCount()));
}
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void resetCart(Long userId, AppTradeCartResetReqVO resetReqVO) {
+ // 第一步:删除原本的购物项
+ TradeCartDO oldCart = cartMapper.selectById(resetReqVO.getId(), userId);
+ if (oldCart == null) {
+ throw exception(CARD_ITEM_NOT_FOUND);
+ }
+ cartMapper.deleteById(oldCart.getId());
+
+ // 第二步:添加新的购物项
+ TradeCartDO newCart = cartMapper.selectByUserIdAndSkuId(userId, resetReqVO.getSkuId(),
+ true, false);
+ if (newCart != null) {
+ updateCart(userId, new AppTradeCartUpdateReqVO()
+ .setId(newCart.getId()).setCount(resetReqVO.getCount()));
+ } else {
+ addCart(userId, new AppTradeCartAddReqVO().setAddStatus(true)
+ .setSkuId(resetReqVO.getSkuId()).setCount(resetReqVO.getCount()));
+ }
+ }
+
/**
* 购物车删除商品
*
@@ -111,8 +134,8 @@ public class TradeCartServiceImpl implements TradeCartService {
@Override
public AppTradeCartListRespVO getCartList(Long userId) {
- // 获得购物车的商品
- List carts = cartMapper.selectListByUserId(userId);
+ // 获得购物车的商品,只查询未下单的
+ List carts = cartMapper.selectListByUserId(userId, true, false);
carts.sort(Comparator.comparing(TradeCartDO::getId).reversed());
// 如果未空,则返回空结果
if (CollUtil.isEmpty(carts)) {
@@ -122,12 +145,26 @@ public class TradeCartServiceImpl implements TradeCartService {
// 查询 SPU、SKU 列表
List spus = productSpuApi.getSpuList(convertSet(carts, TradeCartDO::getSpuId));
- List skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSpuId));
+ List skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSkuId));
+
+ // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除
+ deleteCartIfSpuDeleted(carts, spus);
// 拼接数据
return TradeCartConvert.INSTANCE.convertList(carts, spus, skus);
}
+ private void deleteCartIfSpuDeleted(List carts, List spus) {
+ // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除
+ carts.removeIf(cart -> {
+ if (spus.stream().noneMatch(spu -> spu.getId().equals(cart.getSpuId()))) {
+ cartMapper.deleteById(cart.getId());
+ return true;
+ }
+ return false;
+ });
+ }
+
/**
* 校验商品 SKU 是否合法
* 1. 是否存在
@@ -140,7 +177,7 @@ public class TradeCartServiceImpl implements TradeCartService {
*/
private ProductSkuRespDTO checkProductSku(Long skuId, Integer count) {
ProductSkuRespDTO sku = productSkuApi.getSku(skuId);
- if (sku == null || CommonStatusEnum.DISABLE.getStatus().equals(sku.getStatus())) {
+ if (sku == null) {
throw exception(SKU_NOT_EXISTS);
}
if (count > sku.getStock()) {
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
index 86d84c415..464cb86a7 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
@@ -5,7 +5,6 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
@@ -125,15 +124,10 @@ public class TradeOrderServiceImpl implements TradeOrderService {
if (items.size() != skus.size()) {
throw exception(ORDER_CREATE_SKU_NOT_FOUND);
}
- // 校验是否禁用 or 库存不足
+ // 校验库存不足
Map skuMap = convertMap(skus, ProductSkuRespDTO::getId);
items.forEach(item -> {
ProductSkuRespDTO sku = skuMap.get(item.getSkuId());
- // SKU 禁用
- if (ObjectUtil.notEqual(CommonStatusEnum.ENABLE.getStatus(), sku.getStatus())) {
- throw exception(ORDER_CREATE_SKU_NOT_SALE);
- }
- // SKU 库存不足
if (item.getCount() > sku.getStock()) {
throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_STOCK_NOT_ENOUGH);
}