Переглянути джерело

trade:创建订单接口的后端实现的单元测试 50%

YunaiV 2 роки тому
батько
коміт
bc2aa78f70
12 змінених файлів з 247 додано та 233 видалено
  1. 6 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  2. 0 20
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/price/PriceConvert.java
  3. 13 13
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
  4. 3 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java
  5. 8 8
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
  6. 0 110
      yudao-module-mall/yudao-module-trade-biz/src/main/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
  7. 0 78
      yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql
  8. 145 0
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
  9. 0 0
      yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml
  10. 0 0
      yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml
  11. 0 0
      yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql
  12. 72 0
      yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

+ 6 - 2
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.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;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
@@ -33,7 +34,7 @@ public interface TradeOrderConvert {
             @Mapping(source = "address.postCode", target = "receiverPostCode"),
             @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"),
     })
-    TradeOrderDO convert(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO,
+    TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
                          PriceCalculateRespDTO.Order order, AddressRespDTO address);
 
     @Mappings({
@@ -49,10 +50,13 @@ public interface TradeOrderConvert {
             TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId()));
             tradeOrderItemDO.setOrderId(tradeOrderDO.getId());
             tradeOrderItemDO.setUserId(tradeOrderDO.getUserId());
-            tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus());
+            tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()).setRefundTotal(0); // 退款信息
 //            tradeOrderItemDO.setCommented(false);
             return tradeOrderItemDO;
         });
     }
 
+    @Mapping(source = "userId" , target = "userId")
+    PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId);
+
 }

+ 0 - 20
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/price/PriceConvert.java

@@ -1,20 +0,0 @@
-package cn.iocoder.yudao.module.trade.convert.price;
-
-import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
-import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-import org.mapstruct.factory.Mappers;
-
-@Mapper
-public interface PriceConvert {
-
-    PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class);
-
-    @Mappings(
-            @Mapping(source = "userId" , target = "userId")
-    )
-    PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId);
-
-}

+ 13 - 13
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java

@@ -138,19 +138,19 @@ public class TradeOrderItemDO extends BaseDO {
      * 枚举 {@link TradeOrderItemRefundStatusEnum}
      */
     private Integer refundStatus; // TODO 芋艿:可以考虑去查
-//    // 如上字段,举个例子:
-//    // 假设购买三个,即 stock = 3 。
-//    // originPrice = 15
-//    // 使用限时折扣(单品优惠)8 折,buyPrice = 12
-//    // 开始算总的价格
-//    // buyTotal = buyPrice * stock = 12 * 3 = 36
-//    // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11
-//    // presentTotal = buyTotal - discountTotal = 24 - 11 = 13
-//    // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33
-//    /**
-//     * 退款总金额,单位:分 TODO
-//     */
-//    private Integer refundTotal;
+    // 如上字段,举个例子:
+    // 假设购买三个,即 stock = 3 。
+    // originPrice = 15
+    // 使用限时折扣(单品优惠)8 折,buyPrice = 12
+    // 开始算总的价格
+    // buyTotal = buyPrice * stock = 12 * 3 = 36
+    // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11
+    // presentTotal = buyTotal - discountTotal = 24 - 11 = 13
+    // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33
+    /**
+     * 退款总金额,单位:分 TODO
+     */
+    private Integer refundTotal;
 
     /**
      * 商品属性

+ 3 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java

@@ -14,9 +14,10 @@ public interface TradeOrderService {
      * 创建交易订单
      *
      * @param loginUserId 登录用户
-     * @param clientIp 用户 IP 地址
+     * @param userIp 用户 IP 地址
      * @param createReqVO 创建交易订单请求模型
      * @return 交易订单的编号
      */
-    Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO);
+    Long createTradeOrder(Long loginUserId, String userIp, AppTradeOrderCreateReqVO createReqVO);
+
 }

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

@@ -18,12 +18,10 @@ 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.price.PriceApi;
-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;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item;
 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
-import cn.iocoder.yudao.module.trade.convert.price.PriceConvert;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
@@ -82,20 +80,19 @@ public class TradeOrderServiceImpl implements TradeOrderService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public Long createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO) {
+    public Long createTradeOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
         // 商品 SKU 检查:可售状态、库存
         List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems());
         // 商品 SPU 检查:可售状态
-        List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId));
+        validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId));
         // 用户收件地址的校验
         AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId());
 
         // 价格计算
-        PriceCalculateReqDTO priceCalculateReqDTO = PriceConvert.INSTANCE.convert(createReqVO, userId);
-        PriceCalculateRespDTO priceResp = priceApi.calculatePrice(priceCalculateReqDTO);
+        PriceCalculateRespDTO priceResp = priceApi.calculatePrice(TradeOrderConvert.INSTANCE.convert(createReqVO, userId));
 
         // 插入 TradeOrderDO 订单
-        TradeOrderDO tradeOrderDO = createTradeOrder(userId, clientIp, createReqVO, priceResp.getOrder(), address);
+        TradeOrderDO tradeOrderDO = createTradeOrder(userId, userIp, createReqVO, priceResp.getOrder(), address);
         // 插入 TradeOrderItemDO 订单项
         createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus);
 
@@ -208,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         // 校验是否存在禁用的 SPU
         ProductSpuRespDTO spu = CollectionUtils.findFirst(spus,
                 spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus()));
-        if (Objects.isNull(spu)) {
+        if (spu != null) {
             throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE);
         }
         return spus;
@@ -238,6 +235,9 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
         tradeOrderDO.setProductCount(getSumValue(order.getItems(),  PriceCalculateRespDTO.OrderItem::getCount, Integer::sum));
         tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
+        tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息
+        tradeOrderDO.setDeliveryStatus(false); // 物流信息
+        tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息
         tradeOrderMapper.insert(tradeOrderDO);
         return tradeOrderDO;
     }

+ 0 - 110
yudao-module-mall/yudao-module-trade-biz/src/main/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java

@@ -1,110 +0,0 @@
-package cn.iocoder.yudao.module.trade.service.order;
-
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
-import cn.iocoder.yudao.module.promotion.api.price.PriceApi;
-import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
-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.spu.ProductSpuApi;
-import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO;
-import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
-import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
-import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
-import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
-import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper;
-import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
-import com.google.common.collect.Lists;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.context.annotation.Import;
-
-import javax.annotation.Resource;
-import java.util.Collections;
-
-import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomInteger;
-import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
-
-// TODO @芋艿: 单测的 review; 最后搞;
-/**
- * @author LeeYan9
- * @since 2022-09-07
- */
-@Import({TradeOrderServiceImpl.class, TradeOrderConfig.class})
-class TradeOrderServiceTest extends BaseDbUnitTest {
-
-
-    @Resource
-    TradeOrderService tradeOrderService;
-    @Resource
-    TradeOrderMapper tradeOrderMapper;
-    @Resource
-    TradeOrderItemMapper tradeOrderItemMapper;
-    @MockBean
-    ProductSpuApi productSpuApi;
-    @MockBean
-    ProductSkuApi productSkuApi;
-    @MockBean
-    PriceApi priceApi;
-    @MockBean
-    private PayOrderApi payOrderApi;
-
-    @Test
-    void testCreateTradeOrder_success() {
-        // mock 商品SPU数据
-        SpuInfoRespDTO spuInfoRespDTO = randomPojo(SpuInfoRespDTO.class, spuInfo -> {
-            spuInfo.setId(1L);
-            spuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus());
-        });
-        when(productSpuApi.getSpuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(spuInfoRespDTO));
-        // mock 商品SkU数据
-        ProductSkuRespDTO skuInfoRespDTO = randomPojo(ProductSkuRespDTO.class, skuInfo -> {
-            skuInfo.setId(1L);
-            skuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus());
-            skuInfo.setStock(randomInteger());
-            skuInfo.setSpuId(1L);
-        });
-        when(productSkuApi.getSkuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(skuInfoRespDTO));
-        // mock 价格信息
-        PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> {
-            PriceCalculateRespDTO.OrderItem item = priceCalculateRespDTO.getOrder().getItems().get(0);
-            item.setSkuId(1L);
-            item.setCount(2);
-            priceCalculateRespDTO.getOrder().setItems(Collections.singletonList(item));
-        });
-        when(priceApi.calculatePrice(any())).thenReturn(calculateRespDTO);
-        //mock 支付订单信息
-        when(payOrderApi.createPayOrder(any())).thenReturn(1L);
-
-        // 准备请求数据
-        AppTradeOrderCreateReqVO tradeOrderCreateReqVO = randomPojo(AppTradeOrderCreateReqVO.class, reqVO -> {
-            AppTradeOrderCreateReqVO.Item item = randomPojo(AppTradeOrderCreateReqVO.Item.class, o -> {
-                o.setSkuId(1L);
-                o.setCount(2);
-            });
-            reqVO.setItems(Collections.singletonList(item));
-        });
-        // 创建交易订单,支付订单记录
-        Long payOrderId = tradeOrderService.createTradeOrder(1L, "127.0.0.1", tradeOrderCreateReqVO);
-        //断言交易订单
-        TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(TradeOrderDO::getUserId, 1L);
-        assertNotNull(tradeOrderDO);
-        //价格&用户
-        assertEquals(calculateRespDTO.getOrder().getPayPrice(), tradeOrderDO.getPayPrice());
-        assertEquals(1L, tradeOrderDO.getUserId());
-        //断言交易订单项
-        TradeOrderItemDO tradeOrderItemDO = tradeOrderItemMapper.selectOne(TradeOrderItemDO::getOrderId, tradeOrderDO.getId());
-        assertNotNull(tradeOrderDO);
-        //商品&用户
-        assertEquals(skuInfoRespDTO.getId(), tradeOrderItemDO.getSkuId());
-        assertEquals(1L, tradeOrderItemDO.getUserId());
-        //价格
-        assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice());
-    }
-
-}

