Commit 952e6aa4a8d176ed4e7d2c84bdaa8d7223db2520

Authored by 芋道源码
Committed by Gitee
2 parents fbee21de 9cf470df

!266 接口实现-交易订单 单元测试

Merge pull request !266 from LeeYan9/ly_uniapp
Showing 22 changed files with 502 additions and 68 deletions
sql/optional/mall/order.sql
1 /**todo cancelType 设置默认值 0?*/ 1 /**todo cancelType 设置默认值 0?*/
  2 +DROP TABLE IF EXISTS `trade_order`;
2 CREATE TABLE `trade_order` 3 CREATE TABLE `trade_order`
3 ( 4 (
4 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', 5 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
@@ -10,9 +11,10 @@ CREATE TABLE `trade_order` @@ -10,9 +11,10 @@ CREATE TABLE `trade_order`
10 `user_remark` varchar(200) DEFAULT NULL COMMENT '用户备注', 11 `user_remark` varchar(200) DEFAULT NULL COMMENT '用户备注',
11 `status` int NOT NULL DEFAULT '0' COMMENT '订单状态:[0:待付款 1:待发货 2:待收货 3:已完成 4:已关闭]', 12 `status` int NOT NULL DEFAULT '0' COMMENT '订单状态:[0:待付款 1:待发货 2:待收货 3:已完成 4:已关闭]',
12 `product_count` int NOT NULL COMMENT '购买的商品数量', 13 `product_count` int NOT NULL COMMENT '购买的商品数量',
13 - `cancel_type` int NOT NULL COMMENT '取消类型:[10:超时未支付 20:退款关闭 30:买家取消 40:已通过货到付款交易]', 14 + `cancel_type` int DEFAULT NULL COMMENT '取消类型:[10:超时未支付 20:退款关闭 30:买家取消 40:已通过货到付款交易]',
14 `remark` varchar(200) DEFAULT NULL COMMENT '商家备注', 15 `remark` varchar(200) DEFAULT NULL COMMENT '商家备注',
15 `payed` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已支付:[0:未支付 1:已经支付过]', 16 `payed` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已支付:[0:未支付 1:已经支付过]',
  17 + `pay_time` datetime DEFAULT NULL COMMENT '订单支付时间',
16 `finish_time` datetime DEFAULT NULL COMMENT '订单完成时间', 18 `finish_time` datetime DEFAULT NULL COMMENT '订单完成时间',
17 `cancel_time` datetime DEFAULT NULL COMMENT '订单取消时间', 19 `cancel_time` datetime DEFAULT NULL COMMENT '订单取消时间',
18 `sku_original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价(总),单位:分', 20 `sku_original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价(总),单位:分',
@@ -20,11 +22,11 @@ CREATE TABLE `trade_order` @@ -20,11 +22,11 @@ CREATE TABLE `trade_order`
20 `order_promotion_price` int NOT NULL DEFAULT '0' COMMENT '订单优惠(总),单位:分', 22 `order_promotion_price` int NOT NULL DEFAULT '0' COMMENT '订单优惠(总),单位:分',
21 `delivery_price` int NOT NULL DEFAULT '0' COMMENT '运费金额,单位:分', 23 `delivery_price` int NOT NULL DEFAULT '0' COMMENT '运费金额,单位:分',
22 `pay_price` int NOT NULL DEFAULT '0' COMMENT '应付金额(总),单位:分', 24 `pay_price` int NOT NULL DEFAULT '0' COMMENT '应付金额(总),单位:分',
23 - `pay_order_id` int NOT NULL COMMENT '支付订单编号',  
24 - `pay_channel` int NOT NULL COMMENT '支付成功的支付渠道',  
25 - `delivery_type` int NOT NULL DEFAULT '1' COMMENT '配送方式:[1:快递发货 2:自提]',  
26 - `actual_delivery_type` int NOT NULL DEFAULT '1' COMMENT '实际的配送方式:[1:快递发货 2:自提]',  
27 - `delivery_templateid` int DEFAULT NULL COMMENT '配置模板的编号', 25 + `pay_order_id` int DEFAULT NULL COMMENT '支付订单编号',
  26 + `pay_channel` int DEFAULT NULL COMMENT '支付成功的支付渠道',
  27 + `delivery_type` int DEFAULT NULL DEFAULT '1' COMMENT '配送方式:[1:快递发货 2:自提]',
  28 + `actual_delivery_type` int DEFAULT NULL DEFAULT '1' COMMENT '实际的配送方式:[1:快递发货 2:自提]',
  29 + `delivery_template_id` int DEFAULT NULL COMMENT '配置模板的编号',
28 `express_no` int DEFAULT NULL COMMENT '物流公司单号', 30 `express_no` int DEFAULT NULL COMMENT '物流公司单号',
29 `delivery_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '发货状态[0:未发货 1:已发货]', 31 `delivery_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '发货状态[0:未发货 1:已发货]',
30 `delivery_time` datetime DEFAULT NULL COMMENT '发货时间', 32 `delivery_time` datetime DEFAULT NULL COMMENT '发货时间',
@@ -73,4 +75,4 @@ CREATE TABLE `trade_order_item` @@ -73,4 +75,4 @@ CREATE TABLE `trade_order_item`
73 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 75 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
74 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', 76 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
75 PRIMARY KEY (`id`) USING BTREE 77 PRIMARY KEY (`id`) USING BTREE
76 -) ENGINE = InnoDB COMMENT ='交易订单明细表';  
77 \ No newline at end of file 78 \ No newline at end of file
  79 +) ENGINE = InnoDB COMMENT ='交易订单明细表';
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
1 package cn.iocoder.yudao.module.product.api.sku; 1 package cn.iocoder.yudao.module.product.api.sku;
2 2
  3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
