parent
da162853ec
commit
f7fe9ad7b0
|
@ -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 状态
|
||||
* <p>
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 库存
|
||||
*/
|
||||
|
|
|
@ -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, "收货地址不存在");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Boolean> updateCartItemQuantity(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) {
|
||||
public CommonResult<Boolean> updateCart(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) {
|
||||
cartService.updateCart(getLoginUserId(), updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/reset")
|
||||
@Operation(summary = "重置购物车商品")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> 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")
|
||||
|
|
|
@ -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<Long> skuIds;
|
||||
|
||||
@Schema(description = "是否选中", required = true, example = "true")
|
||||
@NotNull(message = "是否选中不能为空")
|
||||
private Boolean selected;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -45,8 +45,11 @@ public interface TradeCartMapper extends BaseMapperX<TradeCartDO> {
|
|||
.eq(TradeCartDO::getUserId, userId));
|
||||
}
|
||||
|
||||
default List<TradeCartDO> selectListByUserId(Long userId) {
|
||||
return selectList(TradeCartDO::getUserId, userId);
|
||||
default List<TradeCartDO> selectListByUserId(Long userId, Boolean addStatus, Boolean orderStatus) {
|
||||
return selectList(new LambdaQueryWrapper<TradeCartDO>()
|
||||
.eq(TradeCartDO::getUserId, userId)
|
||||
.eq(TradeCartDO::getAddStatus, addStatus)
|
||||
.eq(TradeCartDO::getOrderStatus, orderStatus));
|
||||
}
|
||||
|
||||
default void updateByIds(Collection<Long> ids, TradeCartDO updateObject) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* 删除购物车商品
|
||||
*
|
||||
|
|
|
@ -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<TradeCartDO> carts = cartMapper.selectListByUserId(userId);
|
||||
// 获得购物车的商品,只查询未下单的
|
||||
List<TradeCartDO> 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<ProductSpuRespDTO> spus = productSpuApi.getSpuList(convertSet(carts, TradeCartDO::getSpuId));
|
||||
List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSpuId));
|
||||
List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSkuId));
|
||||
|
||||
// 如果 SPU 被删除,则删除购物车对应的商品。延迟删除
|
||||
deleteCartIfSpuDeleted(carts, spus);
|
||||
|
||||
// 拼接数据
|
||||
return TradeCartConvert.INSTANCE.convertList(carts, spus, skus);
|
||||
}
|
||||
|
||||
private void deleteCartIfSpuDeleted(List<TradeCartDO> carts, List<ProductSpuRespDTO> 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()) {
|
||||
|
|
|
@ -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<Long, ProductSkuRespDTO> 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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue