diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuUpdateStockReqDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuUpdateStockReqDTO.java index 0b854eeca..345c17cbd 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuUpdateStockReqDTO.java +++ b/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; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java index 43d34ccba..b29d612be 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java +++ b/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; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java index 0a3f7a155..2791ae5d3 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java +++ b/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); } 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 a94fb18fe..87ce87015 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 @@ -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))); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index a9e7cc6c2..15e9ae728 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/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 convertList(List list); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java deleted file mode 100644 index 916f2d9d8..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java +++ /dev/null @@ -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 convert(List list); - -} 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 56d3124c0..92b4e2ec7 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 @@ -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 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 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 orderItems, List skus) { + private List createTradeOrderItems(TradeOrderDO tradeOrderDO, + List orderItems, List skus) { List 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 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 芋艿:待实现 } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java index 85e469687..e8c908d5a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java +++ b/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() { + + @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);