创建交易订单-单元测试
parent
7bf20ec72e
commit
5889093a64
@ -0,0 +1,20 @@
|
|||||||
|
package cn.iocoder.yudao.module.market.api.price;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LeeYan9
|
||||||
|
* @since 2022-09-06
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class PriceApiImpl implements PriceApi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.yudao.module.product.api.sku;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
|
||||||
|
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
|
||||||
|
import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LeeYan9
|
||||||
|
* @since 2022-09-06
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class ProductSkuApiImpl implements ProductSkuApi {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProductSkuMapper productSkuMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SkuInfoRespDTO> getSkusByIds(Collection<Long> skuIds) {
|
||||||
|
if (CollectionUtils.isAnyEmpty(skuIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<ProductSkuDO> productSkuDOList = productSkuMapper.selectBatchIds(skuIds);
|
||||||
|
return ProductSkuConvert.INSTANCE.convertList03(productSkuDOList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void decrementStockBatch(SkuDecrementStockBatchReqDTO batchReqDTO) {
|
||||||
|
productSkuMapper.decrementStockBatch(batchReqDTO.getItems());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package cn.iocoder.yudao.module.product.api.spu;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
|
||||||
|
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
|
||||||
|
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LeeYan9
|
||||||
|
* @since 2022-09-06
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class ProductSpuApiImpl implements ProductSpuApi {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProductSpuMapper productSpuMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SpuInfoRespDTO> getSpusByIds(Collection<Long> spuIds) {
|
||||||
|
if (CollectionUtils.isAnyEmpty(spuIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds);
|
||||||
|
return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +1,33 @@
|
|||||||
package cn.iocoder.yudao.module.trade.convert.pay;
|
package cn.iocoder.yudao.module.trade.convert.pay;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.pay.api.order.PayOrderDataCreateReqDTO;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
import org.mapstruct.Named;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LeeYan9
|
* @author LeeYan9
|
||||||
* @since 2022-08-26
|
* @since 2022-08-26
|
||||||
*/
|
*/
|
||||||
|
@Mapper
|
||||||
public interface PayOrderConvert {
|
public interface PayOrderConvert {
|
||||||
|
|
||||||
PayOrderConvert INSTANCE = Mappers.getMapper(PayOrderConvert.class);
|
PayOrderConvert INSTANCE = Mappers.getMapper(PayOrderConvert.class);
|
||||||
|
|
||||||
|
@Mappings({
|
||||||
|
@Mapping(source = "payPrice", target = "amount"),
|
||||||
|
@Mapping(target = "expireTime", source = "cancelTime" , qualifiedByName = "convertCreateTimeToPayExpireTime")
|
||||||
|
})
|
||||||
|
PayOrderInfoCreateReqDTO convert(TradeOrderDO tradeOrderDO);
|
||||||
|
|
||||||
PayOrderDataCreateReqDTO convert(TradeOrderDO tradeOrderDO);
|
@Named("convertCreateTimeToPayExpireTime")
|
||||||
|
default Date convertCreateTimeToPayExpireTime(Date cancelTime) {
|
||||||
|
return DateUtil.offsetMinute(new Date(), 30);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.framework.order.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LeeYan9
|
||||||
|
* @since 2022-09-15
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(TradeOrderProperties.class)
|
||||||
|
public class TradeOrderConfig {
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.framework.order.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LeeYan9
|
||||||
|
* @since 2022-09-15
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = "yudao.trade.order")
|
||||||
|
@Data
|
||||||
|
@Validated
|
||||||
|
public class TradeOrderProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商户订单编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "商户订单编号不能为空")
|
||||||
|
private String merchantOrderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "应用编号不能为空")
|
||||||
|
private Long appId;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
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.market.api.price.PriceApi;
|
||||||
|
import cn.iocoder.yudao.module.market.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.SkuInfoRespDTO;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.getSpusByIds(Collections.singleton(1L))).thenReturn(Lists.newArrayList(spuInfoRespDTO));
|
||||||
|
// mock 商品SkU数据
|
||||||
|
SkuInfoRespDTO skuInfoRespDTO = randomPojo(SkuInfoRespDTO.class, skuInfo -> {
|
||||||
|
skuInfo.setId(1L);
|
||||||
|
skuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
skuInfo.setStock(randomInteger());
|
||||||
|
skuInfo.setSpuId(1L);
|
||||||
|
});
|
||||||
|
when(productSkuApi.getSkusByIds(Collections.singleton(1L))).thenReturn(Lists.newArrayList(skuInfoRespDTO));
|
||||||
|
// mock 价格信息
|
||||||
|
PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> {
|
||||||
|
PriceCalculateRespDTO.Item item = priceCalculateRespDTO.getItems().get(0);
|
||||||
|
item.setSkuId(1L);
|
||||||
|
item.setCount(2);
|
||||||
|
priceCalculateRespDTO.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.getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
<configuration>
|
||||||
|
<!-- 引用 Spring Boot 的 logback 基础配置 -->
|
||||||
|
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||||
|
</configuration>
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
DELETE FROM trade_order;
|
||||||
|
DELETE FROM trade_order_item;
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
/**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")
|
||||||
|
);
|
||||||
|
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.api.order;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LeeYan9
|
||||||
|
* @since 2022-09-06
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class PayOrderApiImpl implements PayOrderApi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue