diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 5b2bd8f22..a9e7cc6c2 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.order; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.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); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/price/PriceConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/price/PriceConvert.java deleted file mode 100644 index dd8bda851..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/price/PriceConvert.java +++ /dev/null @@ -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); - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java index dfa4ed9af..d185f6cd3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java +++ b/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; /** * 商品属性 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java index 572a654ba..f9e635fac 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java +++ b/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); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 59e08987f..56d3124c0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -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 skus = validateSkuSaleable(createReqVO.getItems()); // 商品 SPU 检查:可售状态 - List 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; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/main/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java deleted file mode 100644 index a2c197267..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java +++ /dev/null @@ -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()); - } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql deleted file mode 100644 index 16e441516..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql +++ /dev/null @@ -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") -); - diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java new file mode 100644 index 000000000..717d90d91 --- /dev/null +++ b/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()); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/application-unit-test.yaml b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml similarity index 100% rename from yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/application-unit-test.yaml rename to yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/logback.xml b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml similarity index 100% rename from yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/logback.xml rename to yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/clean.sql b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql similarity index 100% rename from yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/clean.sql rename to yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 000000000..25d17d744 --- /dev/null +++ b/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 '交易订单明细表';