Commit 73b92190c602ec79fe1c50de8e0402755e5290dc

Authored by YunaiV
1 parent af71a192

trade:【交易售后】增加申请售后的单元测试

yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
... ... @@ -19,13 +19,13 @@ public class ProductSkuRespDTO {
19 19 */
20 20 private Long id;
21 21 /**
22   - * SPU 名字
23   - */
24   - private String name;
25   - /**
26 22 * SPU 编号
27 23 */
28 24 private Long spuId;
  25 + /**
  26 + * SPU 名字
  27 + */
  28 + private String spuName;
29 29  
30 30 /**
31 31 * 规格值数组,JSON 格式
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
... ... @@ -27,6 +27,7 @@ import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueServ
27 27 import cn.iocoder.yudao.module.product.service.sku.ProductSkuServiceImpl;
28 28 import com.google.common.collect.Lists;
29 29 import org.junit.jupiter.api.Assertions;
  30 +import org.junit.jupiter.api.Disabled;
30 31 import org.junit.jupiter.api.Test;
31 32 import org.mockito.Mockito;
32 33 import org.springframework.boot.test.mock.mockito.MockBean;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java
... ... @@ -18,14 +18,19 @@ public class AppTradeAfterSaleCreateReqVO {
18 18 @NotNull(message = "订单项编号不能为空")
19 19 private Long orderItemId;
20 20  
  21 + @ApiModelProperty(name = "售后类型", required = true, example = "1", notes = "对应 TradeAfterSaleTypeEnum 枚举")
  22 + @NotNull(message = "售后类型不能为空")
  23 + @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
  24 + private Integer type;
  25 +
21 26 @ApiModelProperty(name = "退款金额", required = true, example = "100", notes = "单位:分")
22 27 @NotNull(message = "退款金额不能为空")
23 28 @Min(value = 1, message = "退款金额必须大于 0")
24   - private Integer applyPrice;
  29 + private Integer refundPrice;
25 30  
26 31 @ApiModelProperty(name = "申请原因", required = true, example = "1", notes = "使用数据字典枚举,对应 trade_refund_apply_reason 类型")
27 32 @NotNull(message = "申请原因不能为空")
28   - private Integer applyReason;
  33 + private String applyReason;
29 34  
30 35 @ApiModelProperty(name = "补充描述", example = "商品质量不好")
31 36 private String applyDescription;
... ... @@ -33,9 +38,4 @@ public class AppTradeAfterSaleCreateReqVO {
33 38 @ApiModelProperty(name = "补充凭证图片", example = "https://www.iocoder.cn/1.png, https://www.iocoder.cn/2.png")
34 39 private List<String> applyPicUrls;
35 40  
36   - @ApiModelProperty(name = "售后类型", required = true, example = "1", notes = "对应 TradeAfterSaleTypeEnum 枚举")
37   - @NotNull(message = "售后类型不能为空")
38   - @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
39   - private Integer type;
40   -
41 41 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java
... ... @@ -20,7 +20,7 @@ import java.util.List;
20 20 *
21 21 * @author 芋道源码
22 22 */
23   -@TableName(value = "trade_after_sale")
  23 +@TableName(value = "trade_after_sale", autoResultMap = true)
24 24 @Data
25 25 @EqualsAndHashCode(callSuper = true)
26 26 @Accessors(chain = true)
... ... @@ -57,9 +57,10 @@ public class TradeAfterSaleDO extends BaseDO {
57 57 /**
58 58 * 申请原因
59 59 *
60   - * 使用数据字典枚举,对应 trade_refund_apply_reason 类型
  60 + * type = 退款,对应 trade_after_sale_refund_reason 类型
  61 + * type = 退货退款,对应 trade_after_sale_refund_and_return_reason 类型
61 62 */
62   - private Integer applyReason;
  63 + private String applyReason;
63 64 /**
64 65 * 补充描述
65 66 */
... ... @@ -72,25 +73,6 @@ public class TradeAfterSaleDO extends BaseDO {
72 73 @TableField(typeHandler = JacksonTypeHandler.class)
73 74 private List<String> applyPicUrls;
74 75  
75   - // ========== 商家相关 ==========
76   -
77   - /**
78   - * 审批时间
79   - */
80   - private LocalDateTime auditTime;
81   - /**
82   - * 审批人
83   - *
84   - * 关联 AdminUserDO 的 id 编号
85   - */
86   - private Long auditUserId;
87   - /**
88   - * 审批备注
89   - *
90   - * 注意,只有审批不通过才会填写
91   - */
92   - private String auditReason;
93   -
94 76 // ========== 交易订单相关 ==========
95 77 /**
96 78 * 交易订单编号
... ... @@ -107,20 +89,60 @@ public class TradeAfterSaleDO extends BaseDO {
107 89 /**
108 90 * 商品 SPU 编号
109 91 *
110   - * 关联 ProductSpuDO 的编号
  92 + * 关联 ProductSpuDO 的 id 字段
  93 + * 冗余 {@link TradeOrderItemDO#getSpuId()}
111 94 */
112 95 private Long spuId;
113 96 /**
  97 + * 商品 SPU 名称
  98 + *
  99 + * 关联 ProductSkuDO 的 name 字段
  100 + * 冗余 {@link TradeOrderItemDO#getSpuName()}
  101 + */
  102 + private String spuName;
  103 + /**
114 104 * 商品 SKU 编号
115 105 *
116 106 * 关联 ProductSkuDO 的编号
117 107 */
118   - private Integer skuId;
  108 + private Long skuId;
  109 + /**
  110 + * 规格值数组,JSON 格式
  111 + *
  112 + * 冗余 {@link TradeOrderItemDO#getProperties()}
  113 + */
  114 + @TableField(typeHandler = TradeOrderItemDO.PropertyTypeHandler.class)
  115 + private List<TradeOrderItemDO.Property> properties;
  116 + /**
  117 + * 商品图片
  118 + *
  119 + * 冗余 {@link TradeOrderItemDO#getPicUrl()}
  120 + */
  121 + private String picUrl;
119 122 /**
120 123 * 退货商品数量
121 124 */
122 125 private Integer count;
123 126  
  127 + // ========== 审批相关 ==========
  128 +
  129 + /**
  130 + * 审批时间
  131 + */
  132 + private LocalDateTime auditTime;
  133 + /**
  134 + * 审批人
  135 + *
  136 + * 关联 AdminUserDO 的 id 编号
  137 + */
  138 + private Long auditUserId;
  139 + /**
  140 + * 审批备注
  141 + *
  142 + * 注意,只有审批不通过才会填写
  143 + */
  144 + private String auditReason;
  145 +
124 146 // ========== 退款相关 ==========
125 147 /**
126 148 * 退款金额,单位:分。
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order;
2 2  
3 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
5 6 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
6 7 import com.baomidou.mybatisplus.annotation.TableField;
7 8 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -41,7 +42,7 @@ public class TradeOrderItemDO extends BaseDO {
41 42 */
42 43 private Long orderId;
43 44  
44   - // ========== 商品基本信息 ==========
  45 + // ========== 商品基本信息; 冗余较多字段,减少关联查询 ==========
45 46 /**
46 47 * 商品 SPU 编号
47 48 *
... ... @@ -49,6 +50,12 @@ public class TradeOrderItemDO extends BaseDO {
49 50 */
50 51 private Long spuId;
51 52 /**
  53 + * 商品 SPU 名称
  54 + *
  55 + * 冗余 ProductSkuDO 的 spuName 编号
  56 + */
  57 + private String spuName;
  58 + /**
52 59 * 商品 SKU 编号
53 60 *
54 61 * 关联 ProductSkuDO 的 id 编号
... ... @@ -56,16 +63,12 @@ public class TradeOrderItemDO extends BaseDO {
56 63 private Long skuId;
57 64 /**
58 65 * 规格值数组,JSON 格式
  66 + *
  67 + * 冗余 ProductSkuDO 的 properties 字段
59 68 */
60 69 @TableField(typeHandler = PropertyTypeHandler.class)
61 70 private List<Property> properties;
62 71 /**
63   - * 商品名称
64   - *
65   - * 冗余 ProductSpuDO 的 name 字段
66   - */
67   - private String name;
68   - /**
69 72 * 商品图片
70 73 */
71 74 private String picUrl;
... ... @@ -142,7 +145,7 @@ public class TradeOrderItemDO extends BaseDO {
142 145 *
143 146 * 枚举 {@link TradeOrderItemAfterSaleStatusEnum}
144 147 *
145   - * @see cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO
  148 + * @see TradeAfterSaleDO
146 149 */
147 150 private Integer afterSaleStatus;
148 151  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
... ... @@ -84,7 +84,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
84 84 // TODO 芋艿:超过一定时间,不允许售后
85 85  
86 86 // 申请的退款金额,不能超过商品的价格
87   - if (createReqVO.getApplyPrice() > orderItem.getOrderDividePrice()) {
  87 + if (createReqVO.getRefundPrice() > orderItem.getOrderDividePrice()) {
88 88 throw exception(AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR);
89 89 }
90 90  
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.aftersale;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
  5 +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
  6 +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
  8 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
  9 +import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper;
  10 +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum;
  11 +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum;
  12 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
  13 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
  14 +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
  15 +import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
  16 +import org.junit.jupiter.api.Test;
  17 +import org.springframework.boot.test.mock.mockito.MockBean;
  18 +import org.springframework.context.annotation.Import;
  19 +
  20 +import javax.annotation.Resource;
  21 +
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  23 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  24 +import static java.util.Arrays.asList;
  25 +import static org.junit.jupiter.api.Assertions.*;
  26 +import static org.mockito.ArgumentMatchers.eq;
  27 +import static org.mockito.Mockito.when;
  28 +
  29 +/**
  30 + * {@link TradeAfterSaleService} 的单元测试
  31 + *
  32 + * @author 芋道源码
  33 + */
  34 +@Import(TradeAfterSaleServiceImpl.class)
  35 +public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
  36 +
  37 + @Resource
  38 + private TradeAfterSaleServiceImpl tradeAfterSaleService;
  39 +
  40 + @Resource
  41 + private TradeAfterSaleMapper tradeAfterSaleMapper;
  42 +
  43 + @MockBean
  44 + private TradeOrderService tradeOrderService;
  45 + @MockBean
  46 + private PayRefundApi payRefundApi;
  47 +
  48 + @MockBean
  49 + private TradeOrderProperties tradeOrderProperties;
  50 +
  51 + @Test
  52 + public void testCreateAfterSale() {
  53 + // 准备参数
  54 + Long userId = 1024L;
  55 + AppTradeAfterSaleCreateReqVO createReqVO = new AppTradeAfterSaleCreateReqVO()
  56 + .setOrderItemId(1L).setRefundPrice(100).setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType())
  57 + .setApplyReason("退钱").setApplyDescription("快退")
  58 + .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png"));
  59 + // mock 方法(交易订单项)
  60 + TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> {
  61 + o.setOrderId(111L).setUserId(userId).setOrderDividePrice(200);
  62 + o.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
  63 + });
  64 + when(tradeOrderService.getOrderItem(eq(1024L), eq(1L)))
  65 + .thenReturn(orderItem);
  66 + // mock 方法(交易订单)
  67 + TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> o.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()));
  68 + when(tradeOrderService.getOrder(eq(1024L), eq(111L))).thenReturn(order);
  69 +
  70 + // 调用
  71 + Long afterSaleId = tradeAfterSaleService.createAfterSale(userId, createReqVO);
  72 + // 断言
  73 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId);
  74 + assertNotNull(afterSale.getNo());
  75 + assertEquals(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus());
  76 + assertPojoEquals(afterSale, createReqVO);
  77 + assertEquals(afterSale.getUserId(), 1024L);
  78 + assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime");
  79 + assertNull(afterSale.getPayRefundId());
  80 + assertNull(afterSale.getRefundTime());
  81 + assertNull(afterSale.getLogisticsId());
  82 + assertNull(afterSale.getLogisticsNo());
  83 + assertNull(afterSale.getDeliveryTime());
  84 + assertNull(afterSale.getReceiveReason());
  85 + }
  86 +
  87 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
