Commit 5934d6b0299b0091e1b652aeaf1bad7e968c6a1f

Authored by YunaiV
1 parent 84f6ec10

trade:完成下单时,创建支付单逻辑

yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
1 package cn.iocoder.yudao.module.trade.convert.order; 1 package cn.iocoder.yudao.module.trade.convert.order;
2 2
  3 +import cn.hutool.core.date.DateUtil;
3 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
4 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 6 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
  7 +import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO;
5 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
6 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; 9 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
  10 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
7 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; 11 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
8 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; 12 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; 13 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
10 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 14 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
11 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 15 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
12 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemRefundStatusEnum; 16 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemRefundStatusEnum;
  17 +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
13 import org.mapstruct.Mapper; 18 import org.mapstruct.Mapper;
14 import org.mapstruct.Mapping; 19 import org.mapstruct.Mapping;
15 import org.mapstruct.Mappings; 20 import org.mapstruct.Mappings;
16 import org.mapstruct.factory.Mappers; 21 import org.mapstruct.factory.Mappers;
17 22
  23 +import java.time.Duration;
18 import java.util.List; 24 import java.util.List;
19 import java.util.Map; 25 import java.util.Map;
20 26
21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  28 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
22 29
23 @Mapper 30 @Mapper
24 public interface TradeOrderConvert { 31 public interface TradeOrderConvert {
@@ -67,4 +74,20 @@ public interface TradeOrderConvert { @@ -67,4 +74,20 @@ public interface TradeOrderConvert {
67 ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean); 74 ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean);
68 List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); 75 List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);
69 76
  77 + default PayOrderInfoCreateReqDTO convert(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs,
  78 + List<ProductSpuRespDTO> spus, TradeOrderProperties tradeOrderProperties) {
  79 + PayOrderInfoCreateReqDTO createReqDTO = new PayOrderInfoCreateReqDTO()
  80 + .setAppId(tradeOrderProperties.getAppId()).setUserIp(tradeOrderDO.getUserIp());
  81 + // 商户相关字段
  82 + createReqDTO.setMerchantOrderId(String.valueOf(tradeOrderDO.getId()));
  83 + String subject = spus.get(0).getName();
  84 + if (spus.size() > 1) {
  85 + subject += " 等多件";
  86 + }
  87 + createReqDTO.setSubject(subject);
  88 + // 订单相关字段
  89 + createReqDTO.setAmount(tradeOrderDO.getPayPrice()).setExpireTime(addTime(tradeOrderProperties.getExpireTime()));
  90 + return createReqDTO;
  91 + }
  92 +
70 } 93 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/pay/PayOrderConvert.java deleted
1 -package cn.iocoder.yudao.module.trade.convert.pay;  
2 -  
3 -import cn.hutool.core.date.DateUtil;  
4 -import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO;  
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;  
10 -import org.mapstruct.factory.Mappers;  
11 -  
12 -import java.util.Date;  
13 -  
14 -@Mapper  
15 -public interface PayOrderConvert {  
16 -  
17 - PayOrderConvert INSTANCE = Mappers.getMapper(PayOrderConvert.class);  
18 -  
19 - @Mappings({  
20 - @Mapping(source = "payPrice", target = "amount"),  
21 - @Mapping(target = "expireTime", source = "cancelTime" , qualifiedByName = "convertCreateTimeToPayExpireTime")  
22 - })  
23 - PayOrderInfoCreateReqDTO convert(TradeOrderDO tradeOrderDO);  
24 -  
25 - @Named("convertCreateTimeToPayExpireTime")  
26 - default Date convertCreateTimeToPayExpireTime(Date cancelTime) {  
27 - return DateUtil.offsetMinute(new Date(), 30);  
28 - }  
29 -  
30 -}  
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java
@@ -5,8 +5,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @@ -5,8 +5,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
5 import org.springframework.validation.annotation.Validated; 5 import org.springframework.validation.annotation.Validated;
6 6
7 import javax.validation.constraints.NotNull; 7 import javax.validation.constraints.NotNull;
  8 +import java.time.Duration;
8 9
9 /** 10 /**
  11 + * 交易订单的配置项
  12 + *
10 * @author LeeYan9 13 * @author LeeYan9
11 * @since 2022-09-15 14 * @since 2022-09-15
12 */ 15 */
@@ -16,15 +19,15 @@ import javax.validation.constraints.NotNull; @@ -16,15 +19,15 @@ import javax.validation.constraints.NotNull;
16 public class TradeOrderProperties { 19 public class TradeOrderProperties {
17 20
18 /** 21 /**
19 - * 商户订单编号  
20 - */  
21 - @NotNull(message = "商户订单编号不能为空")  
22 - private String merchantOrderId;  
23 -  
24 - /**  
25 * 应用编号 22 * 应用编号
26 */ 23 */
27 @NotNull(message = "应用编号不能为空") 24 @NotNull(message = "应用编号不能为空")
28 private Long appId; 25 private Long appId;
29 26
  27 + /**
  28 + * 支付超时时间
  29 + */
  30 + @NotNull(message = "支付超时时间不能为空")
  31 + private Duration expireTime;
  32 +
30 } 33 }
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;  
4 -import cn.hutool.core.text.StrBuilder;  
5 import cn.hutool.core.util.IdUtil; 3 import cn.hutool.core.util.IdUtil;
6 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
8 import cn.iocoder.yudao.framework.common.enums.TerminalEnum; 6 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
9 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
10 -import cn.iocoder.yudao.framework.common.util.string.StrUtils;  
11 import cn.iocoder.yudao.module.member.api.address.AddressApi; 8 import cn.iocoder.yudao.module.member.api.address.AddressApi;
12 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 9 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
13 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; 10 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
@@ -30,7 +27,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; @@ -30,7 +27,6 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
30 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; 27 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
31 import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; 28 import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper;
32 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; 29 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
33 -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemRefundStatusEnum;  
34 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; 30 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
35 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 31 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
36 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 32 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
@@ -58,10 +54,6 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREAT @@ -58,10 +54,6 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREAT
58 @Service 54 @Service
59 public class TradeOrderServiceImpl implements TradeOrderService { 55 public class TradeOrderServiceImpl implements TradeOrderService {
60 56
61 - // TODO LeeYan9: 静态变量, 需要在最前面哈; 另外, 静态变量的注释最好写下;  
62 - private static final String BLANK_PLACEHOLDER = " ";  
63 - private static final String MULTIPLIER_PLACEHOLDER = "x";  
64 -  
65 @Resource 57 @Resource
66 private TradeOrderMapper tradeOrderMapper; 58 private TradeOrderMapper tradeOrderMapper;
67 @Resource 59 @Resource
@@ -89,7 +81,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -89,7 +81,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
89 // 商品 SKU 检查:可售状态、库存 81 // 商品 SKU 检查:可售状态、库存
90 List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); 82 List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems());
91 // 商品 SPU 检查:可售状态 83 // 商品 SPU 检查:可售状态
92 - validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); 84 + List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId));
93 // 用户收件地址的校验 85 // 用户收件地址的校验
94 AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); 86 AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId());
95 87
@@ -102,55 +94,11 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -102,55 +94,11 @@ public class TradeOrderServiceImpl implements TradeOrderService {
102 List<TradeOrderItemDO> tradeOrderItems = createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); 94 List<TradeOrderItemDO> tradeOrderItems = createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus);
103 95
104 // 订单创建完后的逻辑 96 // 订单创建完后的逻辑
105 - afterCreateTradeOrder(userId, createReqVO, tradeOrderDO, tradeOrderItems); 97 + afterCreateTradeOrder(userId, createReqVO, tradeOrderDO, tradeOrderItems, spus);
106 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! 98 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
107 return tradeOrderDO.getId(); 99 return tradeOrderDO.getId();
108 } 100 }
109 101
110 - private void fillPayOrderInfoFromItems(PayOrderInfoCreateReqDTO payOrderInfoCreateReqDTO,  
111 - List<TradeOrderItemDO> tradeOrderItems) {  
112 - // 填写 商品&应用信息  
113 - payOrderInfoCreateReqDTO.setMerchantOrderId(tradeOrderProperties.getMerchantOrderId());  
114 - payOrderInfoCreateReqDTO.setAppId(tradeOrderProperties.getAppId());  
115 -  
116 - // 填写商品信息  
117 - StrBuilder subject = new StrBuilder();  
118 - StrBuilder body = new StrBuilder();  
119 - for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) {  
120 - // append subject  
121 - subject.append(BLANK_PLACEHOLDER);  
122 - subject.append(tradeOrderItem.getName());  
123 - // append body  
124 - body.append(BLANK_PLACEHOLDER);  
125 - body.append(tradeOrderItem.getName());  
126 - body.append(MULTIPLIER_PLACEHOLDER);  
127 - body.append(tradeOrderItem.getCount());  
128 - }  
129 - // 设置 subject & body  
130 - // TODO @LeeYan9: 可以抽象一个 StrUtils 方法; 或者看看 hutool 有没自带的哈  
131 - payOrderInfoCreateReqDTO.setSubject(StrUtils.maxLength(subject.subString(1), 32));  
132 - payOrderInfoCreateReqDTO.setBody(StrUtils.maxLength(body.subString(1), 128));  
133 - }  
134 -  
135 - private void xfillItemsInfoFromSkuAndOrder(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItems,  
136 - Map<Long, ProductSkuRespDTO> spuInfos) {  
137 - for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) {  
138 - // 填充订单信息  
139 - tradeOrderItem.setOrderId(tradeOrderDO.getId());  
140 - tradeOrderItem.setUserId(tradeOrderDO.getUserId());  
141 - // 填充SKU信息  
142 - ProductSkuRespDTO skuInfoRespDTO = spuInfos.get(tradeOrderItem.getSkuId());  
143 - tradeOrderItem.setSpuId(skuInfoRespDTO.getSpuId());  
144 - tradeOrderItem.setPicUrl(skuInfoRespDTO.getPicUrl());  
145 - tradeOrderItem.setName(skuInfoRespDTO.getName());  
146 - tradeOrderItem.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus());  
147 - // todo  
148 - List<TradeOrderItemDO.Property> property =  
149 - BeanUtil.copyToList(skuInfoRespDTO.getProperties(), TradeOrderItemDO.Property.class);  
150 - tradeOrderItem.setProperties(property);  
151 - }  
152 - }  
153 -  
154 /** 102 /**
155 * 校验商品 SKU 是否可出售 103 * 校验商品 SKU 是否可出售
156 * 104 *
@@ -248,7 +196,8 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -248,7 +196,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
248 * @param tradeOrderDO 交易订单 196 * @param tradeOrderDO 交易订单
249 */ 197 */
250 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, 198 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
251 - TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs) { 199 + TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs,
  200 + List<ProductSpuRespDTO> spus) {
252 // 下单时扣减商品库存 201 // 下单时扣减商品库存
253 productSkuApi.updateSkuStock(new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(tradeOrderItemDOs))); 202 productSkuApi.updateSkuStock(new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(tradeOrderItemDOs)));
254 203
@@ -262,13 +211,21 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -262,13 +211,21 @@ public class TradeOrderServiceImpl implements TradeOrderService {
262 .setOrderId(tradeOrderDO.getId())); 211 .setOrderId(tradeOrderDO.getId()));
263 } 212 }
264 213
265 - // 构建预支付请求参数  
266 - // TODO @LeeYan9: 需要更新到订单上  
267 -// PayOrderInfoCreateReqDTO payOrderCreateReqDTO = PayOrderConvert.INSTANCE.convert(tradeOrderDO);  
268 -// fillPayOrderInfoFromItems(payOrderCreateReqDTO, tradeOrderItems);  
269 // 生成预支付 214 // 生成预支付
  215 + createPayOrder(tradeOrderDO, tradeOrderItemDOs, spus);
