Browse Source

自动增减库存逻辑修改

codingliang 2 years ago
parent
commit
51e0d412b2

+ 13 - 2
src/main/java/com/study/mall/controller/GoodsCategoryController.java

@@ -37,8 +37,19 @@ public class GoodsCategoryController {
      * 分类树形列表
      */
     @GetMapping("open/list")
-    public CommonResult<List<CategoryTreeVO>> list(){
-        List<CategoryTreeVO> vos = goodsCategoryService.treeList();
+    public CommonResult<List<CategoryTreeVO>> openList(){
+        List<CategoryTreeVO> vos = goodsCategoryService.openTreeList();
+
+        return CommonResult.ok().setResult(vos);
+    }
+
+    /**
+     * 分类树形列表(管理员)
+     * @apiNote 返回包含为禁用状态的分类
+     */
+    @GetMapping("admin/list")
+    public CommonResult<List<CategoryTreeVO>> adminList(){
+        List<CategoryTreeVO> vos = goodsCategoryService.adminTreeList();
 
         return CommonResult.ok().setResult(vos);
     }

+ 3 - 1
src/main/java/com/study/mall/service/GoodsCategoryService.java

@@ -19,7 +19,9 @@ public interface GoodsCategoryService extends IService<GoodsCategoryEntity> {
 
     PageUtils queryPage(PageParam pageParam);
 
-    List<CategoryTreeVO> treeList();
+    List<CategoryTreeVO> openTreeList();
+
+    List<CategoryTreeVO> adminTreeList();
 
     void clearTreeListCache();
 

+ 38 - 20
src/main/java/com/study/mall/service/impl/GoodsCategoryServiceImpl.java

@@ -1,5 +1,6 @@
 package com.study.mall.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.study.mall.common.exception.BizCodeEnum;
 import com.study.mall.common.exception.RRException;
@@ -55,29 +56,11 @@ public class GoodsCategoryServiceImpl extends ServiceImpl<GoodsCategoryDao, Good
     }
 
     @Override
-    public List<CategoryTreeVO> treeList() {
+    public List<CategoryTreeVO> openTreeList() {
         CacheObject cacheObject = cacheChannel.get(REGION, CATEGORY_TREE_VO_CACHE_KEY);
         List<CategoryTreeVO> levelOneVOS;
         if (cacheObject.getValue() == null) {
-            // 查询所有分类
-            LambdaQueryWrapper<GoodsCategoryEntity> queryWrapper = new LambdaQueryWrapper<>();
-            queryWrapper.eq(GoodsCategoryEntity::getState, "1");
-            List<GoodsCategoryEntity> list = list(queryWrapper);
-
-            // 查询一级目录
-            List<GoodsCategoryEntity> levelOneCategory = list.stream().filter(e -> e.getLevel().intValue() == 1).sorted(Comparator.comparing(GoodsCategoryEntity::getSort)).collect(Collectors.toList());
-
-            // 封装一级目录
-            levelOneVOS = packageCategoryTreeVO(levelOneCategory).stream().map(levelOneVO -> {
-                // 过滤当前一级分类所有的二级分类
-                List<GoodsCategoryEntity> collect = list.stream()
-                        .filter(e -> (e.getLevel().intValue() != 1 && e.getPid().longValue() == levelOneVO.getId().longValue()))
-                        .sorted(Comparator.comparing(GoodsCategoryEntity::getSort))
-                        .collect(Collectors.toList());
-                levelOneVO.setChildCategory(packageCategoryTreeVO(collect));
-
-                return levelOneVO;
-            }).collect(Collectors.toList());
+            levelOneVOS = doQuery("1");
 
             cacheChannel.set(REGION, CATEGORY_TREE_VO_CACHE_KEY, levelOneVOS);
         } else {
@@ -87,6 +70,11 @@ public class GoodsCategoryServiceImpl extends ServiceImpl<GoodsCategoryDao, Good
     }
 
     @Override
+    public List<CategoryTreeVO> adminTreeList() {
+        return doQuery(null);
+    }
+
+    @Override
     public void clearTreeListCache() {
         cacheChannel.evict(REGION, CATEGORY_TREE_VO_CACHE_KEY);
     }
@@ -193,4 +181,34 @@ public class GoodsCategoryServiceImpl extends ServiceImpl<GoodsCategoryDao, Good
             return vo;
         }).collect(Collectors.toList());
     }
+
+    /**
+     *
+     * @param state 不填查询所有分类、1传启用状态的分类
+     * @return
+     */
+    private List<CategoryTreeVO> doQuery(String state) {
+        // 查询所有分类
+        LambdaQueryWrapper<GoodsCategoryEntity> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(ObjectUtil.isNotEmpty(state), GoodsCategoryEntity::getState, state);
+
+        List<GoodsCategoryEntity> list = list(queryWrapper);
+
+        // 查询一级目录
+        List<GoodsCategoryEntity> levelOneCategory = list.stream().filter(e -> e.getLevel().intValue() == 1).sorted(Comparator.comparing(GoodsCategoryEntity::getSort)).collect(Collectors.toList());
+
+        // 封装一级目录
+        List<CategoryTreeVO> levelOneVOS = packageCategoryTreeVO(levelOneCategory).stream().map(levelOneVO -> {
+            // 过滤当前一级分类所有的二级分类
+            List<GoodsCategoryEntity> collect = list.stream()
+                    .filter(e -> (e.getLevel().intValue() != 1 && e.getPid().longValue() == levelOneVO.getId().longValue()))
+                    .sorted(Comparator.comparing(GoodsCategoryEntity::getSort))
+                    .collect(Collectors.toList());
+            levelOneVO.setChildCategory(packageCategoryTreeVO(collect));
+
+            return levelOneVO;
+        }).collect(Collectors.toList());
+
+        return levelOneVOS;
+    }
 }