... ... @@ -51,7 +51,7 @@ import static org.mockito.Mockito.when;
51 51 * @since 2022-09-07
52 52 */
53 53 @Import({TradeOrderServiceImpl.class, TradeOrderConfig.class})
54   -class TradeOrderServiceTest extends BaseDbUnitTest {
  54 +public class TradeOrderServiceTest extends BaseDbUnitTest {
55 55  
56 56 @Resource
57 57 private TradeOrderServiceImpl tradeOrderService;
... ... @@ -196,7 +196,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
196 196 assertEquals(tradeOrderItemDO01.getProperties().size(), 1);
197 197 assertEquals(tradeOrderItemDO01.getProperties().get(0).getPropertyId(), 111L);
198 198 assertEquals(tradeOrderItemDO01.getProperties().get(0).getValueId(), 222L);
199   - assertEquals(tradeOrderItemDO01.getName(), sku01.getName());
  199 + assertEquals(tradeOrderItemDO01.getSpuName(), sku01.getSpuName());
200 200 assertEquals(tradeOrderItemDO01.getPicUrl(), sku01.getPicUrl());
201 201 assertEquals(tradeOrderItemDO01.getCount(), 3);
202 202 assertEquals(tradeOrderItemDO01.getOriginalPrice(), 150);
... ... @@ -216,7 +216,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
216 216 assertEquals(tradeOrderItemDO02.getProperties().size(), 1);
217 217 assertEquals(tradeOrderItemDO02.getProperties().get(0).getPropertyId(), 333L);
218 218 assertEquals(tradeOrderItemDO02.getProperties().get(0).getValueId(), 444L);
219   - assertEquals(tradeOrderItemDO02.getName(), sku02.getName());
  219 + assertEquals(tradeOrderItemDO02.getSpuName(), sku02.getSpuName());
220 220 assertEquals(tradeOrderItemDO02.getPicUrl(), sku02.getPicUrl());
221 221 assertEquals(tradeOrderItemDO02.getCount(), 4);
222 222 assertEquals(tradeOrderItemDO02.getOriginalPrice(), 80);
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql
1 1 DELETE FROM trade_order;
2   -DELETE FROM trade_order_item;
3 2 \ No newline at end of file
  3 +DELETE FROM trade_order_item;
  4 +DELETE FROM trade_after_sale;
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
... ... @@ -50,9 +50,9 @@ CREATE TABLE IF NOT EXISTS &quot;trade_order_item&quot; (
50 50 "user_id" bigint NOT NULL,
51 51 "order_id" bigint NOT NULL,
52 52 "spu_id" bigint NOT NULL,
  53 + "spu_name" varchar NOT NULL,
53 54 "sku_id" bigint NOT NULL,
54 55 "properties" varchar,
55   - "name" varchar NOT NULL,
56 56 "pic_url" varchar,
57 57 "count" int NOT NULL,
58 58 "original_price" int NOT NULL,
... ... @@ -69,3 +69,39 @@ CREATE TABLE IF NOT EXISTS &quot;trade_order_item&quot; (
69 69 "deleted" bit NOT NULL DEFAULT FALSE,
70 70 PRIMARY KEY ("id")
71 71 ) COMMENT '交易订单明细表';
  72 +
  73 +CREATE TABLE IF NOT EXISTS "trade_after_sale" (
  74 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  75 + "no" varchar NOT NULL,
  76 + "status" int NOT NULL,
  77 + "type" int NOT NULL,
  78 + "user_id" bigint NOT NULL,
  79 + "apply_reason" varchar NOT NULL,
  80 + "apply_description" varchar,
  81 + "apply_pic_urls" varchar,
  82 + "order_id" bigint NOT NULL,
  83 + "order_item_id" bigint NOT NULL,
  84 + "spu_id" bigint NOT NULL,
  85 + "spu_name" varchar NOT NULL,
  86 + "sku_id" bigint NOT NULL,
  87 + "properties" varchar,
  88 + "pic_url" varchar,
  89 + "count" int NOT NULL,
  90 + "audit_time" varchar,
  91 + "audit_user_id" bigint,
  92 + "audit_reason" varchar,
  93 + "refund_price" int NOT NULL,
  94 + "pay_refund_id" bigint,
  95 + "refund_time" varchar,
  96 + "logistics_id" bigint,
  97 + "logistics_no" varchar,
  98 + "delivery_time" varchar,
  99 + "receive_time" varchar,
  100 + "receive_reason" varchar,
  101 + "creator" varchar DEFAULT '',
  102 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  103 + "updater" varchar DEFAULT '',
  104 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  105 + "deleted" bit NOT NULL DEFAULT FALSE,
  106 + PRIMARY KEY ("id")
  107 +) COMMENT '交易售后表';
... ...