3 import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; 4 import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
4 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 5 +import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO;
5 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; 6 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
6 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; 7 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
7 -import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; 8 +import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
8 import org.springframework.stereotype.Service; 9 import org.springframework.stereotype.Service;
  10 +import org.springframework.transaction.annotation.Transactional;
  11 +import org.springframework.validation.annotation.Validated;
9 12
10 import javax.annotation.Resource; 13 import javax.annotation.Resource;
11 import java.util.Collection; 14 import java.util.Collection;
  15 +import java.util.Collections;
12 import java.util.List; 16 import java.util.List;
13 17
14 /** 18 /**
15 - * 商品 SKU API 实现类  
16 - *  
17 - * @author 芋道源码  
18 - * @since 2022-08-26 19 + * @author LeeYan9
  20 + * @since 2022-09-06
19 */ 21 */
20 @Service 22 @Service
  23 +@Validated
21 public class ProductSkuApiImpl implements ProductSkuApi { 24 public class ProductSkuApiImpl implements ProductSkuApi {
22 25
23 @Resource 26 @Resource
24 - private ProductSkuService productSkuService; 27 + private ProductSkuMapper productSkuMapper;
25 28
26 @Override 29 @Override
27 - public ProductSkuRespDTO getSku(Long id) {  
28 - ProductSkuDO skuDO = productSkuService.getSku(id);  
29 - return ProductSkuConvert.INSTANCE.convert02(skuDO);  
30 - }  
31 -  
32 - @Override  
33 - public List<ProductSkuRespDTO> getSkuList(Collection<Long> ids) {  
34 - List<ProductSkuDO> list = productSkuService.getSkuList(ids);  
35 - return ProductSkuConvert.INSTANCE.convertList02(list); 30 + public List<SkuInfoRespDTO> getSkusByIds(Collection<Long> skuIds) {
  31 + if (CollectionUtils.isAnyEmpty(skuIds)) {
  32 + return Collections.emptyList();
  33 + }
  34 + List<ProductSkuDO> productSkuDOList = productSkuMapper.selectBatchIds(skuIds);
  35 + return ProductSkuConvert.INSTANCE.convertList03(productSkuDOList);
36 } 36 }
37 37
38 @Override 38 @Override
  39 + @Transactional(rollbackFor = Exception.class)
39 public void decrementStockBatch(SkuDecrementStockBatchReqDTO batchReqDTO) { 40 public void decrementStockBatch(SkuDecrementStockBatchReqDTO batchReqDTO) {
40 - 41 + productSkuMapper.decrementStockBatch(batchReqDTO.getItems());
41 } 42 }
42 -  
43 } 43 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
1 package cn.iocoder.yudao.module.product.api.spu; 1 package cn.iocoder.yudao.module.product.api.spu;
2 2
  3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
3 import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; 4 import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO;
  5 +import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
  6 +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
  7 +import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
4 import org.springframework.stereotype.Service; 8 import org.springframework.stereotype.Service;
  9 +import org.springframework.validation.annotation.Validated;
5 10
  11 +import javax.annotation.Resource;
6 import java.util.Collection; 12 import java.util.Collection;
  13 +import java.util.Collections;
7 import java.util.List; 14 import java.util.List;
8 15
9 /** 16 /**
10 - * 商品 SPU API 实现类  
11 - *  
12 * @author LeeYan9 17 * @author LeeYan9
13 - * @since 2022-08-26 18 + * @since 2022-09-06
14 */ 19 */
15 @Service 20 @Service
  21 +@Validated
16 public class ProductSpuApiImpl implements ProductSpuApi { 22 public class ProductSpuApiImpl implements ProductSpuApi {
17 23
  24 + @Resource
  25 + private ProductSpuMapper productSpuMapper;
  26 +
18 @Override 27 @Override
19 public List<SpuInfoRespDTO> getSpuList(Collection<Long> spuIds) { 28 public List<SpuInfoRespDTO> getSpuList(Collection<Long> spuIds) {
20 - return null; 29 + if (CollectionUtils.isAnyEmpty(spuIds)) {
  30 + return Collections.emptyList();
  31 + }
  32 + List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds);
  33 + return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList);
21 } 34 }
22 -  
23 } 35 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
1 package cn.iocoder.yudao.module.product.convert.sku; 1 package cn.iocoder.yudao.module.product.convert.sku;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO;
3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; 6 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
5 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; 7 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
@@ -34,4 +36,7 @@ public interface ProductSkuConvert { @@ -34,4 +36,7 @@ public interface ProductSkuConvert {
34 36
35 List<ProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> list); 37 List<ProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> list);
36 38
  39 + List<SkuInfoRespDTO> convertList03(List<ProductSkuDO> list);
  40 +
  41 +
37 } 42 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
1 package cn.iocoder.yudao.module.product.convert.spu; 1 package cn.iocoder.yudao.module.product.convert.spu;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO;
4 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; 5 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
5 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO; 6 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
6 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO; 7 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
@@ -34,4 +35,7 @@ public interface ProductSpuConvert { @@ -34,4 +35,7 @@ public interface ProductSpuConvert {
34 35
35 AppSpuPageRespVO convertAppResp(ProductSpuDO list); 36 AppSpuPageRespVO convertAppResp(ProductSpuDO list);
36 37
  38 + List<SpuInfoRespDTO> convertList2(List<ProductSpuDO> list);
  39 +
  40 +
37 } 41 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
@@ -2,7 +2,10 @@ package cn.iocoder.yudao.module.product.dal.mysql.sku; @@ -2,7 +2,10 @@ package cn.iocoder.yudao.module.product.dal.mysql.sku;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
  6 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuPageReqVO;
5 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; 7 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
  8 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
6 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
7 10
8 import java.util.List; 11 import java.util.List;
@@ -31,4 +34,16 @@ public interface ProductSkuMapper extends BaseMapperX&lt;ProductSkuDO&gt; { @@ -31,4 +34,16 @@ public interface ProductSkuMapper extends BaseMapperX&lt;ProductSkuDO&gt; {
31 delete(lambdaQueryWrapperX); 34 delete(lambdaQueryWrapperX);
32 } 35 }
33 36
  37 + default void decrementStockBatch(List<SkuDecrementStockBatchReqDTO.Item> items) {
  38 + for (SkuDecrementStockBatchReqDTO.Item item : items) {
  39 + // 扣减库存 cas 逻辑
  40 + LambdaUpdateWrapper<ProductSkuDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<ProductSkuDO>()
  41 + .setSql(" stock = stock-" + item.getCount())
  42 + .eq(ProductSkuDO::getSpuId, item.getProductId())
  43 + .eq(ProductSkuDO::getId, item.getSkuId())
  44 + .ge(ProductSkuDO::getStock, item.getCount());
  45 + // 执行
  46 + this.update(null, lambdaUpdateWrapper);
  47 + }
  48 + }
34 } 49 }
yudao-module-mall/yudao-module-trade-biz/pom.xml
@@ -57,9 +57,16 @@ @@ -57,9 +57,16 @@
57 <groupId>cn.iocoder.boot</groupId> 57 <groupId>cn.iocoder.boot</groupId>
58 <artifactId>yudao-spring-boot-starter-web</artifactId> 58 <artifactId>yudao-spring-boot-starter-web</artifactId>
59 </dependency> 59 </dependency>
  60 +
60 <dependency> 61 <dependency>
61 <groupId>cn.iocoder.boot</groupId> 62 <groupId>cn.iocoder.boot</groupId>
62 - <artifactId>yudao-spring-boot-starter-excel</artifactId> 63 + <artifactId>yudao-spring-boot-starter-biz-pay</artifactId>
  64 + </dependency>
  65 +
  66 + <!-- DB 相关 -->
  67 + <dependency>
  68 + <groupId>cn.iocoder.boot</groupId>
  69 + <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
63 </dependency> 70 </dependency>
64 71
65 <!-- DB 相关 --> 72 <!-- DB 相关 -->
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate
5 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 5 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
6 import org.mapstruct.Mapper; 6 import org.mapstruct.Mapper;
7 import org.mapstruct.Mapping; 7 import org.mapstruct.Mapping;
  8 +import org.mapstruct.Mappings;