+ 0 - 78
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql

@@ -1,78 +0,0 @@
-/**todo cancelType 设置默认值 0?*/
-
-CREATE TABLE IF NOT EXISTS `trade_order`
-(
-    `id` number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    `sn`                      varchar(32)     NOT NULL,
-    `type`                    int             NOT NULL,
-    `terminal`                int             NOT NULL,
-    `user_id`                 bigint unsigned NOT NULL,
-    `user_ip`                 varchar(30)     NOT NULL,
-    `user_remark`             varchar(200),
-    `status`                  int             NOT NULL,
-    `product_count`           int             NOT NULL,
-    `cancel_type`             int                      DEFAULT NULL,
-    `remark`                  varchar(200),
-    `payed`                   bit(1)          NOT NULL DEFAULT FALSE,
-    `pay_time`                datetime                 DEFAULT NULL,
-    `finish_time`             datetime                 DEFAULT NULL,
-    `cancel_time`             datetime                 DEFAULT NULL,
-    `sku_original_price`      int             NOT NULL DEFAULT '0',
-    `sku_promotion_price`     int             NOT NULL DEFAULT '0',
-    `order_promotion_price`   int             NOT NULL DEFAULT '0',
-    `delivery_price`          int             NOT NULL DEFAULT '0',
-    `pay_price`               int                      DEFAULT '0',
-    `pay_order_id`            int                      DEFAULT NULL,
-    `pay_channel`             int                      DEFAULT NULL,
-    `delivery_type`           int             NOT NULL DEFAULT '1',
-    `actual_delivery_type`    int             NOT NULL DEFAULT '1',
-    `delivery_template_id`     int                      DEFAULT NULL,
-    `express_no`              int                      DEFAULT NULL,
-    `delivery_status`         bit(1)          NOT NULL DEFAULT FALSE,
-    `delivery_time`           datetime                 DEFAULT NULL,
-    `receive_time`            datetime                 DEFAULT NULL,
-    `receiver_name`           varchar(20)              DEFAULT NULL,
-    `receiver_mobile`         varchar(20)              DEFAULT NULL,
-    `receiver_area_id`        int                      DEFAULT NULL,
-    `receiver_post_code`      int                      DEFAULT NULL,
-    `receiver_detail_address` varchar(255)             DEFAULT NULL,
-    `refund_status`           int             NOT NULL DEFAULT '0',
-    `refund_price`            int             NOT NULL DEFAULT '0',
-    `coupon_id`               bigint unsigned          DEFAULT NULL,
-    `creator`                 varchar(64)              DEFAULT '',
-    `create_time`             datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    `updater`                 varchar(64)              DEFAULT '',
-    `update_time`             datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    `deleted`                 bit(1)          NOT NULL DEFAULT FALSE,
-    PRIMARY KEY ("id")
-);
-
-
-CREATE TABLE IF NOT EXISTS `trade_order_item`
-(
-    `id` number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    `user_id`               bigint unsigned NOT NULL,
-    `order_id`              bigint unsigned NOT NULL,
-    `spu_id`                bigint unsigned NOT NULL,
-    `sku_id`                bigint unsigned NOT NULL,
-    `properties`            json                     DEFAULT NULL,
-    `name`                  varchar(128)             DEFAULT NULL,
-    `pic_url`               varchar(200)             DEFAULT NULL,
-    `count`                 int             NOT NULL,
-    `commented`             bit(1)                   DEFAULT NULL,
-    `original_price`        int             NOT NULL DEFAULT '0',
-    `total_original_price`  int             NOT NULL DEFAULT '0',
-    `total_promotion_price` int             NOT NULL DEFAULT '0',
-    `present_price`         int             NOT NULL DEFAULT '0',
-    `total_present_price`   int             NOT NULL DEFAULT '0',
-    `total_pay_price`       int             NOT NULL DEFAULT '0',
-    `refund_status`         int             NOT NULL DEFAULT '0',
-    `refund_total`          int             NOT NULL DEFAULT '0',
-    `creator`               varchar(64)              DEFAULT '',
-    `create_time`           datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    `updater`               varchar(64)              DEFAULT '',
-    `update_time`           datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    `deleted`               bit(1)                   DEFAULT FALSE,
-    PRIMARY KEY ("id")
-);
-

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

@@ -0,0 +1,145 @@
+package cn.iocoder.yudao.module.trade.service.order;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.member.api.address.AddressApi;
+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.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.price.PriceApi;
+import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
+import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
+import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
+import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper;
+import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+
+import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link TradeOrderServiceImpl} 的单元测试类
+ *
+ * @author LeeYan9
+ * @since 2022-09-07
+ */
+@Import({TradeOrderServiceImpl.class, TradeOrderConfig.class})
+class TradeOrderServiceTest extends BaseDbUnitTest {
+
+    @Resource
+    private TradeOrderServiceImpl tradeOrderService;
+
+    @Resource
+    private TradeOrderMapper tradeOrderMapper;
+    @Resource
+    private TradeOrderItemMapper tradeOrderItemMapper;
+
+    @MockBean
+    private ProductSpuApi productSpuApi;
+    @MockBean
+    private ProductSkuApi productSkuApi;
+    @MockBean
+    private PriceApi priceApi;
+    @MockBean
+    private PayOrderApi payOrderApi;
+    @MockBean
+    private AddressApi addressApi;
+
+    // 1, 3 个,50 块;打折 20;总和 = 60;42;
+    // 2, 4 个,20 块;打折 10;总和 = 40;28;
+    // 优惠劵,满 100 减 30
+
+    @Test
+    public void testCreateTradeOrder_success() {
+        // 准备参数
+        Long userId = 100L;
+        String clientIp = "127.0.0.1";
+        AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()
+                .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)
+                .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),
+                        new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));
+        // mock 方法(商品 SKU 检查)
+        ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L)
+                .setPrice(50).setStock(100).setStatus(CommonStatusEnum.ENABLE.getStatus()));
+        ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L)
+                .setPrice(20).setStock(50).setStatus(CommonStatusEnum.ENABLE.getStatus()));
+        when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02));
+        // mock 方法(商品 SPU 检查)
+        ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L)
+                .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
+        ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L)
+                .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
+        when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02));
+        // mock 方法(用户收件地址的校验)
+        AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿")
+                .setMobile("15601691300").setAreaId(3306L).setPostCode("85757").setDetailAddress("土豆村");
+        when(addressApi.getAddress(eq(userId), eq(10L))).thenReturn(addressRespDTO);
+        // mock 方法(价格计算)
+        PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem()
+                .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50)
+                .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35);
+        PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem()
+                .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20)
+                .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25);
+        PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order()
+                .setOriginalPrice(230).setOrderPrice(100).setDiscountPrice(0).setCouponPrice(30)
+                .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30)
+                .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02));
+        when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> {
+            assertEquals(priceCalculateReqDTO.getUserId(), 100L);
+            assertEquals(priceCalculateReqDTO.getCouponId(), 101L);
+            assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L);
+            assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3);
+            assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L);
+            assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4);
+            return true;
+        }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));
+
+        // 调用方法
+        Long tradeOrderId = tradeOrderService.createTradeOrder(userId, clientIp, reqVO);
+        System.out.println(tradeOrderId);
+
+//        // mock 价格信息
+//        PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> {
+//            PriceCalculateRespDTO.OrderItem item = priceCalculateRespDTO.getOrder().getItems().get(0);
+//            item.setSkuId(1L);
+//            item.setCount(2);
+//            priceCalculateRespDTO.getOrder().setItems(Collections.singletonList(item));
+//        });
+//        when(priceApi.calculatePrice(any())).thenReturn(calculateRespDTO);
+//        //mock 支付订单信息
+//        when(payOrderApi.createPayOrder(any())).thenReturn(1L);
+
+
+//        // 创建交易订单,支付订单记录
+//        Long payOrderId = tradeOrderService.createTradeOrder(1L, "127.0.0.1", tradeOrderCreateReqVO);
+//        //断言交易订单
+//        TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(TradeOrderDO::getUserId, 1L);
+//        assertNotNull(tradeOrderDO);
+//        //价格&用户
+//        assertEquals(calculateRespDTO.getOrder().getPayPrice(), tradeOrderDO.getPayPrice());
+//        assertEquals(1L, tradeOrderDO.getUserId());
+//        //断言交易订单项
+//        TradeOrderItemDO tradeOrderItemDO = tradeOrderItemMapper.selectOne(TradeOrderItemDO::getOrderId, tradeOrderDO.getId());
+//        assertNotNull(tradeOrderDO);
+//        //商品&用户
+//        assertEquals(skuInfoRespDTO.getId(), tradeOrderItemDO.getSkuId());
+//        assertEquals(1L, tradeOrderItemDO.getUserId());
+//        //价格
+//        assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice());
+    }
+
+}

