Commit 5934d6b0299b0091e1b652aeaf1bad7e968c6a1f
1 parent
84f6ec10
trade:完成下单时,创建支付单逻辑
Showing
7 changed files
with
79 additions
and
104 deletions
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} |