8 import org.mapstruct.factory.Mappers; 9 import org.mapstruct.factory.Mappers;
9 10
10 /** 11 /**
@@ -16,6 +17,12 @@ public interface TradeOrderConvert { @@ -16,6 +17,12 @@ public interface TradeOrderConvert {
16 17
17 TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class); 18 TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class);
18 19
19 - @Mapping(source = "order.couponId", target = "couponId")  
20 - TradeOrderDO convert(AppTradeOrderCreateReqVO createReqVO, PriceCalculateRespDTO.Order order); 20 +
  21 + @Mappings({
  22 + @Mapping(source = "order.couponId", target = "couponId"),
  23 + @Mapping(target = "remark", ignore = true),
  24 + @Mapping(source = "createVO.remark", target = "userRemark"),
  25 + @Mapping(source = "createVO.addressId", target = "receiverAreaId")
  26 + })
  27 + TradeOrderDO convert(AppTradeOrderCreateReqVO createVO, PriceCalculateRespDTO.Order order);
21 } 28 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java
1 package cn.iocoder.yudao.module.trade.convert.order; 1 package cn.iocoder.yudao.module.trade.convert.order;
2 2
3 import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; 3 import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO;
4 -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;  
5 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 4 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
6 import org.mapstruct.Mapper; 5 import org.mapstruct.Mapper;
7 -import org.mapstruct.Mapping;  
8 -import org.mapstruct.Mappings;  
9 import org.mapstruct.factory.Mappers; 6 import org.mapstruct.factory.Mappers;
10 7
11 import java.util.List; 8 import java.util.List;
@@ -20,17 +17,8 @@ public interface TradeOrderItemConvert { @@ -20,17 +17,8 @@ public interface TradeOrderItemConvert {
20 TradeOrderItemConvert INSTANCE = Mappers.getMapper(TradeOrderItemConvert.class); 17 TradeOrderItemConvert INSTANCE = Mappers.getMapper(TradeOrderItemConvert.class);
21 18
22 /** 19 /**
23 - *  
24 - * @param tradeOrder 交易订单  
25 * @param items sku列表价格 20 * @param items sku列表价格
26 * @return 订单项 21 * @return 订单项
27 */ 22 */
28 - @Mappings({  
29 - @Mapping(source = "tradeOrder.userId", target = "userId"),  
30 - @Mapping(source = "tradeOrder.orderId", target = "orderId")  
31 - })  
32 - default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrder, List<PriceCalculateRespDTO.OrderItem> items) {  
33 - // TODO @Com: Mapstruct 生成会报错  
34 - throw new UnsupportedOperationException("无法实现");  
35 - } 23 + List<TradeOrderItemDO> convertList(List<PriceCalculateRespDTO.OrderItem> items);
36 } 24 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/pay/PayOrderConvert.java
1 package cn.iocoder.yudao.module.trade.convert.pay; 1 package cn.iocoder.yudao.module.trade.convert.pay;
2 2
3 -import cn.iocoder.yudao.module.pay.api.order.PayOrderDataCreateReqDTO; 3 +import cn.hutool.core.date.DateUtil;
  4 +import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO;
4 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 5 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
  6 +import org.mapstruct.Mapper;
  7 +import org.mapstruct.Mapping;
  8 +import org.mapstruct.Mappings;
  9 +import org.mapstruct.Named;
5 import org.mapstruct.factory.Mappers; 10 import org.mapstruct.factory.Mappers;
6 11
  12 +import java.util.Date;
  13 +
7 /** 14 /**
8 * @author LeeYan9 15 * @author LeeYan9
9 * @since 2022-08-26 16 * @since 2022-08-26
10 */ 17 */
  18 +@Mapper
