Commit bc2aa78f706ca45ae1e4e715de56eb031e001d3c

Authored by YunaiV
1 parent 01d10b51

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

Showing 12 changed files with 247 additions and 233 deletions
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; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.order;
3 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 3 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 4 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  6 +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
6 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; 7 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
7 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; 8 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
8 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 9 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
@@ -33,7 +34,7 @@ public interface TradeOrderConvert { @@ -33,7 +34,7 @@ public interface TradeOrderConvert {
33 @Mapping(source = "address.postCode", target = "receiverPostCode"), 34 @Mapping(source = "address.postCode", target = "receiverPostCode"),
34 @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), 35 @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"),
35 }) 36 })
36 - TradeOrderDO convert(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, 37 + TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
37 PriceCalculateRespDTO.Order order, AddressRespDTO address); 38 PriceCalculateRespDTO.Order order, AddressRespDTO address);
38 39
39 @Mappings({ 40 @Mappings({
@@ -49,10 +50,13 @@ public interface TradeOrderConvert { @@ -49,10 +50,13 @@ public interface TradeOrderConvert {
49 TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId())); 50 TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId()));
50 tradeOrderItemDO.setOrderId(tradeOrderDO.getId()); 51 tradeOrderItemDO.setOrderId(tradeOrderDO.getId());
51 tradeOrderItemDO.setUserId(tradeOrderDO.getUserId()); 52 tradeOrderItemDO.setUserId(tradeOrderDO.getUserId());
52 - tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()); 53 + tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()).setRefundTotal(0); // 退款信息
53 // tradeOrderItemDO.setCommented(false); 54 // tradeOrderItemDO.setCommented(false);
54 return tradeOrderItemDO; 55 return tradeOrderItemDO;
55 }); 56 });
56 } 57 }
57 58
  59 + @Mapping(source = "userId" , target = "userId")
  60 + PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId);
  61 +