270 216
271 // 增加订单日志 TODO 芋艿:待实现 217 // 增加订单日志 TODO 芋艿:待实现
272 } 218 }
273 219
  220 + private void createPayOrder(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs,
  221 + List<ProductSpuRespDTO> spus) {
  222 + // 创建支付单,用于后续的支付
  223 + PayOrderInfoCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
  224 + tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties);
  225 + Long payOrderId = payOrderApi.createPayOrder(payOrderCreateReqDTO);
  226 +
  227 + // 更新到交易单上
  228 + tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId));
  229 + }
  230 +
274 } 231 }
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
@@ -25,12 +25,15 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; @@ -25,12 +25,15 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
25 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 25 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
26 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 26 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
27 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig; 27 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
  28 +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
  29 +import org.junit.jupiter.api.BeforeEach;
28 import org.junit.jupiter.api.Test; 30 import org.junit.jupiter.api.Test;
29 import org.mockito.ArgumentMatcher; 31 import org.mockito.ArgumentMatcher;
30 import org.springframework.boot.test.mock.mockito.MockBean; 32 import org.springframework.boot.test.mock.mockito.MockBean;
31 import org.springframework.context.annotation.Import; 33 import org.springframework.context.annotation.Import;
32 34
33 import javax.annotation.Resource; 35 import javax.annotation.Resource;
  36 +import java.time.Duration;