11 public interface PayOrderConvert { 19 public interface PayOrderConvert {
12 20
13 PayOrderConvert INSTANCE = Mappers.getMapper(PayOrderConvert.class); 21 PayOrderConvert INSTANCE = Mappers.getMapper(PayOrderConvert.class);
14 22
  23 + @Mappings({
  24 + @Mapping(source = "payPrice", target = "amount"),
  25 + @Mapping(target = "expireTime", source = "cancelTime" , qualifiedByName = "convertCreateTimeToPayExpireTime")
  26 + })
  27 + PayOrderInfoCreateReqDTO convert(TradeOrderDO tradeOrderDO);
15 28
16 - PayOrderDataCreateReqDTO convert(TradeOrderDO tradeOrderDO); 29 + @Named("convertCreateTimeToPayExpireTime")
  30 + default Date convertCreateTimeToPayExpireTime(Date cancelTime) {
  31 + return DateUtil.offsetMinute(new Date(), 30);
  32 + }
17 } 33 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderConfig.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.framework.order.config;
  2 +
  3 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
  4 +import org.springframework.context.annotation.Configuration;
  5 +
  6 +/**
  7 + * @author LeeYan9
  8 + * @since 2022-09-15
  9 + */
  10 +@Configuration
  11 +@EnableConfigurationProperties(TradeOrderProperties.class)
  12 +public class TradeOrderConfig {
  13 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.framework.order.config;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +import org.springframework.validation.annotation.Validated;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +/**
  10 + * @author LeeYan9
  11 + * @since 2022-09-15
  12 + */
  13 +@ConfigurationProperties(prefix = "yudao.trade.order")
  14 +@Data
  15 +@Validated
  16 +public class TradeOrderProperties {
  17 +
  18 + /**
  19 + * 商户订单编号
  20 + */
  21 + @NotNull(message = "商户订单编号不能为空")
  22 + private String merchantOrderId;
  23 +
  24 + /**
  25 + * 应用编号
  26 + */
  27 + @NotNull(message = "应用编号不能为空")
  28 + private Long appId;
  29 +
  30 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
1 package cn.iocoder.yudao.module.trade.service.order; 1 package cn.iocoder.yudao.module.trade.service.order;
2 2
3 import cn.hutool.core.bean.BeanUtil; 3 import cn.hutool.core.bean.BeanUtil;
  4 +import cn.hutool.core.text.StrBuilder;
  5 +import cn.hutool.core.util.IdUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  7 +import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 8 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 9 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  10 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
7 import cn.iocoder.yudao.module.market.api.price.PriceApi; 11 import cn.iocoder.yudao.module.market.api.price.PriceApi;
8 import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; 12 import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO;
9 import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; 13 import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO;
10 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; 14 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
11 -import cn.iocoder.yudao.module.pay.api.order.PayOrderDataCreateReqDTO; 15 +import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO;
12 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 16 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
13 import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; 17 import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
14 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 18 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
@@ -27,10 +31,15 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; @@ -27,10 +31,15 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
27 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; 31 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
28 import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; 32 import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper;
29 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; 33 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
30 -import lombok.RequiredArgsConstructor; 34 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemRefundStatusEnum;
  35 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
  36 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
  37 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  38 +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
31 import org.springframework.stereotype.Service; 39 import org.springframework.stereotype.Service;
32 import org.springframework.transaction.annotation.Transactional; 40 import org.springframework.transaction.annotation.Transactional;
33 41
  42 +import javax.annotation.Resource;
34 import java.util.List; 43 import java.util.List;
35 import java.util.Map; 44 import java.util.Map;
36 import java.util.Objects; 45 import java.util.Objects;
@@ -40,20 +49,31 @@ import java.util.Objects; @@ -40,20 +49,31 @@ import java.util.Objects;
40 * @since 2022-08-26 49 * @since 2022-08-26
41 */ 50 */
42 @Service 51 @Service
43 -@RequiredArgsConstructor  
44 public class TradeOrderServiceImpl implements TradeOrderService { 52 public class TradeOrderServiceImpl implements TradeOrderService {
45 53
46 - private final TradeOrderMapper tradeOrderMapper; 54 + @Resource
  55 + private TradeOrderMapper tradeOrderMapper;
47 56
48 - private final TradeOrderItemMapper tradeOrderItemMapper; 57 + @Resource
  58 + private TradeOrderItemMapper tradeOrderItemMapper;
49 59
50 - private final PriceApi priceApi; 60 + @Resource
  61 + private PriceApi priceApi;
51 62
52 - private final ProductSkuApi productSkuApi; 63 + @Resource
  64 + private ProductSkuApi productSkuApi;
53 65
54 - private final ProductSpuApi productSpuApi; 66 + @Resource
  67 + private ProductSpuApi productSpuApi;
55 68
56 - private final PayOrderApi payOrderApi; 69 + @Resource
  70 + private PayOrderApi payOrderApi;
  71 +
  72 + @Resource
  73 + private TradeOrderProperties tradeOrderProperties;
  74 +
  75 + private static final String BLANK_PLACEHOLDER = " ";
  76 + private static final String MULTIPLIER_PLACEHOLDER = "x";
57 77
58 78
59 @Override 79 @Override
@@ -61,46 +81,92 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -61,46 +81,92 @@ public class TradeOrderServiceImpl implements TradeOrderService {
61 public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { 81 public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) {
62 82
63 List<Item> items = createReqVO.getItems(); 83 List<Item> items = createReqVO.getItems();
64 - // 商品SKU检查 sku可售状态,库存 84 + // 商品SKU检查 sku可售状态,库存
65 List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId)); 85 List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId));
66 Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId); 86 Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId);
67 checkSaleableAndStockFromSpu(skuInfoMap, items); 87 checkSaleableAndStockFromSpu(skuInfoMap, items);
68 88
69 - // 商品SPU检查 sku可售状态,库存 89 + // 商品SPU检查 sku可售状态,库存
70 List<SpuInfoRespDTO> spuInfos = productSpuApi.getSpuList(CollectionUtils.convertSet(skuInfos, ProductSkuRespDTO::getSpuId)); 90 List<SpuInfoRespDTO> spuInfos = productSpuApi.getSpuList(CollectionUtils.convertSet(skuInfos, ProductSkuRespDTO::getSpuId));
71 checkSaleableFromSpu(spuInfos); 91 checkSaleableFromSpu(spuInfos);
72 92
73 // 价格计算 93 // 价格计算
74 PriceCalculateReqDTO priceCalculateReqDTO = PriceConvert.INSTANCE.convert(createReqVO, loginUserId); 94 PriceCalculateReqDTO priceCalculateReqDTO = PriceConvert.INSTANCE.convert(createReqVO, loginUserId);
75 PriceCalculateRespDTO priceResp = priceApi.calculatePrice(priceCalculateReqDTO); 95 PriceCalculateRespDTO priceResp = priceApi.calculatePrice(priceCalculateReqDTO);
76 -  
77 // 订单信息记录 96 // 订单信息记录
78 TradeOrderDO tradeOrderDO = TradeOrderConvert.INSTANCE.convert(createReqVO, priceResp.getOrder()); 97 TradeOrderDO tradeOrderDO = TradeOrderConvert.INSTANCE.convert(createReqVO, priceResp.getOrder());
  98 + fillTradeOrderInfoFromReqInfo(tradeOrderDO,createReqVO,loginUserId, clientIp);
79 tradeOrderMapper.insert(tradeOrderDO); 99 tradeOrderMapper.insert(tradeOrderDO);
80 100
81 // 订单项信息记录 101 // 订单项信息记录
82 - List<TradeOrderItemDO> tradeOrderItems = TradeOrderItemConvert.INSTANCE.convertList(tradeOrderDO, priceResp.getOrder().getItems()); 102 + List<TradeOrderItemDO> tradeOrderItems = TradeOrderItemConvert.INSTANCE.convertList(priceResp.getOrder().getItems());
83 //-填充订单项-SKU信息 103 //-填充订单项-SKU信息
84 - fillItemsInfoFromSku(tradeOrderItems, skuInfoMap); 104 + fillItemsInfoFromSkuAndOrder(tradeOrderDO, tradeOrderItems, skuInfoMap);
85 tradeOrderItemMapper.insertBatch(tradeOrderItems); 105 tradeOrderItemMapper.insertBatch(tradeOrderItems);
86 106
87 // 库存扣减 107 // 库存扣减
88 List<SkuDecrementStockBatchReqDTO.Item> skuDecrementStockItems = ProductSkuConvert.INSTANCE.convert(tradeOrderItems); 108 List<SkuDecrementStockBatchReqDTO.Item> skuDecrementStockItems = ProductSkuConvert.INSTANCE.convert(tradeOrderItems);
89 productSkuApi.decrementStockBatch(SkuDecrementStockBatchReqDTO.of(skuDecrementStockItems)); 109 productSkuApi.decrementStockBatch(SkuDecrementStockBatchReqDTO.of(skuDecrementStockItems));
90 - // 生成预支付  
91 110
92 - PayOrderDataCreateReqDTO payOrderCreateReqDTO = PayOrderConvert.INSTANCE.convert(tradeOrderDO); 111 + // 构建预支付请求参数
  112 + PayOrderInfoCreateReqDTO payOrderCreateReqDTO = PayOrderConvert.INSTANCE.convert(tradeOrderDO);
  113 + fillPayOrderInfoFromItems(payOrderCreateReqDTO, tradeOrderItems);
  114 + // 生成预支付
93 return payOrderApi.createPayOrder(payOrderCreateReqDTO); 115 return payOrderApi.createPayOrder(payOrderCreateReqDTO);
94 } 116 }
95 117
96 - private void fillItemsInfoFromSku(List<TradeOrderItemDO> tradeOrderItems,  
97 - Map<Long, ProductSkuRespDTO> spuInfos) { 118 + private void fillTradeOrderInfoFromReqInfo(TradeOrderDO tradeOrderDO, AppTradeOrderCreateReqVO createReqVO,
  119 + Long loginUserId, String clientIp) {
  120 + tradeOrderDO.setUserId(loginUserId);
  121 + tradeOrderDO.setUserIp(clientIp);
  122 + tradeOrderDO.setSn(IdUtil.getSnowflakeNextId() + "");
  123 + tradeOrderDO.setStatus(TradeOrderStatusEnum.WAITING_PAYMENT.getStatus());
  124 + tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType());
  125 + tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
  126 + tradeOrderDO.setProductCount(CollectionUtils.getSumValue(createReqVO.getItems(), Item::getCount,Integer::sum));
  127 + // todo 地址&用户信息解析
  128 +
  129 + // todo 数据来源?
  130 + tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal());
  131 + }
  132 +
  133 + private void fillPayOrderInfoFromItems(PayOrderInfoCreateReqDTO payOrderInfoCreateReqDTO,
  134 + List<TradeOrderItemDO> tradeOrderItems) {
  135 + // 填写 商品&应用信息
  136 + payOrderInfoCreateReqDTO.setMerchantOrderId(tradeOrderProperties.getMerchantOrderId());
  137 + payOrderInfoCreateReqDTO.setAppId(tradeOrderProperties.getAppId());
  138 +
  139 + // 填写商品信息
  140 + StrBuilder subject = new StrBuilder();
  141 + StrBuilder body = new StrBuilder();
  142 +
  143 + for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) {
  144 + // append subject
  145 + subject.append(BLANK_PLACEHOLDER);
  146 + subject.append(tradeOrderItem.getName());
  147 + // append body
  148 + body.append(BLANK_PLACEHOLDER);
  149 + body.append(tradeOrderItem.getName());
  150 + body.append(MULTIPLIER_PLACEHOLDER);
  151 + body.append(tradeOrderItem.getCount());
  152 + }
  153 + // 设置 subject & body
  154 + payOrderInfoCreateReqDTO.setSubject(StrUtils.maxLength(subject.subString(1), 32));
  155 + payOrderInfoCreateReqDTO.setBody(StrUtils.maxLength(body.subString(1), 128));
  156 + }
  157 +
  158 + private void fillItemsInfoFromSkuAndOrder(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItems,
  159 + Map<Long, ProductSkuRespDTO> spuInfos) {
98 for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) { 160 for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) {
  161 + // 填充订单信息
  162 + tradeOrderItem.setOrderId(tradeOrderDO.getId());
  163 + tradeOrderItem.setUserId(tradeOrderDO.getUserId());
99 // 填充SKU信息 164 // 填充SKU信息
100 ProductSkuRespDTO skuInfoRespDTO = spuInfos.get(tradeOrderItem.getSkuId()); 165 ProductSkuRespDTO skuInfoRespDTO = spuInfos.get(tradeOrderItem.getSkuId());
101 tradeOrderItem.setSpuId(skuInfoRespDTO.getSpuId()); 166 tradeOrderItem.setSpuId(skuInfoRespDTO.getSpuId());
102 tradeOrderItem.setPicUrl(skuInfoRespDTO.getPicUrl()); 167 tradeOrderItem.setPicUrl(skuInfoRespDTO.getPicUrl());
103 tradeOrderItem.setName(skuInfoRespDTO.getName()); 168 tradeOrderItem.setName(skuInfoRespDTO.getName());
  169 + tradeOrderItem.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus());