58 } 62 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/price/PriceConvert.java deleted
1 -package cn.iocoder.yudao.module.trade.convert.price;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
4 -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;  
5 -import org.mapstruct.Mapper;  
6 -import org.mapstruct.Mapping;  
7 -import org.mapstruct.Mappings;  
8 -import org.mapstruct.factory.Mappers;  
9 -  
10 -@Mapper  
11 -public interface PriceConvert {  
12 -  
13 - PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class);  
14 -  
15 - @Mappings(  
16 - @Mapping(source = "userId" , target = "userId")  
17 - )  
18 - PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId);  
19 -  
20 -}  
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 { @@ -138,19 +138,19 @@ public class TradeOrderItemDO extends BaseDO {
138 * 枚举 {@link TradeOrderItemRefundStatusEnum} 138 * 枚举 {@link TradeOrderItemRefundStatusEnum}
139 */ 139 */
140 private Integer refundStatus; // TODO 芋艿:可以考虑去查 140 private Integer refundStatus; // TODO 芋艿:可以考虑去查
141 -// // 如上字段,举个例子:  
142 -// // 假设购买三个,即 stock = 3 。  
143 -// // originPrice = 15  
144 -// // 使用限时折扣(单品优惠)8 折,buyPrice = 12  
145 -// // 开始算总的价格  
146 -// // buyTotal = buyPrice * stock = 12 * 3 = 36  
147 -// // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11  
148 -// // presentTotal = buyTotal - discountTotal = 24 - 11 = 13  
149 -// // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33  
150 -// /**  
151 -// * 退款总金额,单位:分 TODO  
152 -// */  
153 -// private Integer refundTotal; 141 + // 如上字段,举个例子:
  142 + // 假设购买三个,即 stock = 3 。
  143 + // originPrice = 15
  144 + // 使用限时折扣(单品优惠)8 折,buyPrice = 12
  145 + // 开始算总的价格
  146 + // buyTotal = buyPrice * stock = 12 * 3 = 36
  147 + // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11
  148 + // presentTotal = buyTotal - discountTotal = 24 - 11 = 13
  149 + // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33
  150 + /**
  151 + * 退款总金额,单位:分 TODO
  152 + */
  153 + private Integer refundTotal;
154 154
155 /** 155 /**
156 * 商品属性 156 * 商品属性
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 { @@ -14,9 +14,10 @@ public interface TradeOrderService {
14 * 创建交易订单 14 * 创建交易订单
15 * 15 *
16 * @param loginUserId 登录用户 16 * @param loginUserId 登录用户
17 - * @param clientIp 用户 IP 地址 17 + * @param userIp 用户 IP 地址
18 * @param createReqVO 创建交易订单请求模型 18 * @param createReqVO 创建交易订单请求模型
19 * @return 交易订单的编号 19 * @return 交易订单的编号
20 */ 20 */
21 - Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO); 21 + Long createTradeOrder(Long loginUserId, String userIp, AppTradeOrderCreateReqVO createReqVO);
  22 +
22 } 23 }
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; @@ -18,12 +18,10 @@ import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
18 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 18 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
19 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; 19 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
20 import cn.iocoder.yudao.module.promotion.api.price.PriceApi; 20 import cn.iocoder.yudao.module.promotion.api.price.PriceApi;
21 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;  
22 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; 21 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
23 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; 22 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
24 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item; 23 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item;
25 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; 24 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
26 -import cn.iocoder.yudao.module.trade.convert.price.PriceConvert;  
27 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 25 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
28 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 26 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
29 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; 27 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
@@ -82,20 +80,19 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -82,20 +80,19 @@ public class TradeOrderServiceImpl implements TradeOrderService {
82 80
83 @Override 81 @Override
84 @Transactional(rollbackFor = Exception.class) 82 @Transactional(rollbackFor = Exception.class)
85 - public Long createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { 83 + public Long createTradeOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
86 // 商品 SKU 检查:可售状态、库存 84 // 商品 SKU 检查:可售状态、库存
87 List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); 85 List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems());
88 // 商品 SPU 检查:可售状态 86 // 商品 SPU 检查:可售状态
89 - List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); 87 + validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId));
90 // 用户收件地址的校验 88 // 用户收件地址的校验
91 AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); 89 AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId());
92 90
93 // 价格计算 91 // 价格计算
94 - PriceCalculateReqDTO priceCalculateReqDTO = PriceConvert.INSTANCE.convert(createReqVO, userId);  
95 - PriceCalculateRespDTO priceResp = priceApi.calculatePrice(priceCalculateReqDTO); 92 + PriceCalculateRespDTO priceResp = priceApi.calculatePrice(TradeOrderConvert.INSTANCE.convert(createReqVO, userId));
96 93
97 // 插入 TradeOrderDO 订单 94 // 插入 TradeOrderDO 订单
98 - TradeOrderDO tradeOrderDO = createTradeOrder(userId, clientIp, createReqVO, priceResp.getOrder(), address); 95 + TradeOrderDO tradeOrderDO = createTradeOrder(userId, userIp, createReqVO, priceResp.getOrder(), address);
99 // 插入 TradeOrderItemDO 订单项 96 // 插入 TradeOrderItemDO 订单项
100 createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); 97 createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus);
101 98
@@ -208,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -208,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
208 // 校验是否存在禁用的 SPU 205 // 校验是否存在禁用的 SPU
209 ProductSpuRespDTO spu = CollectionUtils.findFirst(spus, 206 ProductSpuRespDTO spu = CollectionUtils.findFirst(spus,
210 spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus())); 207 spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus()));
211 - if (Objects.isNull(spu)) { 208 + if (spu != null) {
212 throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE); 209 throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE);
213 } 210 }
214 return spus; 211 return spus;
@@ -238,6 +235,9 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -238,6 +235,9 @@ public class TradeOrderServiceImpl implements TradeOrderService {
238 tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); 235 tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
239 tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); 236 tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum));
240 tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? 237 tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
  238 + tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息
  239 + tradeOrderDO.setDeliveryStatus(false); // 物流信息
  240 + tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息