+ 0 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/application-unit-test.yaml → yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml


+ 0 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/logback.xml → yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml


+ 0 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/clean.sql → yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql


+ 72 - 0
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

@@ -0,0 +1,72 @@
+CREATE TABLE IF NOT EXISTS "trade_order" (
+     "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+     "no" varchar NOT NULL,
+     "type" int NOT NULL,
+     "terminal" int NOT NULL,
+     "user_id" bigint NOT NULL,
+     "user_ip" varchar NOT NULL,
+     "user_remark" varchar,
+     "status" int NOT NULL,
+     "product_count" int NOT NULL,
+     "cancel_type" int,
+     "remark" varchar,
+     "payed" bit NOT NULL,
+     "pay_time" datetime,
+     "finish_time" datetime,
+     "cancel_time" datetime,
+     "original_price" int NOT NULL,
+     "order_price" int NOT NULL,
+     "discount_price" int NOT NULL,
+     "delivery_price" int NOT NULL,
+     "adjust_price" int NOT NULL,
+     "pay_price" int NOT NULL,
+     "pay_order_id" int,
+     "pay_channel" int,
+     "delivery_templateid" int,
+     "express_no" int,
+     "delivery_status" bit NOT NULL,
+     "delivery_time" datetime,
+     "receive_time" datetime,
+     "receiver_name" varchar NOT NULL,
+     "receiver_mobile" varchar NOT NULL,
+     "receiver_area_id" int NOT NULL,
+     "receiver_post_code" int,
+     "receiver_detail_address" varchar NOT NULL,
+     "refund_status" int NOT NULL,
+     "refund_price" int NOT NULL,
+     "coupon_id" bigint NOT NULL,
+     "coupon_price" int NOT NULL,
+     "point_price" int NOT NULL,
+     "creator" varchar DEFAULT '',
+     "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+     "updater" varchar DEFAULT '',
+     "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+     "deleted" bit NOT NULL DEFAULT FALSE,
+     PRIMARY KEY ("id")
+) COMMENT '交易订单表';
+
+CREATE TABLE IF NOT EXISTS "trade_order_item" (
+      "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+      "user_id" bigint NOT NULL,
+      "order_id" bigint NOT NULL,
+      "spu_id" bigint NOT NULL,
+      "sku_id" bigint NOT NULL,
+      "properties" varchar,
+      "name" varchar NOT NULL,
+      "pic_url" varchar,
+      "count" int NOT NULL,
+      "original_price" int NOT NULL,
+      "original_unit_price" int NOT NULL,
+      "discount_price" int NOT NULL,
+      "pay_price" int NOT NULL,
+      "order_part_price" int NOT NULL,
+      "order_divide_price" int NOT NULL,
+      "refund_status" int NOT NULL,
+      "refund_total" int NOT NULL,
+      "creator" varchar DEFAULT '',
+      "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+      "updater" varchar DEFAULT '',
+      "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+      "deleted" bit NOT NULL DEFAULT FALSE,
+      PRIMARY KEY ("id")
+) COMMENT '交易订单明细表';