浏览代码

trade:增加优惠劵使用、商品库存的扣减

YunaiV 2 年之前
父节点
当前提交
84f6ec10bc

+ 1 - 1
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuUpdateStockReqDTO.java

@@ -40,7 +40,7 @@ public class ProductSkuUpdateStockReqDTO {
          * 负数:扣减库存
          */
         @NotNull(message = "库存变化数量不能为空")
-        private Integer incCount;
+        private Integer incrCount;
 
     }
 

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java

@@ -60,7 +60,7 @@ public interface ProductSkuConvert {
             if (spuId == null) {
                 return;
             }
-            Integer stock = spuIdAndStockMap.getOrDefault(spuId, 0) + item.getIncCount();
+            Integer stock = spuIdAndStockMap.getOrDefault(spuId, 0) + item.getIncrCount();
             spuIdAndStockMap.put(spuId, stock);
         });
         return spuIdAndStockMap;

+ 4 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java

@@ -203,10 +203,10 @@ public class ProductSkuServiceImpl implements ProductSkuService {
     public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) {
         // 更新 SKU 库存
         updateStockReqDTO.getItems().forEach(item -> {
-            if (item.getIncCount() > 0) {
-                productSkuMapper.updateStockIncr(item.getId(), item.getIncCount());
-            } else if (item.getIncCount() < 0) {
-                int updateStockIncr = productSkuMapper.updateStockDecr(item.getId(), item.getIncCount());
+            if (item.getIncrCount() > 0) {
+                productSkuMapper.updateStockIncr(item.getId(), item.getIncrCount());
+            } else if (item.getIncrCount() < 0) {
+                int updateStockIncr = productSkuMapper.updateStockDecr(item.getId(), item.getIncrCount());
                 if (updateStockIncr == 0) {
                     throw exception(SKU_STOCK_NOT_ENOUGH);
                 }

+ 3 - 3
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java

@@ -46,7 +46,7 @@ public class ProductSkuServiceTest extends BaseDbUnitTest {
     public void testUpdateSkuStock_incrSuccess() {
         // 准备参数
         ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO()
-                .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncCount(10)));
+                .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(10)));
         // mock 数据
         productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> o.setId(1L).setSpuId(10L).setStock(20)));
 
@@ -66,7 +66,7 @@ public class ProductSkuServiceTest extends BaseDbUnitTest {
     public void testUpdateSkuStock_decrSuccess() {
         // 准备参数
         ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO()
-                .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncCount(-10)));
+                .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(-10)));
         // mock 数据
         productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> o.setId(1L).setSpuId(10L).setStock(20)));
 
@@ -86,7 +86,7 @@ public class ProductSkuServiceTest extends BaseDbUnitTest {
     public void testUpdateSkuStock_decrFail() {
         // 准备参数
         ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO()
-                .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncCount(-30)));
+                .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(-30)));
         // mock 数据
         productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> o.setId(1L).setSpuId(10L).setStock(20)));
 

+ 9 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.order;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
@@ -17,7 +18,7 @@ import org.mapstruct.factory.Mappers;
 import java.util.List;
 import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 
 @Mapper
 public interface TradeOrderConvert {
@@ -59,4 +60,11 @@ public interface TradeOrderConvert {
     @Mapping(source = "userId" , target = "userId")
     PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId);
 
+    @Mappings({
+            @Mapping(source = "skuId", target = "id"),
+            @Mapping(source = "count", target = "incrCount"),
+    })
+    ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean);
+    List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);
+
 }

+ 0 - 22
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java

@@ -1,22 +0,0 @@
-package cn.iocoder.yudao.module.trade.convert.sku;
-
-import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
-import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-
-// TODO @LeeYan9:挪到 OrderConvert 那
-/**
- * @author LeeYan9
- * @since 2022-08-26
- */
-@Mapper
-public interface ProductSkuConvert {
-
-    ProductSkuConvert INSTANCE = Mappers.getMapper(ProductSkuConvert.class);
-
-    List<SkuDecrementStockBatchReqDTO.Item> convert(List<TradeOrderItemDO> list);
-
-}

+ 44 - 21
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java

@@ -14,9 +14,12 @@ import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
 import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO;
 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.sku.dto.ProductSkuUpdateStockReqDTO;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
+import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
+import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
 import cn.iocoder.yudao.module.promotion.api.price.PriceApi;
 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
@@ -74,6 +77,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
     private PayOrderApi payOrderApi;
     @Resource
     private AddressApi addressApi;
+    @Resource
+    private CouponApi couponApi;
 
     @Resource
     private TradeOrderProperties tradeOrderProperties;
@@ -94,26 +99,10 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         // 插入 TradeOrderDO 订单
         TradeOrderDO tradeOrderDO = createTradeOrder(userId, userIp, createReqVO, priceResp.getOrder(), address);
         // 插入 TradeOrderItemDO 订单项
-        createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus);
-
-        // 下单时扣减商品库存 TODO
-//        List<SkuDecrementStockBatchReqDTO.Item> skuDecrementStockItems = ProductSkuConvert.INSTANCE.convert(tradeOrderItems);
-//        productSkuApi.decrementStockBatch(SkuDecrementStockBatchReqDTO.of(skuDecrementStockItems));
-
-        // 删除购物车商品 TODO 芋艿:待实现
-
-        // 扣减积分,抵扣金额 TODO 芋艿:待实现
-
-        // 有使用优惠券时更新
-
-        // 增加订单日志 TODO 芋艿:待实现
-
-        // 构建预支付请求参数
-        // TODO @LeeYan9: 需要更新到订单上
-//        PayOrderInfoCreateReqDTO payOrderCreateReqDTO = PayOrderConvert.INSTANCE.convert(tradeOrderDO);
-//        fillPayOrderInfoFromItems(payOrderCreateReqDTO, tradeOrderItems);
-        // 生成预支付
+        List<TradeOrderItemDO> tradeOrderItems = createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus);
 
+        // 订单创建完后的逻辑
+        afterCreateTradeOrder(userId, createReqVO, tradeOrderDO, tradeOrderItems);
         // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
         return tradeOrderDO.getId();
     }
@@ -242,10 +231,44 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         return tradeOrderDO;
     }
 
-    private void createTradeOrderItems(TradeOrderDO tradeOrderDO,
-                                       List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) {
+    private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO,
+                                                         List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) {
         List<TradeOrderItemDO> tradeOrderItemDOs = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, orderItems, skus);
         tradeOrderItemMapper.insertBatch(tradeOrderItemDOs);
+        return tradeOrderItemDOs;
+    }
+
+    /**
+     * 执行创建完创建完订单后的逻辑
+     *
+     * 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等
+     *
+     * @param userId 用户编号
+     * @param createReqVO 创建订单请求
+     * @param tradeOrderDO 交易订单
+     */
+    private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
+                                       TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs) {
+        // 下单时扣减商品库存
+        productSkuApi.updateSkuStock(new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(tradeOrderItemDOs)));
+
+        // 删除购物车商品 TODO 芋艿:待实现
+
+        // 扣减积分,抵扣金额 TODO 芋艿:待实现
+
+        // 有使用优惠券时更新
+        if (createReqVO.getCouponId() != null) {
+            couponApi.useCoupon(new CouponUseReqDTO().setId(createReqVO.getCouponId()).setUserId(userId)
+                    .setOrderId(tradeOrderDO.getId()));
+        }
+
+        // 构建预支付请求参数
+        // TODO @LeeYan9: 需要更新到订单上
+//        PayOrderInfoCreateReqDTO payOrderCreateReqDTO = PayOrderConvert.INSTANCE.convert(tradeOrderDO);
+//        fillPayOrderInfoFromItems(payOrderCreateReqDTO, tradeOrderItems);
+        // 生成预支付
+
+        // 增加订单日志 TODO 芋艿:待实现
     }
 
 }

+ 26 - 4
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java

@@ -8,9 +8,11 @@ import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
 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.sku.dto.ProductSkuUpdateStockReqDTO;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
+import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
 import cn.iocoder.yudao.module.promotion.api.price.PriceApi;
 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
@@ -24,6 +26,7 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatcher;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Import;
 
@@ -37,6 +40,7 @@ import static java.util.Collections.singletonList;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
@@ -66,10 +70,8 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
     private PayOrderApi payOrderApi;
     @MockBean
     private AddressApi addressApi;
-
-    // 1, 3 个,50 块;打折 20;总和 = 60;42;
-    // 2, 4 个,20 块;打折 10;总和 = 40;28;
-    // 优惠劵,满 100 减 30
+    @MockBean
+    private CouponApi couponApi;
 
     @Test
     public void testCreateTradeOrder_success() {
@@ -205,6 +207,26 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
         assertEquals(tradeOrderItemDO02.getOrderDividePrice(), 25);
         assertEquals(tradeOrderItemDO02.getRefundStatus(), TradeOrderItemRefundStatusEnum.NONE.getStatus());
         assertEquals(tradeOrderItemDO02.getRefundTotal(), 0);
+        // 校验调用
+        verify(productSkuApi).updateSkuStock(argThat(new ArgumentMatcher<ProductSkuUpdateStockReqDTO>() {
+
+            @Override
+            public boolean matches(ProductSkuUpdateStockReqDTO updateStockReqDTO) {
+                assertEquals(updateStockReqDTO.getItems().size(), 2);
+                assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L);
+                assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3);
+                assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L);
+                assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4);
+                return true;
+            }
+
+        }));
+        verify(couponApi).useCoupon(argThat(reqDTO -> {
+            assertEquals(reqDTO.getId(), reqVO.getCouponId());
+            assertEquals(reqDTO.getUserId(), userId);
+            assertEquals(reqDTO.getOrderId(), tradeOrderId);
+            return true;
+        }));
 //        //mock 支付订单信息
 //        when(payOrderApi.createPayOrder(any())).thenReturn(1L);