34 import java.util.Arrays; 37 import java.util.Arrays;
35 import java.util.List; 38 import java.util.List;
36 39
@@ -73,6 +76,15 @@ class TradeOrderServiceTest extends BaseDbUnitTest { @@ -73,6 +76,15 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
73 @MockBean 76 @MockBean
74 private CouponApi couponApi; 77 private CouponApi couponApi;
75 78
  79 + @MockBean
  80 + private TradeOrderProperties tradeOrderProperties;
  81 +
  82 + @BeforeEach
  83 + public void setUp() {
  84 + when(tradeOrderProperties.getAppId()).thenReturn(888L);
  85 + when(tradeOrderProperties.getExpireTime()).thenReturn(Duration.ofDays(1));
  86 + }
  87 +
76 @Test 88 @Test
77 public void testCreateTradeOrder_success() { 89 public void testCreateTradeOrder_success() {
78 // 准备参数 90 // 准备参数
@@ -92,7 +104,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { @@ -92,7 +104,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
92 when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02)); 104 when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02));
93 // mock 方法(商品 SPU 检查) 105 // mock 方法(商品 SPU 检查)
94 ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L) 106 ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L)
95 - .setStatus(ProductSpuStatusEnum.ENABLE.getStatus())); 107 + .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()).setName("商品 1"));
96 ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L) 108 ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L)
97 .setStatus(ProductSpuStatusEnum.ENABLE.getStatus())); 109 .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()));
98 when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02)); 110 when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02));
@@ -120,6 +132,17 @@ class TradeOrderServiceTest extends BaseDbUnitTest { @@ -120,6 +132,17 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
120 assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4); 132 assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4);
121 return true; 133 return true;
122 }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder)); 134 }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));
  135 + // mock 方法(创建支付单)
  136 + when(payOrderApi.createPayOrder(argThat(createReqDTO -> {
  137 + assertEquals(createReqDTO.getAppId(), 888L);
  138 + assertEquals(createReqDTO.getUserIp(), userIp);
  139 + assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空
  140 + assertEquals(createReqDTO.getSubject(), "商品 1 等多件");
  141 + assertNull(createReqDTO.getBody());
  142 + assertEquals(createReqDTO.getAmount(), 80);
  143 + assertNotNull(createReqDTO.getExpireTime());
  144 + return true;
  145 + }))).thenReturn(1000L);
