Commit bc2aa78f706ca45ae1e4e715de56eb031e001d3c
1 parent
01d10b51
trade:创建订单接口的后端实现的单元测试 50%
Showing
12 changed files
with
247 additions
and
233 deletions
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.order; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.order; | ||
| 3 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 3 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 4 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | 4 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| 5 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 5 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 6 | +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | ||
| 6 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | 7 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; |
| 7 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | 8 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | 9 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| @@ -33,7 +34,7 @@ public interface TradeOrderConvert { | @@ -33,7 +34,7 @@ public interface TradeOrderConvert { | ||
| 33 | @Mapping(source = "address.postCode", target = "receiverPostCode"), | 34 | @Mapping(source = "address.postCode", target = "receiverPostCode"), |
| 34 | @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), | 35 | @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), |
| 35 | }) | 36 | }) |
| 36 | - TradeOrderDO convert(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, | 37 | + TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, |
| 37 | PriceCalculateRespDTO.Order order, AddressRespDTO address); | 38 | PriceCalculateRespDTO.Order order, AddressRespDTO address); |
| 38 | 39 | ||
| 39 | @Mappings({ | 40 | @Mappings({ |
| @@ -49,10 +50,13 @@ public interface TradeOrderConvert { | @@ -49,10 +50,13 @@ public interface TradeOrderConvert { | ||
| 49 | TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId())); | 50 | TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId())); |
| 50 | tradeOrderItemDO.setOrderId(tradeOrderDO.getId()); | 51 | tradeOrderItemDO.setOrderId(tradeOrderDO.getId()); |
| 51 | tradeOrderItemDO.setUserId(tradeOrderDO.getUserId()); | 52 | tradeOrderItemDO.setUserId(tradeOrderDO.getUserId()); |
| 52 | - tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()); | 53 | + tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()).setRefundTotal(0); // 退款信息 |
| 53 | // tradeOrderItemDO.setCommented(false); | 54 | // tradeOrderItemDO.setCommented(false); |
| 54 | return tradeOrderItemDO; | 55 | return tradeOrderItemDO; |
| 55 | }); | 56 | }); |
| 56 | } | 57 | } |
| 57 | 58 | ||
| 59 | + @Mapping(source = "userId" , target = "userId") | ||
| 60 | + PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId); | ||
| 61 | + | ||
| 58 | } | 62 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/price/PriceConvert.java deleted
| 1 | -package cn.iocoder.yudao.module.trade.convert.price; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | ||
| 4 | -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | ||
| 5 | -import org.mapstruct.Mapper; | ||
| 6 | -import org.mapstruct.Mapping; | ||
| 7 | -import org.mapstruct.Mappings; | ||
| 8 | -import org.mapstruct.factory.Mappers; | ||
| 9 | - | ||
| 10 | -@Mapper | ||
| 11 | -public interface PriceConvert { | ||
| 12 | - | ||
| 13 | - PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class); | ||
| 14 | - | ||
| 15 | - @Mappings( | ||
| 16 | - @Mapping(source = "userId" , target = "userId") | ||
| 17 | - ) | ||
| 18 | - PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId); | ||
| 19 | - | ||
| 20 | -} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
| @@ -138,19 +138,19 @@ public class TradeOrderItemDO extends BaseDO { | @@ -138,19 +138,19 @@ public class TradeOrderItemDO extends BaseDO { | ||
| 138 | * 枚举 {@link TradeOrderItemRefundStatusEnum} | 138 | * 枚举 {@link TradeOrderItemRefundStatusEnum} |
| 139 | */ | 139 | */ |
| 140 | private Integer refundStatus; // TODO 芋艿:可以考虑去查 | 140 | private Integer refundStatus; // TODO 芋艿:可以考虑去查 |
| 141 | -// // 如上字段,举个例子: | ||
| 142 | -// // 假设购买三个,即 stock = 3 。 | ||
| 143 | -// // originPrice = 15 | ||
| 144 | -// // 使用限时折扣(单品优惠)8 折,buyPrice = 12 | ||
| 145 | -// // 开始算总的价格 | ||
| 146 | -// // buyTotal = buyPrice * stock = 12 * 3 = 36 | ||
| 147 | -// // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11 | ||
| 148 | -// // presentTotal = buyTotal - discountTotal = 24 - 11 = 13 | ||
| 149 | -// // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 | ||
| 150 | -// /** | ||
| 151 | -// * 退款总金额,单位:分 TODO | ||
| 152 | -// */ | ||
| 153 | -// private Integer refundTotal; | 141 | + // 如上字段,举个例子: |
| 142 | + // 假设购买三个,即 stock = 3 。 | ||
| 143 | + // originPrice = 15 | ||
| 144 | + // 使用限时折扣(单品优惠)8 折,buyPrice = 12 | ||
| 145 | + // 开始算总的价格 | ||
| 146 | + // buyTotal = buyPrice * stock = 12 * 3 = 36 | ||
| 147 | + // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11 | ||
| 148 | + // presentTotal = buyTotal - discountTotal = 24 - 11 = 13 | ||
| 149 | + // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 | ||
| 150 | + /** | ||
| 151 | + * 退款总金额,单位:分 TODO | ||
| 152 | + */ | ||
| 153 | + private Integer refundTotal; | ||
| 154 | 154 | ||
| 155 | /** | 155 | /** |
| 156 | * 商品属性 | 156 | * 商品属性 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java
| @@ -14,9 +14,10 @@ public interface TradeOrderService { | @@ -14,9 +14,10 @@ public interface TradeOrderService { | ||
| 14 | * 创建交易订单 | 14 | * 创建交易订单 |
| 15 | * | 15 | * |
| 16 | * @param loginUserId 登录用户 | 16 | * @param loginUserId 登录用户 |
| 17 | - * @param clientIp 用户 IP 地址 | 17 | + * @param userIp 用户 IP 地址 |
| 18 | * @param createReqVO 创建交易订单请求模型 | 18 | * @param createReqVO 创建交易订单请求模型 |
| 19 | * @return 交易订单的编号 | 19 | * @return 交易订单的编号 |
| 20 | */ | 20 | */ |
| 21 | - Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO); | 21 | + Long createTradeOrder(Long loginUserId, String userIp, AppTradeOrderCreateReqVO createReqVO); |
| 22 | + | ||
| 22 | } | 23 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
| @@ -18,12 +18,10 @@ import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | @@ -18,12 +18,10 @@ import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||
| 18 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | 18 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 19 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | 19 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; |
| 20 | import cn.iocoder.yudao.module.promotion.api.price.PriceApi; | 20 | import cn.iocoder.yudao.module.promotion.api.price.PriceApi; |
| 21 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | ||
| 22 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | 21 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; |
| 23 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | 22 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| 24 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item; | 23 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item; |
| 25 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; | 24 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; |
| 26 | -import cn.iocoder.yudao.module.trade.convert.price.PriceConvert; | ||
| 27 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | 25 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 28 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | 26 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 29 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; | 27 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| @@ -82,20 +80,19 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -82,20 +80,19 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 82 | 80 | ||
| 83 | @Override | 81 | @Override |
| 84 | @Transactional(rollbackFor = Exception.class) | 82 | @Transactional(rollbackFor = Exception.class) |
| 85 | - public Long createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { | 83 | + public Long createTradeOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { |
| 86 | // 商品 SKU 检查:可售状态、库存 | 84 | // 商品 SKU 检查:可售状态、库存 |
| 87 | List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); | 85 | List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); |
| 88 | // 商品 SPU 检查:可售状态 | 86 | // 商品 SPU 检查:可售状态 |
| 89 | - List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); | 87 | + validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); |
| 90 | // 用户收件地址的校验 | 88 | // 用户收件地址的校验 |
| 91 | AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); | 89 | AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); |
| 92 | 90 | ||
| 93 | // 价格计算 | 91 | // 价格计算 |
| 94 | - PriceCalculateReqDTO priceCalculateReqDTO = PriceConvert.INSTANCE.convert(createReqVO, userId); | ||
| 95 | - PriceCalculateRespDTO priceResp = priceApi.calculatePrice(priceCalculateReqDTO); | 92 | + PriceCalculateRespDTO priceResp = priceApi.calculatePrice(TradeOrderConvert.INSTANCE.convert(createReqVO, userId)); |
| 96 | 93 | ||
| 97 | // 插入 TradeOrderDO 订单 | 94 | // 插入 TradeOrderDO 订单 |
| 98 | - TradeOrderDO tradeOrderDO = createTradeOrder(userId, clientIp, createReqVO, priceResp.getOrder(), address); | 95 | + TradeOrderDO tradeOrderDO = createTradeOrder(userId, userIp, createReqVO, priceResp.getOrder(), address); |
| 99 | // 插入 TradeOrderItemDO 订单项 | 96 | // 插入 TradeOrderItemDO 订单项 |
| 100 | createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); | 97 | createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); |
| 101 | 98 | ||
| @@ -208,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -208,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 208 | // 校验是否存在禁用的 SPU | 205 | // 校验是否存在禁用的 SPU |
| 209 | ProductSpuRespDTO spu = CollectionUtils.findFirst(spus, | 206 | ProductSpuRespDTO spu = CollectionUtils.findFirst(spus, |
| 210 | spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus())); | 207 | spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus())); |
| 211 | - if (Objects.isNull(spu)) { | 208 | + if (spu != null) { |
| 212 | throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE); | 209 | throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE); |
| 213 | } | 210 | } |
| 214 | return spus; | 211 | return spus; |
| @@ -238,6 +235,9 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -238,6 +235,9 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 238 | tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); | 235 | tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); |
| 239 | tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); | 236 | tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); |
| 240 | tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? | 237 | tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? |
| 238 | + tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息 | ||
| 239 | + tradeOrderDO.setDeliveryStatus(false); // 物流信息 | ||
| 240 | + tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息 | ||
| 241 | tradeOrderMapper.insert(tradeOrderDO); | 241 | tradeOrderMapper.insert(tradeOrderDO); |
| 242 | return tradeOrderDO; | 242 | return tradeOrderDO; |
| 243 | } | 243 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java deleted
| 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.promotion.api.price.PriceApi; | ||
| 6 | -import cn.iocoder.yudao.module.promotion.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 | -// TODO @芋艿: 单测的 review; 最后搞; | ||
| 34 | -/** | ||
| 35 | - * @author LeeYan9 | ||
| 36 | - * @since 2022-09-07 | ||
| 37 | - */ | ||
| 38 | -@Import({TradeOrderServiceImpl.class, TradeOrderConfig.class}) | ||
| 39 | -class TradeOrderServiceTest extends BaseDbUnitTest { | ||
| 40 | - | ||
| 41 | - | ||
| 42 | - @Resource | ||
| 43 | - TradeOrderService tradeOrderService; | ||
| 44 | - @Resource | ||
| 45 | - TradeOrderMapper tradeOrderMapper; | ||
| 46 | - @Resource | ||
| 47 | - TradeOrderItemMapper tradeOrderItemMapper; | ||
| 48 | - @MockBean | ||
| 49 | - ProductSpuApi productSpuApi; | ||
| 50 | - @MockBean | ||
| 51 | - ProductSkuApi productSkuApi; | ||
| 52 | - @MockBean | ||
| 53 | - PriceApi priceApi; | ||
| 54 | - @MockBean | ||
| 55 | - private PayOrderApi payOrderApi; | ||
| 56 | - | ||
| 57 | - @Test | ||
| 58 | - void testCreateTradeOrder_success() { | ||
| 59 | - // mock 商品SPU数据 | ||
| 60 | - SpuInfoRespDTO spuInfoRespDTO = randomPojo(SpuInfoRespDTO.class, spuInfo -> { | ||
| 61 | - spuInfo.setId(1L); | ||
| 62 | - spuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus()); | ||
| 63 | - }); | ||
| 64 | - when(productSpuApi.getSpuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(spuInfoRespDTO)); | ||
| 65 | - // mock 商品SkU数据 | ||
| 66 | - ProductSkuRespDTO skuInfoRespDTO = randomPojo(ProductSkuRespDTO.class, skuInfo -> { | ||
| 67 | - skuInfo.setId(1L); | ||
| 68 | - skuInfo.setStatus(CommonStatusEnum.ENABLE.getStatus()); | ||
| 69 | - skuInfo.setStock(randomInteger()); | ||
| 70 | - skuInfo.setSpuId(1L); | ||
| 71 | - }); | ||
| 72 | - when(productSkuApi.getSkuList(Collections.singleton(1L))).thenReturn(Lists.newArrayList(skuInfoRespDTO)); | ||
| 73 | - // mock 价格信息 | ||
| 74 | - PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> { | ||
| 75 | - PriceCalculateRespDTO.OrderItem item = priceCalculateRespDTO.getOrder().getItems().get(0); | ||
| 76 | - item.setSkuId(1L); | ||
| 77 | - item.setCount(2); | ||
| 78 | - priceCalculateRespDTO.getOrder().setItems(Collections.singletonList(item)); | ||
| 79 | - }); | ||
| 80 | - when(priceApi.calculatePrice(any())).thenReturn(calculateRespDTO); | ||
| 81 | - //mock 支付订单信息 | ||
| 82 | - when(payOrderApi.createPayOrder(any())).thenReturn(1L); | ||
| 83 | - | ||
| 84 | - // 准备请求数据 | ||
| 85 | - AppTradeOrderCreateReqVO tradeOrderCreateReqVO = randomPojo(AppTradeOrderCreateReqVO.class, reqVO -> { | ||
| 86 | - AppTradeOrderCreateReqVO.Item item = randomPojo(AppTradeOrderCreateReqVO.Item.class, o -> { | ||
| 87 | - o.setSkuId(1L); | ||
| 88 | - o.setCount(2); | ||
| 89 | - }); | ||
| 90 | - reqVO.setItems(Collections.singletonList(item)); | ||
| 91 | - }); | ||
| 92 | - // 创建交易订单,支付订单记录 | ||
| 93 | - Long payOrderId = tradeOrderService.createTradeOrder(1L, "127.0.0.1", tradeOrderCreateReqVO); | ||
| 94 | - //断言交易订单 | ||
| 95 | - TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(TradeOrderDO::getUserId, 1L); | ||
| 96 | - assertNotNull(tradeOrderDO); | ||
| 97 | - //价格&用户 | ||
| 98 | - assertEquals(calculateRespDTO.getOrder().getPayPrice(), tradeOrderDO.getPayPrice()); | ||
| 99 | - assertEquals(1L, tradeOrderDO.getUserId()); | ||
| 100 | - //断言交易订单项 | ||
| 101 | - TradeOrderItemDO tradeOrderItemDO = tradeOrderItemMapper.selectOne(TradeOrderItemDO::getOrderId, tradeOrderDO.getId()); | ||
| 102 | - assertNotNull(tradeOrderDO); | ||
| 103 | - //商品&用户 | ||
| 104 | - assertEquals(skuInfoRespDTO.getId(), tradeOrderItemDO.getSkuId()); | ||
| 105 | - assertEquals(1L, tradeOrderItemDO.getUserId()); | ||
| 106 | - //价格 | ||
| 107 | - assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice()); | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | -} |
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/create_tables.sql deleted
| 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-mall/yudao-module-trade-biz/src/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.member.api.address.AddressApi; | ||
| 6 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||
| 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.ProductSpuRespDTO; | ||
| 12 | +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | ||
| 13 | +import cn.iocoder.yudao.module.promotion.api.price.PriceApi; | ||
| 14 | +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | ||
| 15 | +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | ||
| 16 | +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; | ||
| 17 | +import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; | ||
| 18 | +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig; | ||
| 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.Arrays; | ||
| 25 | + | ||
| 26 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||
| 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.mockito.ArgumentMatchers.argThat; | ||
| 30 | +import static org.mockito.ArgumentMatchers.eq; | ||
| 31 | +import static org.mockito.Mockito.when; | ||
| 32 | + | ||
| 33 | +/** | ||
| 34 | + * {@link TradeOrderServiceImpl} 的单元测试类 | ||
| 35 | + * | ||
| 36 | + * @author LeeYan9 | ||
| 37 | + * @since 2022-09-07 | ||
| 38 | + */ | ||
| 39 | +@Import({TradeOrderServiceImpl.class, TradeOrderConfig.class}) | ||
| 40 | +class TradeOrderServiceTest extends BaseDbUnitTest { | ||
| 41 | + | ||
| 42 | + @Resource | ||
| 43 | + private TradeOrderServiceImpl tradeOrderService; | ||
| 44 | + | ||
| 45 | + @Resource | ||
| 46 | + private TradeOrderMapper tradeOrderMapper; | ||
| 47 | + @Resource | ||
| 48 | + private TradeOrderItemMapper tradeOrderItemMapper; | ||
| 49 | + | ||
| 50 | + @MockBean | ||
| 51 | + private ProductSpuApi productSpuApi; | ||
| 52 | + @MockBean | ||
| 53 | + private ProductSkuApi productSkuApi; | ||
| 54 | + @MockBean | ||
| 55 | + private PriceApi priceApi; | ||
| 56 | + @MockBean | ||
| 57 | + private PayOrderApi payOrderApi; | ||
| 58 | + @MockBean | ||
| 59 | + private AddressApi addressApi; | ||
| 60 | + | ||
| 61 | + // 1, 3 个,50 块;打折 20;总和 = 60;42; | ||
| 62 | + // 2, 4 个,20 块;打折 10;总和 = 40;28; | ||
| 63 | + // 优惠劵,满 100 减 30 | ||
| 64 | + | ||
| 65 | + @Test | ||
| 66 | + public void testCreateTradeOrder_success() { | ||
| 67 | + // 准备参数 | ||
| 68 | + Long userId = 100L; | ||
| 69 | + String clientIp = "127.0.0.1"; | ||
| 70 | + AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO() | ||
| 71 | + .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true) | ||
| 72 | + .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3), | ||
| 73 | + new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4))); | ||
| 74 | + // mock 方法(商品 SKU 检查) | ||
| 75 | + ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L) | ||
| 76 | + .setPrice(50).setStock(100).setStatus(CommonStatusEnum.ENABLE.getStatus())); | ||
| 77 | + ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L) | ||
| 78 | + .setPrice(20).setStock(50).setStatus(CommonStatusEnum.ENABLE.getStatus())); | ||
| 79 | + when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02)); | ||
| 80 | + // mock 方法(商品 SPU 检查) | ||
| 81 | + ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L) | ||
| 82 | + .setStatus(ProductSpuStatusEnum.ENABLE.getStatus())); | ||
| 83 | + ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L) | ||
| 84 | + .setStatus(ProductSpuStatusEnum.ENABLE.getStatus())); | ||
| 85 | + when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02)); | ||
| 86 | + // mock 方法(用户收件地址的校验) | ||
| 87 | + AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿") | ||
| 88 | + .setMobile("15601691300").setAreaId(3306L).setPostCode("85757").setDetailAddress("土豆村"); | ||
| 89 | + when(addressApi.getAddress(eq(userId), eq(10L))).thenReturn(addressRespDTO); | ||
| 90 | + // mock 方法(价格计算) | ||
| 91 | + PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem() | ||
| 92 | + .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50) | ||
| 93 | + .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35); | ||
| 94 | + PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem() | ||
| 95 | + .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20) | ||
| 96 | + .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25); | ||
| 97 | + PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order() | ||
| 98 | + .setOriginalPrice(230).setOrderPrice(100).setDiscountPrice(0).setCouponPrice(30) | ||
| 99 | + .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30) | ||
| 100 | + .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02)); | ||
| 101 | + when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> { | ||
| 102 | + assertEquals(priceCalculateReqDTO.getUserId(), 100L); | ||
| 103 | + assertEquals(priceCalculateReqDTO.getCouponId(), 101L); | ||
| 104 | + assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L); | ||
| 105 | + assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3); | ||
| 106 | + assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L); | ||
| 107 | + assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4); | ||
| 108 | + return true; | ||
| 109 | + }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder)); | ||
| 110 | + | ||
| 111 | + // 调用方法 | ||
| 112 | + Long tradeOrderId = tradeOrderService.createTradeOrder(userId, clientIp, reqVO); | ||
| 113 | + System.out.println(tradeOrderId); | ||
| 114 | + | ||
| 115 | +// // mock 价格信息 | ||
| 116 | +// PriceCalculateRespDTO calculateRespDTO = randomPojo(PriceCalculateRespDTO.class, priceCalculateRespDTO -> { | ||
| 117 | +// PriceCalculateRespDTO.OrderItem item = priceCalculateRespDTO.getOrder().getItems().get(0); | ||
| 118 | +// item.setSkuId(1L); | ||
| 119 | +// item.setCount(2); | ||
| 120 | +// priceCalculateRespDTO.getOrder().setItems(Collections.singletonList(item)); | ||
| 121 | +// }); | ||
| 122 | +// when(priceApi.calculatePrice(any())).thenReturn(calculateRespDTO); | ||
| 123 | +// //mock 支付订单信息 | ||
| 124 | +// when(payOrderApi.createPayOrder(any())).thenReturn(1L); | ||
| 125 | + | ||
| 126 | + | ||
| 127 | +// // 创建交易订单,支付订单记录 | ||
| 128 | +// Long payOrderId = tradeOrderService.createTradeOrder(1L, "127.0.0.1", tradeOrderCreateReqVO); | ||
| 129 | +// //断言交易订单 | ||
| 130 | +// TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(TradeOrderDO::getUserId, 1L); | ||
| 131 | +// assertNotNull(tradeOrderDO); | ||
| 132 | +// //价格&用户 | ||
| 133 | +// assertEquals(calculateRespDTO.getOrder().getPayPrice(), tradeOrderDO.getPayPrice()); | ||
| 134 | +// assertEquals(1L, tradeOrderDO.getUserId()); | ||
| 135 | +// //断言交易订单项 | ||
| 136 | +// TradeOrderItemDO tradeOrderItemDO = tradeOrderItemMapper.selectOne(TradeOrderItemDO::getOrderId, tradeOrderDO.getId()); | ||
| 137 | +// assertNotNull(tradeOrderDO); | ||
| 138 | +// //商品&用户 | ||
| 139 | +// assertEquals(skuInfoRespDTO.getId(), tradeOrderItemDO.getSkuId()); | ||
| 140 | +// assertEquals(1L, tradeOrderItemDO.getUserId()); | ||
| 141 | +// //价格 | ||
| 142 | +// assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice()); | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/application-unit-test.yaml renamed to yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/logback.xml renamed to yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml
yudao-module-mall/yudao-module-trade-biz/src/main/test/resources/sql/clean.sql renamed to yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
0 → 100644
| 1 | +CREATE TABLE IF NOT EXISTS "trade_order" ( | ||
| 2 | + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||
| 3 | + "no" varchar NOT NULL, | ||
| 4 | + "type" int NOT NULL, | ||
| 5 | + "terminal" int NOT NULL, | ||
| 6 | + "user_id" bigint NOT NULL, | ||
| 7 | + "user_ip" varchar NOT NULL, | ||
| 8 | + "user_remark" varchar, | ||
| 9 | + "status" int NOT NULL, | ||
| 10 | + "product_count" int NOT NULL, | ||
| 11 | + "cancel_type" int, | ||
| 12 | + "remark" varchar, | ||
| 13 | + "payed" bit NOT NULL, | ||
| 14 | + "pay_time" datetime, | ||
| 15 | + "finish_time" datetime, | ||
| 16 | + "cancel_time" datetime, | ||
| 17 | + "original_price" int NOT NULL, | ||
| 18 | + "order_price" int NOT NULL, | ||
| 19 | + "discount_price" int NOT NULL, | ||
| 20 | + "delivery_price" int NOT NULL, | ||
| 21 | + "adjust_price" int NOT NULL, | ||
| 22 | + "pay_price" int NOT NULL, | ||
| 23 | + "pay_order_id" int, | ||
| 24 | + "pay_channel" int, | ||
| 25 | + "delivery_templateid" int, | ||
| 26 | + "express_no" int, | ||
| 27 | + "delivery_status" bit NOT NULL, | ||
| 28 | + "delivery_time" datetime, | ||
| 29 | + "receive_time" datetime, | ||
| 30 | + "receiver_name" varchar NOT NULL, | ||
| 31 | + "receiver_mobile" varchar NOT NULL, | ||
| 32 | + "receiver_area_id" int NOT NULL, | ||
| 33 | + "receiver_post_code" int, | ||
| 34 | + "receiver_detail_address" varchar NOT NULL, | ||
| 35 | + "refund_status" int NOT NULL, | ||
| 36 | + "refund_price" int NOT NULL, | ||
| 37 | + "coupon_id" bigint NOT NULL, | ||
| 38 | + "coupon_price" int NOT NULL, | ||
| 39 | + "point_price" int NOT NULL, | ||
| 40 | + "creator" varchar DEFAULT '', | ||
| 41 | + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| 42 | + "updater" varchar DEFAULT '', | ||
| 43 | + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| 44 | + "deleted" bit NOT NULL DEFAULT FALSE, | ||
| 45 | + PRIMARY KEY ("id") | ||
| 46 | +) COMMENT '交易订单表'; | ||
| 47 | + | ||
| 48 | +CREATE TABLE IF NOT EXISTS "trade_order_item" ( | ||
| 49 | + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||
| 50 | + "user_id" bigint NOT NULL, | ||
| 51 | + "order_id" bigint NOT NULL, | ||
| 52 | + "spu_id" bigint NOT NULL, | ||
| 53 | + "sku_id" bigint NOT NULL, | ||
| 54 | + "properties" varchar, | ||
| 55 | + "name" varchar NOT NULL, | ||
| 56 | + "pic_url" varchar, | ||
| 57 | + "count" int NOT NULL, | ||
| 58 | + "original_price" int NOT NULL, | ||
| 59 | + "original_unit_price" int NOT NULL, | ||
| 60 | + "discount_price" int NOT NULL, | ||
| 61 | + "pay_price" int NOT NULL, | ||
| 62 | + "order_part_price" int NOT NULL, | ||
| 63 | + "order_divide_price" int NOT NULL, | ||
| 64 | + "refund_status" int NOT NULL, | ||
| 65 | + "refund_total" int NOT NULL, | ||
| 66 | + "creator" varchar DEFAULT '', | ||
| 67 | + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| 68 | + "updater" varchar DEFAULT '', | ||
| 69 | + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| 70 | + "deleted" bit NOT NULL DEFAULT FALSE, | ||
| 71 | + PRIMARY KEY ("id") | ||
| 72 | +) COMMENT '交易订单明细表'; |