241 tradeOrderMapper.insert(tradeOrderDO); 241 tradeOrderMapper.insert(tradeOrderDO);
242 return tradeOrderDO; 242 return tradeOrderDO;
243 } 243 }
yudao-module-mall/yudao-module-trade-biz/src/main/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java deleted
1 -package cn.iocoder.yudao.module.trade.service.order;  
2 -  
3 -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;  
4 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;  
5 -import cn.iocoder.yudao.module.promotion.api.price.PriceApi;  
6 -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;  
7 -import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;  
8 -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;  
9 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;  
10 -import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;  
11 -import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO;  
12 -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;  
13 -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;  
14 -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;  
15 -import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;  
16 -import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper;  
17 -import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;  
18 -import com.google.common.collect.Lists;  
19 -import org.junit.jupiter.api.Test;  
20 -import org.springframework.boot.test.mock.mockito.MockBean;  
21 -import org.springframework.context.annotation.Import;  
22 -  
23 -import javax.annotation.Resource;  
24 -import java.util.Collections;  
25 -  
26 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomInteger;  
27 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;  
28 -import static org.junit.jupiter.api.Assertions.assertEquals;  
29 -import static org.junit.jupiter.api.Assertions.assertNotNull;  
30 -import static org.mockito.ArgumentMatchers.any;  
31 -import static org.mockito.Mockito.when;  
32 -  
33 -// TODO @芋艿: 单测的 review; 最后搞;  
34 -/**  
35 - * @author LeeYan9  
36 - * @since 2022-09-07  
37 - */  
38 -@Import({TradeOrderServiceImpl.class, TradeOrderConfig.class})  
39 -class TradeOrderServiceTest extends BaseDbUnitTest {  
40 -  
41 -  
42 - @Resource  
43 - TradeOrderService tradeOrderService;  
44 - @Resource  
45 - TradeOrderMapper tradeOrderMapper;  
46 - @Resource  
47 - TradeOrderItemMapper tradeOrderItemMapper;  
48 - @MockBean  
49 - ProductSpuApi productSpuApi;  
50 - @MockBean  
51 - ProductSkuApi productSkuApi;  
52 - @MockBean  
53 - PriceApi priceApi;  
54 - @MockBean  
55 - private PayOrderApi payOrderApi;  
56 -  
57 - @Test  
58 - void testCreateTradeOrder_success() {  
59 - // mock 商品SPU数据  
60 - SpuInfoRespDTO spuInfoRespDTO = randomPojo(SpuInfoRespDTO.class, spuInfo -> {  
61 - spuInfo.setId(1L);  
62 - spuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus());  
63 - });  
64 - when(productSpuApi.getSpuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(spuInfoRespDTO));  
65 - // mock 商品SkU数据  
66 - ProductSkuRespDTO skuInfoRespDTO = randomPojo(ProductSkuRespDTO.class, skuInfo -> {  
67 - skuInfo.setId(1L);  
68 - skuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus());  
69 - skuInfo.setStock(randomInteger());  
70 - skuInfo.setSpuId(1L);  
71 - });  
72 - when(productSkuApi.getSkuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(skuInfoRespDTO));  
73 - // mock 价格信息  
74 - PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> {  
75 - PriceCalculateRespDTO.OrderItem item = priceCalculateRespDTO.getOrder().getItems().get(0);  
76 - item.setSkuId(1L);  
77 - item.setCount(2);  
78 - priceCalculateRespDTO.getOrder().setItems(Collections.singletonList(item));  
79 - });  
80 - when(priceApi.calculatePrice(any())).thenReturn(calculateRespDTO);  
81 - //mock 支付订单信息  
82 - when(payOrderApi.createPayOrder(any())).thenReturn(1L);  
83 -  
84 - // 准备请求数据  
85 - AppTradeOrderCreateReqVO tradeOrderCreateReqVO = randomPojo(AppTradeOrderCreateReqVO.class, reqVO -> {  
86 - AppTradeOrderCreateReqVO.Item item = randomPojo(AppTradeOrderCreateReqVO.Item.class, o -> {  
87 - o.setSkuId(1L);  
88 - o.setCount(2);  
89 - });  
90 - reqVO.setItems(Collections.singletonList(item));  
91 - });  
92 - // 创建交易订单,支付订单记录  
93 - Long payOrderId = tradeOrderService.createTradeOrder(1L, "127.0.0.1", tradeOrderCreateReqVO);  
94 - //断言交易订单  
95 - TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(TradeOrderDO::getUserId, 1L);  
96 - assertNotNull(tradeOrderDO);  
97 - //价格&用户  
98 - assertEquals(calculateRespDTO.getOrder().getPayPrice(), tradeOrderDO.getPayPrice());  
99 - assertEquals(1L, tradeOrderDO.getUserId());  
100 - //断言交易订单项  
101 - TradeOrderItemDO tradeOrderItemDO = tradeOrderItemMapper.selectOne(TradeOrderItemDO::getOrderId, tradeOrderDO.getId());  
102 - assertNotNull(tradeOrderDO);  
103 - //商品&用户  
104 - assertEquals(skuInfoRespDTO.getId(), tradeOrderItemDO.getSkuId());  
105 - assertEquals(1L, tradeOrderItemDO.getUserId());  
106 - //价格  
107 - assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice());  
108 - }  
109 -  
110 -}  
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql deleted
1 -/**todo cancelType 设置默认值 0?*/  
2 -  
3 -CREATE TABLE IF NOT EXISTS `trade_order`  
4 -(  
5 - `id` number NOT NULL GENERATED BY DEFAULT AS IDENTITY,  
6 - `sn` varchar(32) NOT NULL,  
7 - `type` int NOT NULL,  
8 - `terminal` int NOT NULL,  
9 - `user_id` bigint unsigned NOT NULL,  
10 - `user_ip` varchar(30) NOT NULL,  
11 - `user_remark` varchar(200),  
12 - `status` int NOT NULL,  
13 - `product_count` int NOT NULL,  
14 - `cancel_type` int DEFAULT NULL,  
15 - `remark` varchar(200),  
16 - `payed` bit(1) NOT NULL DEFAULT FALSE,  
17 - `pay_time` datetime DEFAULT NULL,  
18 - `finish_time` datetime DEFAULT NULL,  
19 - `cancel_time` datetime DEFAULT NULL,  
20 - `sku_original_price` int NOT NULL DEFAULT '0',  
21 - `sku_promotion_price` int NOT NULL DEFAULT '0',  
22 - `order_promotion_price` int NOT NULL DEFAULT '0',  
23 - `delivery_price` int NOT NULL DEFAULT '0',  
24 - `pay_price` int DEFAULT '0',  
25 - `pay_order_id` int DEFAULT NULL,  
26 - `pay_channel` int DEFAULT NULL,  
27 - `delivery_type` int NOT NULL DEFAULT '1',  
28 - `actual_delivery_type` int NOT NULL DEFAULT '1',  
29 - `delivery_template_id` int DEFAULT NULL,  
30 - `express_no` int DEFAULT NULL,  
31 - `delivery_status` bit(1) NOT NULL DEFAULT FALSE,  
32 - `delivery_time` datetime DEFAULT NULL,  
33 - `receive_time` datetime DEFAULT NULL,  
34 - `receiver_name` varchar(20) DEFAULT NULL,  
35 - `receiver_mobile` varchar(20) DEFAULT NULL,  
36 - `receiver_area_id` int DEFAULT NULL,  
37 - `receiver_post_code` int DEFAULT NULL,  
38 - `receiver_detail_address` varchar(255) DEFAULT NULL,  
39 - `refund_status` int NOT NULL DEFAULT '0',  
40 - `refund_price` int NOT NULL DEFAULT '0',  
41 - `coupon_id` bigint unsigned DEFAULT NULL,  
42 - `creator` varchar(64) DEFAULT '',  
43 - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,  
44 - `updater` varchar(64) DEFAULT '',  
45 - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
46 - `deleted` bit(1) NOT NULL DEFAULT FALSE,  
47 - PRIMARY KEY ("id")  
48 -);  
49 -  
50 -  
51 -CREATE TABLE IF NOT EXISTS `trade_order_item`  
52 -(  
53 - `id` number NOT NULL GENERATED BY DEFAULT AS IDENTITY,  
54 - `user_id` bigint unsigned NOT NULL,  
55 - `order_id` bigint unsigned NOT NULL,  
56 - `spu_id` bigint unsigned NOT NULL,  
57 - `sku_id` bigint unsigned NOT NULL,  
58 - `properties` json DEFAULT NULL,  
59 - `name` varchar(128) DEFAULT NULL,  
60 - `pic_url` varchar(200) DEFAULT NULL,  
61 - `count` int NOT NULL,  
62 - `commented` bit(1) DEFAULT NULL,  
63 - `original_price` int NOT NULL DEFAULT '0',  
64 - `total_original_price` int NOT NULL DEFAULT '0',  
65 - `total_promotion_price` int NOT NULL DEFAULT '0',  
66 - `present_price` int NOT NULL DEFAULT '0',  
67 - `total_present_price` int NOT NULL DEFAULT '0',  
68 - `total_pay_price` int NOT NULL DEFAULT '0',  
69 - `refund_status` int NOT NULL DEFAULT '0',  
70 - `refund_total` int NOT NULL DEFAULT '0',  
71 - `creator` varchar(64) DEFAULT '',  
72 - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,  
73 - `updater` varchar(64) DEFAULT '',  
74 - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
75 - `deleted` bit(1) DEFAULT FALSE,  
76 - PRIMARY KEY ("id")  
77 -);  
78 -  
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.member.api.address.AddressApi;
  6 +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  7 +import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
  8 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  9 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  10 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  11 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  12 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
  13 +import cn.iocoder.yudao.module.promotion.api.price.PriceApi;
  14 +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
  15 +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
  16 +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
  17 +import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper;
  18 +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
  19 +import org.junit.jupiter.api.Test;
  20 +import org.springframework.boot.test.mock.mockito.MockBean;
  21 +import org.springframework.context.annotation.Import;
  22 +
  23 +import javax.annotation.Resource;
  24 +import java.util.Arrays;
  25 +
  26 +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
  27 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  28 +import static org.junit.jupiter.api.Assertions.assertEquals;
  29 +import static org.mockito.ArgumentMatchers.argThat;
  30 +import static org.mockito.ArgumentMatchers.eq;
  31 +import static org.mockito.Mockito.when;
  32 +
  33 +/**
  34 + * {@link TradeOrderServiceImpl} 的单元测试类
  35 + *
  36 + * @author LeeYan9
  37 + * @since 2022-09-07
  38 + */
  39 +@Import({TradeOrderServiceImpl.class, TradeOrderConfig.class})
  40 +class TradeOrderServiceTest extends BaseDbUnitTest {
  41 +
  42 + @Resource
  43 + private TradeOrderServiceImpl tradeOrderService;
  44 +
  45 + @Resource
  46 + private TradeOrderMapper tradeOrderMapper;
  47 + @Resource
  48 + private TradeOrderItemMapper tradeOrderItemMapper;
  49 +
  50 + @MockBean
  51 + private ProductSpuApi productSpuApi;
  52 + @MockBean
  53 + private ProductSkuApi productSkuApi;
  54 + @MockBean
  55 + private PriceApi priceApi;
  56 + @MockBean
  57 + private PayOrderApi payOrderApi;
  58 + @MockBean
  59 + private AddressApi addressApi;
  60 +
  61 + // 1, 3 个,50 块;打折 20;总和 = 60;42;
  62 + // 2, 4 个,20 块;打折 10;总和 = 40;28;
  63 + // 优惠劵,满 100 减 30
  64 +
  65 + @Test
  66 + public void testCreateTradeOrder_success() {
  67 + // 准备参数
  68 + Long userId = 100L;
  69 + String clientIp = "127.0.0.1";
  70 + AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO()
  71 + .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true)
  72 + .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3),
  73 + new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4)));
  74 + // mock 方法(商品 SKU 检查)
  75 + ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L)
  76 + .setPrice(50).setStock(100).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  77 + ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L)
  78 + .setPrice(20).setStock(50).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  79 + when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02));
  80 + // mock 方法(商品 SPU 检查)
  81 + ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L)
  82 + .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
  83 + ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L)
  84 + .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
  85 + when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02));
  86 + // mock 方法(用户收件地址的校验)
  87 + AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿")
  88 + .setMobile("15601691300").setAreaId(3306L).setPostCode("85757").setDetailAddress("土豆村");
  89 + when(addressApi.getAddress(eq(userId), eq(10L))).thenReturn(addressRespDTO);
  90 + // mock 方法(价格计算)
  91 + PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem()
  92 + .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50)
  93 + .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35);
  94 + PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem()
  95 + .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20)
  96 + .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25);
  97 + PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order()
  98 + .setOriginalPrice(230).setOrderPrice(100).setDiscountPrice(0).setCouponPrice(30)
  99 + .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30)
  100 + .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02));
  101 + when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> {
  102 + assertEquals(priceCalculateReqDTO.getUserId(), 100L);
  103 + assertEquals(priceCalculateReqDTO.getCouponId(), 101L);
  104 + assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L);
  105 + assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3);
  106 + assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L);
  107 + assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4);
  108 + return true;
  109 + }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));
  110 +
  111 + // 调用方法
  112 + Long tradeOrderId = tradeOrderService.createTradeOrder(userId, clientIp, reqVO);
  113 + System.out.println(tradeOrderId);
  114 +
  115 +// // mock 价格信息
  116 +// PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> {
  117 +// PriceCalculateRespDTO.OrderItem item = priceCalculateRespDTO.getOrder().getItems().get(0);
  118 +// item.setSkuId(1L);
  119 +// item.setCount(2);
  120 +// priceCalculateRespDTO.getOrder().setItems(Collections.singletonList(item));
  121 +// });
  122 +// when(priceApi.calculatePrice(any())).thenReturn(calculateRespDTO);
  123 +// //mock 支付订单信息
  124 +// when(payOrderApi.createPayOrder(any())).thenReturn(1L);
  125 +
  126 +
  127 +// // 创建交易订单,支付订单记录
  128 +// Long payOrderId = tradeOrderService.createTradeOrder(1L, "127.0.0.1", tradeOrderCreateReqVO);
  129 +// //断言交易订单
  130 +// TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(TradeOrderDO::getUserId, 1L);
  131 +// assertNotNull(tradeOrderDO);
  132 +// //价格&用户
  133 +// assertEquals(calculateRespDTO.getOrder().getPayPrice(), tradeOrderDO.getPayPrice());
  134 +// assertEquals(1L, tradeOrderDO.getUserId());
  135 +// //断言交易订单项
  136 +// TradeOrderItemDO tradeOrderItemDO = tradeOrderItemMapper.selectOne(TradeOrderItemDO::getOrderId, tradeOrderDO.getId());
  137 +// assertNotNull(tradeOrderDO);
  138 +// //商品&用户
  139 +// assertEquals(skuInfoRespDTO.getId(), tradeOrderItemDO.getSkuId());
  140 +// assertEquals(1L, tradeOrderItemDO.getUserId());
  141 +// //价格
  142 +// assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice());
  143 + }
  144 +
  145 +}
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/application-unit-test.yaml renamed to yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/logback.xml renamed to yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/clean.sql renamed to yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql 0 → 100644
  1 +CREATE TABLE IF NOT EXISTS "trade_order" (
  2 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  3 + "no" varchar NOT NULL,
  4 + "type" int NOT NULL,
  5 + "terminal" int NOT NULL,
  6 + "user_id" bigint NOT NULL,
  7 + "user_ip" varchar NOT NULL,
  8 + "user_remark" varchar,
  9 + "status" int NOT NULL,
  10 + "product_count" int NOT NULL,
  11 + "cancel_type" int,
  12 + "remark" varchar,
  13 + "payed" bit NOT NULL,
  14 + "pay_time" datetime,
  15 + "finish_time" datetime,
  16 + "cancel_time" datetime,
  17 + "original_price" int NOT NULL,
  18 + "order_price" int NOT NULL,
  19 + "discount_price" int NOT NULL,
  20 + "delivery_price" int NOT NULL,
  21 + "adjust_price" int NOT NULL,
  22 + "pay_price" int NOT NULL,
  23 + "pay_order_id" int,
  24 + "pay_channel" int,
  25 + "delivery_templateid" int,
  26 + "express_no" int,
  27 + "delivery_status" bit NOT NULL,
  28 + "delivery_time" datetime,
  29 + "receive_time" datetime,
  30 + "receiver_name" varchar NOT NULL,
  31 + "receiver_mobile" varchar NOT NULL,
  32 + "receiver_area_id" int NOT NULL,
  33 + "receiver_post_code" int,
  34 + "receiver_detail_address" varchar NOT NULL,
  35 + "refund_status" int NOT NULL,
  36 + "refund_price" int NOT NULL,
  37 + "coupon_id" bigint NOT NULL,
  38 + "coupon_price" int NOT NULL,
  39 + "point_price" int NOT NULL,
  40 + "creator" varchar DEFAULT '',
  41 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  42 + "updater" varchar DEFAULT '',
  43 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  44 + "deleted" bit NOT NULL DEFAULT FALSE,
  45 + PRIMARY KEY ("id")
  46 +) COMMENT '交易订单表';
  47 +
  48 +CREATE TABLE IF NOT EXISTS "trade_order_item" (
  49 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  50 + "user_id" bigint NOT NULL,
  51 + "order_id" bigint NOT NULL,
  52 + "spu_id" bigint NOT NULL,
  53 + "sku_id" bigint NOT NULL,
  54 + "properties" varchar,
  55 + "name" varchar NOT NULL,
  56 + "pic_url" varchar,
  57 + "count" int NOT NULL,
  58 + "original_price" int NOT NULL,
  59 + "original_unit_price" int NOT NULL,
  60 + "discount_price" int NOT NULL,
  61 + "pay_price" int NOT NULL,
  62 + "order_part_price" int NOT NULL,
  63 + "order_divide_price" int NOT NULL,
  64 + "refund_status" int NOT NULL,
  65 + "refund_total" int NOT NULL,
  66 + "creator" varchar DEFAULT '',
  67 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  68 + "updater" varchar DEFAULT '',
  69 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  70 + "deleted" bit NOT NULL DEFAULT FALSE,
  71 + PRIMARY KEY ("id")
  72 +) COMMENT '交易订单明细表';