123 146
124 // 调用方法 147 // 调用方法
125 Long tradeOrderId = tradeOrderService.createTradeOrder(userId, userIp, reqVO); 148 Long tradeOrderId = tradeOrderService.createTradeOrder(userId, userIp, reqVO);
@@ -147,7 +170,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { @@ -147,7 +170,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
147 assertEquals(tradeOrderDO.getDiscountPrice(), 0); 170 assertEquals(tradeOrderDO.getDiscountPrice(), 0);
148 assertEquals(tradeOrderDO.getAdjustPrice(), 0); 171 assertEquals(tradeOrderDO.getAdjustPrice(), 0);
149 assertEquals(tradeOrderDO.getPayPrice(), 80); 172 assertEquals(tradeOrderDO.getPayPrice(), 80);
150 - assertNull(tradeOrderDO.getPayOrderId()); 173 + assertEquals(tradeOrderDO.getPayOrderId(), 1000L);
151 assertNull(tradeOrderDO.getPayChannel()); 174 assertNull(tradeOrderDO.getPayChannel());
152 assertNull(tradeOrderDO.getDeliveryTemplateId()); 175 assertNull(tradeOrderDO.getDeliveryTemplateId());
153 assertNull(tradeOrderDO.getExpressNo()); 176 assertNull(tradeOrderDO.getExpressNo());
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.pay.api.order; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.pay.api.order;
3 import lombok.Data; 3 import lombok.Data;
4 import org.hibernate.validator.constraints.Length; 4 import org.hibernate.validator.constraints.Length;
5 5
6 -import javax.validation.constraints.DecimalMin; 6 +import javax.validation.constraints.Min;
7 import javax.validation.constraints.NotEmpty; 7 import javax.validation.constraints.NotEmpty;
8 import javax.validation.constraints.NotNull; 8 import javax.validation.constraints.NotNull;
9 import java.io.Serializable; 9 import java.io.Serializable;
@@ -45,7 +45,7 @@ public class PayOrderInfoCreateReqDTO implements Serializable { @@ -45,7 +45,7 @@ public class PayOrderInfoCreateReqDTO implements Serializable {
45 /** 45 /**
46 * 商品描述 46 * 商品描述
47 */ 47 */
48 - @NotEmpty(message = "商品描述信息不能为空") 48 +// @NotEmpty(message = "商品描述信息不能为空") // 允许空
49 @Length(max = 128, message = "商品描述信息长度不能超过128") 49 @Length(max = 128, message = "商品描述信息长度不能超过128")
50 private String body; 50 private String body;
51 51
@@ -55,8 +55,7 @@ public class PayOrderInfoCreateReqDTO implements Serializable { @@ -55,8 +55,7 @@ public class PayOrderInfoCreateReqDTO implements Serializable {
55 * 支付金额,单位:分 55 * 支付金额,单位:分
56 */ 56 */
57 @NotNull(message = "支付金额不能为空") 57 @NotNull(message = "支付金额不能为空")
58 - // TODO @LeeYan9: 是不是 @Min 注解呀, 是 Integer 哈  
59 - @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") 58 + @Min(value = 1, message = "支付金额必须大于零")
60 private Integer amount; 59 private Integer amount;
61 60
62 /** 61 /**
@@ -65,4 +64,4 @@ public class PayOrderInfoCreateReqDTO implements Serializable { @@ -65,4 +64,4 @@ public class PayOrderInfoCreateReqDTO implements Serializable {
65 @NotNull(message = "支付过期时间不能为空") 64 @NotNull(message = "支付过期时间不能为空")
66 private Date expireTime; 65 private Date expireTime;
67 66
68 -}  
69 \ No newline at end of file 67 \ No newline at end of file
  68 +}
yudao-server/src/main/resources/application.yaml
@@ -97,8 +97,8 @@ yudao: @@ -97,8 +97,8 @@ yudao:
97 enable: true # 验证码的开关,默认为 true;注意,优先读取数据库 infra_config 的 yudao.captcha.enable,所以请从数据库修改,可能需要重启项目 97 enable: true # 验证码的开关,默认为 true;注意,优先读取数据库 infra_config 的 yudao.captcha.enable,所以请从数据库修改,可能需要重启项目
98 trade: 98 trade:
99 order: 99 order:
100 - app-id: 1  
101 - merchant-order-id: 1 100 + app-id: 1 # 商户编号
  101 + expire-time: 2h # 支付的过期时间
102 codegen: 102 codegen:
103 base-package: ${yudao.info.base-package} 103 base-package: ${yudao.info.base-package}
104 db-schemas: ${spring.datasource.dynamic.datasource.master.name} 104 db-schemas: ${spring.datasource.dynamic.datasource.master.name}