104 // todo 170 // todo
105 List<TradeOrderItemDO.Property> property = 171 List<TradeOrderItemDO.Property> property =
106 BeanUtil.copyToList(skuInfoRespDTO.getProperties(), TradeOrderItemDO.Property.class); 172 BeanUtil.copyToList(skuInfoRespDTO.getProperties(), TradeOrderItemDO.Property.class);
yudao-module-mall/yudao-module-trade-biz/src/main/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.market.api.price.PriceApi;
  6 +import cn.iocoder.yudao.module.market.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 +/**
  34 + * @author LeeYan9
  35 + * @since 2022-09-07
  36 + */
  37 +@Import({TradeOrderServiceImpl.class, TradeOrderConfig.class})
  38 +class TradeOrderServiceTest extends BaseDbUnitTest {
  39 +
  40 +
  41 + @Resource
  42 + TradeOrderService tradeOrderService;
  43 + @Resource
  44 + TradeOrderMapper tradeOrderMapper;
  45 + @Resource
  46 + TradeOrderItemMapper tradeOrderItemMapper;
  47 + @MockBean
  48 + ProductSpuApi productSpuApi;
  49 + @MockBean
  50 + ProductSkuApi productSkuApi;
  51 + @MockBean
  52 + PriceApi priceApi;
  53 + @MockBean
  54 + private PayOrderApi payOrderApi;
  55 +
  56 + @Test
  57 + void testCreateTradeOrder_success() {
  58 + // mock 商品SPU数据
  59 + SpuInfoRespDTO spuInfoRespDTO = randomPojo(SpuInfoRespDTO.class, spuInfo -> {
  60 + spuInfo.setId(1L);
  61 + spuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus());
  62 + });
  63 + when(productSpuApi.getSpuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(spuInfoRespDTO));
  64 + // mock 商品SkU数据
  65 + ProductSkuRespDTO skuInfoRespDTO = randomPojo(ProductSkuRespDTO.class, skuInfo -> {
  66 + skuInfo.setId(1L);
  67 + skuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus());
  68 + skuInfo.setStock(randomInteger());
  69 + skuInfo.setSpuId(1L);
  70 + });
  71 + when(productSkuApi.getSkuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(skuInfoRespDTO));
  72 + // mock 价格信息
  73 + PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> {
  74 + PriceCalculateRespDTO.OrderItem item = priceCalculateRespDTO.getOrder().getItems().get(0);
  75 + item.setSkuId(1L);
  76 + item.setCount(2);
  77 + priceCalculateRespDTO.getOrder().setItems(Collections.singletonList(item));
  78 + });
  79 + when(priceApi.calculatePrice(any())).thenReturn(calculateRespDTO);
  80 + //mock 支付订单信息
  81 + when(payOrderApi.createPayOrder(any())).thenReturn(1L);
  82 +
  83 + // 准备请求数据
  84 + AppTradeOrderCreateReqVO tradeOrderCreateReqVO = randomPojo(AppTradeOrderCreateReqVO.class, reqVO -> {
  85 + AppTradeOrderCreateReqVO.Item item = randomPojo(AppTradeOrderCreateReqVO.Item.class, o -> {
  86 + o.setSkuId(1L);
  87 + o.setCount(2);
  88 + });
  89 + reqVO.setItems(Collections.singletonList(item));
  90 + });
  91 + // 创建交易订单,支付订单记录
  92 + Long payOrderId = tradeOrderService.createTradeOrder(1L, "127.0.0.1", tradeOrderCreateReqVO);
  93 + //断言交易订单
  94 + TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(TradeOrderDO::getUserId, 1L);
  95 + assertNotNull(tradeOrderDO);
  96 + //价格&用户
  97 + assertEquals(calculateRespDTO.getOrder().getPayPrice(), tradeOrderDO.getPayPrice());
  98 + assertEquals(1L, tradeOrderDO.getUserId());
  99 + //断言交易订单项
  100 + TradeOrderItemDO tradeOrderItemDO = tradeOrderItemMapper.selectOne(TradeOrderItemDO::getOrderId, tradeOrderDO.getId());
  101 + assertNotNull(tradeOrderDO);
  102 + //商品&用户
  103 + assertEquals(skuInfoRespDTO.getId(), tradeOrderItemDO.getSkuId());
  104 + assertEquals(1L, tradeOrderItemDO.getUserId());
  105 + //价格
  106 + assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice());
  107 + }
  108 +
  109 +}
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/application-unit-test.yaml 0 → 100644
  1 +spring:
  2 + main:
  3 + lazy-initialization: true # 开启懒加载,加快速度
  4 + banner-mode: off # 单元测试,禁用 Banner
  5 +
  6 +--- #################### 数据库相关配置 ####################
  7 +
  8 +spring:
  9 + # 数据源配置项
  10 + datasource:
  11 + name: ruoyi-vue-pro
  12 + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写
  13 + driver-class-name: org.h2.Driver
  14 + username: sa
  15 + password:
  16 + druid:
  17 + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
  18 + initial-size: 1 # 单元测试,配置为 1,提升启动速度
  19 + sql:
  20 + init:
  21 + schema-locations: classpath:/sql/create_tables.sql
  22 +
  23 + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
  24 + redis:
  25 + host: 127.0.0.1 # 地址
  26 + port: 16379 # 端口(单元测试,使用 16379 端口)
  27 + database: 0 # 数据库索引
  28 +
  29 +mybatis:
  30 + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
  31 +
  32 +--- #################### 定时任务相关配置 ####################
  33 +
  34 +--- #################### 配置中心相关配置 ####################
  35 +
  36 +--- #################### 服务保障相关配置 ####################
  37 +
  38 +# Lock4j 配置项(单元测试,禁用 Lock4j)
  39 +
  40 +# Resilience4j 配置项
  41 +
  42 +--- #################### 监控相关配置 ####################
  43 +
  44 +--- #################### 芋道相关配置 ####################
  45 +
  46 +# 芋道配置项,设置当前项目所有自定义的配置
  47 +yudao:
  48 + info:
  49 + base-package: cn.iocoder.yudao.module
  50 + trade:
  51 + order:
  52 + app-id: 1
  53 + merchant-order-id: 1
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/logback.xml 0 → 100644
  1 +<configuration>
  2 + <!-- 引用 Spring Boot 的 logback 基础配置 -->
  3 + <include resource="org/springframework/boot/logging/logback/defaults.xml" />
  4 +</configuration>
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/clean.sql 0 → 100644
  1 +DELETE FROM trade_order;
  2 +DELETE FROM trade_order_item;