+ 11 - 0
src/main/java/com/study/mall/service/impl/GoodsSkuServiceImpl.java

@@ -2,6 +2,7 @@ package com.study.mall.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -16,6 +17,7 @@ import com.study.mall.dao.GoodsSkuDao;
 import com.study.mall.dto.SukInfoDTO;
 import com.study.mall.entity.GoodsSkuEntity;
 import com.study.mall.entity.GoodsSkuSaleAttrValueEntity;
+import com.study.mall.service.FileService;
 import com.study.mall.service.GoodsSkuSaleAttrValueService;
 import com.study.mall.service.GoodsSkuService;
 import com.study.mall.vo.GoodsSkuInfoVO;
@@ -37,6 +39,7 @@ import java.util.stream.Collectors;
 public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuDao,GoodsSkuEntity> implements GoodsSkuService {
 
     private final GoodsSkuSaleAttrValueService skuSaleAttrValueService;
+    private final FileService fileService;
 
     @Override
     public PageUtils queryPage(PageParam pageParam) {
@@ -78,6 +81,14 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuDao,GoodsSkuEntity>
             BeanUtil.copyProperties(e, skuEntity);
             skuEntity.setGoodsId(goodsId);
             skuEntity.setId(e.getSkuId());
+
+            // 图片处理
+            String imgsStr = skuEntity.getSkuImg();
+            if (ObjectUtil.isNotEmpty(imgsStr)) {
+                if (imgsStr.contains(FileServiceImpl.TEMP_FILE_INCLUDE_PATH)) {
+                    skuEntity.setSkuImg(fileService.moveToRealPath(imgsStr));
+                }
+            }
             return skuEntity;
         }).collect(Collectors.toList());
 

+ 102 - 74
src/main/java/com/study/mall/service/impl/OrderInfoServiceImpl.java

@@ -64,6 +64,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -82,6 +84,11 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEnt
     private final RabbitTemplate rabbitTemplate;
 
     /**
+     * 本地订单锁
+     */
+    private final Lock orderLock = new ReentrantLock(true);
+
+    /**
      * 订单提交令牌 key 前缀
      */
     private static final String ORDER_SUBMIT_TOKEN_PREFIX = "order:submit:%s";
@@ -321,43 +328,52 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEnt
         List<Long> skuIds = dto.getOrderDetails().stream().filter(e -> ObjectUtil.isNotNull(e.getSkuId())).map(CreateOrderDTO.CreateOrderDetailDTO::getSkuId).collect(Collectors.toList());
         List<GoodsSkuEntity> skuInfos = skuIds.size() > 0 ? goodsSkuService.listByIds(skuIds) : ListUtil.empty();
 
