Commit bc2aa78f706ca45ae1e4e715de56eb031e001d3c
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 | 3 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 4 | 4 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 6 | +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | |
| 6 | 7 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; |
| 7 | 8 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| 8 | 9 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| ... | ... | @@ -33,7 +34,7 @@ public interface TradeOrderConvert { |
| 33 | 34 | @Mapping(source = "address.postCode", target = "receiverPostCode"), |
| 34 | 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 | 38 | PriceCalculateRespDTO.Order order, AddressRespDTO address); |
| 38 | 39 | |
| 39 | 40 | @Mappings({ |
| ... | ... | @@ -49,10 +50,13 @@ public interface TradeOrderConvert { |
| 49 | 50 | TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId())); |
| 50 | 51 | tradeOrderItemDO.setOrderId(tradeOrderDO.getId()); |
| 51 | 52 | tradeOrderItemDO.setUserId(tradeOrderDO.getUserId()); |
| 52 | - tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()); | |
| 53 | + tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()).setRefundTotal(0); // 退款信息 | |
| 53 | 54 | // tradeOrderItemDO.setCommented(false); |
| 54 | 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 | 138 | * 枚举 {@link TradeOrderItemRefundStatusEnum} |
| 139 | 139 | */ |
| 140 | 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 | 14 | * 创建交易订单 |
| 15 | 15 | * |
| 16 | 16 | * @param loginUserId 登录用户 |
| 17 | - * @param clientIp 用户 IP 地址 | |
| 17 | + * @param userIp 用户 IP 地址 | |
| 18 | 18 | * @param createReqVO 创建交易订单请求模型 |
| 19 | 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 | 18 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 19 | 19 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; |
| 20 | 20 | import cn.iocoder.yudao.module.promotion.api.price.PriceApi; |
| 21 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | |
| 22 | 21 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; |
| 23 | 22 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| 24 | 23 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item; |
| 25 | 24 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; |
| 26 | -import cn.iocoder.yudao.module.trade.convert.price.PriceConvert; | |
| 27 | 25 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 28 | 26 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 29 | 27 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| ... | ... | @@ -82,20 +80,19 @@ public class TradeOrderServiceImpl implements TradeOrderService { |
| 82 | 80 | |
| 83 | 81 | @Override |
| 84 | 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 | 84 | // 商品 SKU 检查:可售状态、库存 |
| 87 | 85 | List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); |
| 88 | 86 | // 商品 SPU 检查:可售状态 |
| 89 | - List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); | |
| 87 | + validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); | |
| 90 | 88 | // 用户收件地址的校验 |
| 91 | 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 | 94 | // 插入 TradeOrderDO 订单 |
| 98 | - TradeOrderDO tradeOrderDO = createTradeOrder(userId, clientIp, createReqVO, priceResp.getOrder(), address); | |
| 95 | + TradeOrderDO tradeOrderDO = createTradeOrder(userId, userIp, createReqVO, priceResp.getOrder(), address); | |
| 99 | 96 | // 插入 TradeOrderItemDO 订单项 |
| 100 | 97 | createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); |
| 101 | 98 | |
| ... | ... | @@ -208,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { |
| 208 | 205 | // 校验是否存在禁用的 SPU |
| 209 | 206 | ProductSpuRespDTO spu = CollectionUtils.findFirst(spus, |
| 210 | 207 | spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus())); |
| 211 | - if (Objects.isNull(spu)) { | |
| 208 | + if (spu != null) { | |
| 212 | 209 | throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE); |
| 213 | 210 | } |
| 214 | 211 | return spus; |
| ... | ... | @@ -238,6 +235,9 @@ public class TradeOrderServiceImpl implements TradeOrderService { |
| 238 | 235 | tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); |
| 239 | 236 | tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); |
| 240 | 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 | 241 | tradeOrderMapper.insert(tradeOrderDO); |
| 242 | 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 '交易订单明细表'; | ... | ... |