0 \ No newline at end of file 3 \ No newline at end of file
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql 0 → 100644
  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-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
@@ -15,6 +15,6 @@ public interface PayOrderApi { @@ -15,6 +15,6 @@ public interface PayOrderApi {
15 * @param reqDTO 创建请求 15 * @param reqDTO 创建请求
16 * @return 支付单编号 16 * @return 支付单编号
17 */ 17 */
18 - Long createPayOrder(@Valid PayOrderDataCreateReqDTO reqDTO); 18 + Long createPayOrder(@Valid PayOrderInfoCreateReqDTO reqDTO);
19 19
20 } 20 }
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderDataCreateReqDTO.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java
@@ -14,7 +14,7 @@ import java.util.Date; @@ -14,7 +14,7 @@ import java.util.Date;
14 * @author LeeYan9 14 * @author LeeYan9
15 */ 15 */
16 @Data 16 @Data
17 -public class PayOrderDataCreateReqDTO implements Serializable { 17 +public class PayOrderInfoCreateReqDTO implements Serializable {
18 18
19 /** 19 /**
20 * 应用编号 20 * 应用编号
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.api.order;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import org.springframework.transaction.annotation.Transactional;
  5 +
  6 +/**
  7 + * @author LeeYan9
  8 + * @since 2022-09-06
  9 + */
  10 +@Service
  11 +public class PayOrderApiImpl implements PayOrderApi {
  12 +
  13 + @Override
  14 + @Transactional(rollbackFor = Exception.class)
  15 + public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) {
  16 + return null;
  17 + }
  18 +
  19 +}
yudao-server/src/main/resources/application.yaml
@@ -95,6 +95,10 @@ yudao: @@ -95,6 +95,10 @@ yudao:
95 base-package: ${yudao.info.base-package} 95 base-package: ${yudao.info.base-package}
96 captcha: 96 captcha:
97 enable: true # 验证码的开关,默认为 true;注意,优先读取数据库 infra_config 的 yudao.captcha.enable,所以请从数据库修改,可能需要重启项目 97 enable: true # 验证码的开关,默认为 true;注意,优先读取数据库 infra_config 的 yudao.captcha.enable,所以请从数据库修改,可能需要重启项目
  98 + trade:
  99 + order:
  100 + app-id: 1
  101 + merchant-order-id: 1
98 codegen: 102 codegen:
99 base-package: ${yudao.info.base-package} 103 base-package: ${yudao.info.base-package}
100 db-schemas: ${spring.datasource.dynamic.datasource.master.name} 104 db-schemas: ${spring.datasource.dynamic.datasource.master.name}