-        // 校验商品信息和支付价格
-        Map<String, BigDecimal> checkResult = checkGoodAndPrice(dto, goodsArray, skuInfos);
-        BigDecimal discountAmount = checkResult.get("discountAmount");
-        BigDecimal deliveryFee = checkResult.get("deliveryFee");
-        BigDecimal totalAmount = checkResult.get("totalAmount");
-
-        // 构建订单表
-        OrderInfoEntity orderInfo = addOrder(dto, totalAmount, deliveryFee, discountAmount);
-        // 构建订单详情表
-        orderDetailService.addDetail(orderInfo.getId(), goodsArray, skuInfos, dto);
-        // 构建订单收货人表
-        orderConsigneeInfoService.add(orderInfo.getId(), userAddress);
-
-        // 构建返回参数
-        CreateOrderVO vo = new CreateOrderVO();
-        vo.setOrderId(orderInfo.getId());
-        vo.setOrderAmount(orderInfo.getOrderActualPrice());
-
-        // 删除购物车对应的商品
-        String type = dto.getSubmitType();
-        if ("2".equals(type)) {
-            List<String> keys = dto.getOrderDetails().stream().map(e -> {
-                String key;
-                if (ObjectUtil.isNull(e.getSkuId())) {
-                    key = e.getGoodsId().toString();
-                } else {
-                    key = String.format("%s-%s", e.getGoodsId(), e.getSkuId());
-                }
-                return key;
-            }).collect(Collectors.toList());
-            cartService.deleteItems(keys);
-        }
+        orderLock.lock();
+        try {
+            // 校验商品信息和支付价格
+            Map<String, BigDecimal> checkResult = checkGoodAndPrice(dto, goodsArray, skuInfos);
+            BigDecimal discountAmount = checkResult.get("discountAmount");
+            BigDecimal deliveryFee = checkResult.get("deliveryFee");
+            BigDecimal totalAmount = checkResult.get("totalAmount");
+
+            // 更新库存、销量
+            goodsService.updateBatchById(goodsArray);
+            goodsSkuService.updateBatchById(skuInfos);
+
+            // 构建订单表
+            OrderInfoEntity orderInfo = addOrder(dto, totalAmount, deliveryFee, discountAmount);
+            // 构建订单详情表
+            orderDetailService.addDetail(orderInfo.getId(), goodsArray, skuInfos, dto);
+            // 构建订单收货人表
+            orderConsigneeInfoService.add(orderInfo.getId(), userAddress);
+
+            // 构建返回参数
+            CreateOrderVO vo = new CreateOrderVO();
+            vo.setOrderId(orderInfo.getId());
+            vo.setOrderAmount(orderInfo.getOrderActualPrice());
+
+            // 删除购物车对应的商品
+            String type = dto.getSubmitType();
+            if ("2".equals(type)) {
+                List<String> keys = dto.getOrderDetails().stream().map(e -> {
+                    String key;
+                    if (ObjectUtil.isNull(e.getSkuId())) {
+                        key = e.getGoodsId().toString();
+                    } else {
+                        key = String.format("%s-%s", e.getGoodsId(), e.getSkuId());
+                    }
+                    return key;
+                }).collect(Collectors.toList());
+                cartService.deleteItems(keys);
+            }
 
-        // 订单创建成功通知
-        rabbitTemplate.convertAndSend(MQConstant.ORDER_EXCHANGE, MQConstant.ORDER_CREATE_ROUTE_KEY, vo);
+            // 订单创建成功通知
+            rabbitTemplate.convertAndSend(MQConstant.ORDER_EXCHANGE, MQConstant.ORDER_CREATE_ROUTE_KEY, vo);
 
-        return vo;
+            return vo;
+        } finally {
+            orderLock.unlock();
+        }
     }
 
     @Override
@@ -377,43 +393,6 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEnt
         orderInfo.setState("2");
 
         this.updateById(orderInfo);
-
-        // 更新库存、销量
-        try {
-            addSaleNumAndReducesStock(orderDetailService.getByOrderId(orderId));
-        } catch (Exception e) {
-            log.error("库存扣减、销量新增操作失败,失败原因【{}】", e.getMessage());
-        }
-    }
-
-    /**
-     * 加销量、减库存
-     * @param orderDetails
-     */
-    private void addSaleNumAndReducesStock(List<OrderDetailEntity> orderDetails) {
-        List<Long> goodsIds = orderDetails.stream().map(e -> e.getGoodsId()).distinct().collect(Collectors.toList());
-        List<Long> skuIds = orderDetails.stream().filter(e -> ObjectUtil.isNotNull(e.getSkuId())).distinct().map(e -> e.getSkuId()).collect(Collectors.toList());
-        Map<Long, Integer> goodsMap = orderDetails.stream().collect(Collectors.toMap(OrderDetailEntity::getGoodsId, OrderDetailEntity::getGoodsCount, Integer::sum));
-        Map<Long, Integer> skuMap = orderDetails.stream().filter(e -> ObjectUtil.isNotNull(e.getSkuId())).collect(Collectors.toMap(OrderDetailEntity::getSkuId, OrderDetailEntity::getGoodsCount));
-
-        List<GoodsEntity> goodsEntities = goodsService.getByIds(goodsIds);
-        goodsEntities.forEach(goods -> {
-            Integer num = goodsMap.get(goods.getId());
-            goods.setSaleCnt(goods.getSaleCnt() + num);
-            goods.setStockNum(goods.getStockNum() - num);
-        });
-
-        goodsService.updateBatchById(goodsEntities);
-
-        if (ObjectUtil.isNotEmpty(skuIds)) {
-            List<GoodsSkuEntity> goodsSkuEntities = goodsSkuService.listByIds(skuIds);
-            goodsSkuEntities.forEach(sku -> {
-                Integer num = skuMap.get(sku.getId());
-                sku.setStockNum(sku.getStockNum() - num);
-            });
-
-            goodsSkuService.updateBatchById(goodsSkuEntities);
-        }
     }
 
     @Transactional
@@ -463,12 +442,16 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEnt
         this.updateById(orderInfo);
     }
 
+    @Transactional
     @Override
     public void autoCancelOrderIfNotPay(Long orderId) {
         OrderInfoEntity orderInfo = this.getById(orderId);
         if (orderInfo != null && "1".equals(orderInfo.getState())) {
             orderInfo.setState("6");
             this.updateById(orderInfo);
+
+            // 释放库存
+            releaseStockNum(orderId);
         }
     }
 
@@ -551,10 +534,14 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEnt
                     throw new RRException(BizCodeEnum.PARAMETER_ERROR, "商品:" + goods.getId() + " 不存在");
                 }
 
-                if (goods.getStockNum().intValue() <= 0) {
+                int newStockNum = goods.getStockNum().intValue() - orderDetail.getGoodsCount().intValue();
+                if (newStockNum  < 0) {
                     throw new RRException(BizCodeEnum.PARAMETER_ERROR, "商品:" + goods.getName() + " 库存不足");
                 }
 
+                goods.setStockNum(newStockNum);
+                goods.setSaleCnt(goods.getSaleCnt() + orderDetail.getGoodsCount());
+
                 totalAmount = totalAmount.add(goods.getPrice().multiply(new BigDecimal(orderDetail.getGoodsCount())));
             }
             // 否则用sku数据
@@ -564,10 +551,17 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEnt
                     throw new RRException(BizCodeEnum.PARAMETER_ERROR, "sku:" + orderDetail.getSkuId() + " 不存在");
                 }
 
-                if (sku.getStockNum().intValue() <= 0) {
+                int newStockNum = sku.getStockNum().intValue() - orderDetail.getGoodsCount().intValue();
+
+                if (newStockNum < 0) {
                     throw new RRException(BizCodeEnum.PARAMETER_ERROR, "sku:" + sku.getSkuName() + " 库存不足");
                 }
 
+                sku.setStockNum(newStockNum);
+
+                GoodsEntity goods = goodsMap.get(sku.getGoodsId());
+                goods.setSaleCnt(goods.getSaleCnt() + orderDetail.getGoodsCount());
+
                 totalAmount = totalAmount.add(sku.getPrice().multiply(new BigDecimal(orderDetail.getGoodsCount())));
             }
         }
@@ -733,4 +727,38 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEnt
             throw new RRException(BizCodeEnum.PARAMETER_ERROR, "skuId:" + notInNoSaleGoods.get(0).getId() + "为非销售状态sku");
         }
     }
+
+    /**
+     * 释放库存
+     * @param orderId 订单id
+     */
+    private void releaseStockNum(Long orderId) {
+        List<OrderDetailEntity> orderDetails = orderDetailService.getByOrderId(orderId);
+        List<Long> goodsIds = orderDetails.stream().map(e -> e.getGoodsId()).distinct().collect(Collectors.toList());
+        List<Long> skuIds = orderDetails.stream().filter(e -> ObjectUtil.isNotNull(e.getSkuId())).distinct().map(e -> e.getSkuId()).collect(Collectors.toList());
+        Map<Long, Integer> goodsMap = orderDetails.stream().collect(Collectors.toMap(OrderDetailEntity::getGoodsId, OrderDetailEntity::getGoodsCount, Integer::sum));
+        Map<Long, Integer> skuMap = orderDetails.stream().filter(e -> ObjectUtil.isNotNull(e.getSkuId())).collect(Collectors.toMap(OrderDetailEntity::getSkuId, OrderDetailEntity::getGoodsCount));
+
+        List<GoodsEntity> goodsEntities = goodsService.getByIds(goodsIds);
+        goodsEntities.forEach(goods -> {
+            Integer num = goodsMap.get(goods.getId());
+            goods.setSaleCnt(goods.getSaleCnt() - num);
+            if (!ObjectUtil.equal(goods.getEnableSku(), "1")) {
+                goods.setStockNum(goods.getStockNum() + num);
+            }
+
+        });
+
+        goodsService.updateBatchById(goodsEntities);
+
+        if (ObjectUtil.isNotEmpty(skuIds)) {
+            List<GoodsSkuEntity> goodsSkuEntities = goodsSkuService.listByIds(skuIds);
+            goodsSkuEntities.forEach(sku -> {
+                Integer num = skuMap.get(sku.getId());
+                sku.setStockNum(sku.getStockNum() + num);
+            });
+
+            goodsSkuService.updateBatchById(goodsSkuEntities);
+        }
+    }
 }