Эх сурвалжийг харах

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

YunaiV 2 жил өмнө
parent
commit
73b92190c6

+ 4 - 4
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java

@@ -18,14 +18,14 @@ public class ProductSkuRespDTO {
      * 商品 SKU 编号,自增
      */
     private Long id;
-    /**
-     * SPU 名字
-     */
-    private String name;
     /**
      * SPU 编号
      */
     private Long spuId;
+    /**
+     * SPU 名字
+     */
+    private String spuName;
 
     /**
      * 规格值数组,JSON 格式

+ 1 - 0
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
 import cn.iocoder.yudao.module.product.service.sku.ProductSkuServiceImpl;
 import com.google.common.collect.Lists;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 import org.springframework.boot.test.mock.mockito.MockBean;

+ 7 - 7
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 {
     @NotNull(message = "订单项编号不能为空")
     private Long orderItemId;
 
+    @ApiModelProperty(name = "售后类型", required = true, example = "1", notes = "对应 TradeAfterSaleTypeEnum 枚举")
+    @NotNull(message = "售后类型不能为空")
+    @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
+    private Integer type;
+
     @ApiModelProperty(name = "退款金额", required = true, example = "100", notes = "单位:分")
     @NotNull(message = "退款金额不能为空")
     @Min(value = 1, message = "退款金额必须大于 0")
-    private Integer applyPrice;
+    private Integer refundPrice;
 
     @ApiModelProperty(name = "申请原因", required = true, example = "1", notes = "使用数据字典枚举,对应 trade_refund_apply_reason 类型")
     @NotNull(message = "申请原因不能为空")
-    private Integer applyReason;
+    private String applyReason;
 
     @ApiModelProperty(name = "补充描述", example = "商品质量不好")
     private String applyDescription;
@@ -33,9 +38,4 @@ public class AppTradeAfterSaleCreateReqVO {
     @ApiModelProperty(name = "补充凭证图片", example = "https://www.iocoder.cn/1.png, https://www.iocoder.cn/2.png")
     private List<String> applyPicUrls;
 
-    @ApiModelProperty(name = "售后类型", required = true, example = "1", notes = "对应 TradeAfterSaleTypeEnum 枚举")
-    @NotNull(message = "售后类型不能为空")
-    @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
-    private Integer type;
-
 }

+ 46 - 24
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;
  *
  * @author 芋道源码
  */
-@TableName(value = "trade_after_sale")
+@TableName(value = "trade_after_sale", autoResultMap = true)
 @Data
 @EqualsAndHashCode(callSuper = true)
 @Accessors(chain = true)
@@ -57,9 +57,10 @@ public class TradeAfterSaleDO extends BaseDO {
     /**
      * 申请原因
      *
-     * 使用数据字典枚举,对应 trade_refund_apply_reason 类型
+     * type = 退款,对应 trade_after_sale_refund_reason 类型
+     * type = 退货退款,对应 trade_after_sale_refund_and_return_reason 类型
      */
-    private Integer applyReason;
+    private String applyReason;
     /**
      * 补充描述
      */
@@ -72,25 +73,6 @@ public class TradeAfterSaleDO extends BaseDO {
     @TableField(typeHandler = JacksonTypeHandler.class)
     private List<String> applyPicUrls;
 
-    // ========== 商家相关 ==========
-
-    /**
-     * 审批时间
-     */
-    private LocalDateTime auditTime;
-    /**
-     * 审批人
-     *
-     * 关联 AdminUserDO 的 id 编号
-     */
-    private Long auditUserId;
-    /**
-     * 审批备注
-     *
-     * 注意,只有审批不通过才会填写
-     */
-    private String auditReason;
-
     // ========== 交易订单相关 ==========
     /**
      * 交易订单编号
@@ -107,20 +89,60 @@ public class TradeAfterSaleDO extends BaseDO {
     /**
      * 商品 SPU 编号
      *
-     * 关联 ProductSpuDO 的编号
+     * 关联 ProductSpuDO 的 id 字段
+     * 冗余 {@link TradeOrderItemDO#getSpuId()}
      */
     private Long spuId;
+    /**
+     * 商品 SPU 名称
+     *
+     * 关联 ProductSkuDO 的 name 字段
+     * 冗余 {@link TradeOrderItemDO#getSpuName()}
+     */
+    private String spuName;
     /**
      * 商品 SKU 编号
      *
      * 关联 ProductSkuDO 的编号
      */
-    private Integer skuId;
+    private Long skuId;
+    /**
+     * 规格值数组,JSON 格式
+     *
+     * 冗余 {@link TradeOrderItemDO#getProperties()}
+     */
+    @TableField(typeHandler = TradeOrderItemDO.PropertyTypeHandler.class)
+    private List<TradeOrderItemDO.Property> properties;
+    /**
+     * 商品图片
+     *
+     * 冗余 {@link TradeOrderItemDO#getPicUrl()}
+     */
+    private String picUrl;
     /**
      * 退货商品数量
      */
     private Integer count;
 
+    // ========== 审批相关 ==========
+
+    /**
+     * 审批时间
+     */
+    private LocalDateTime auditTime;
+    /**
+     * 审批人
+     *
+     * 关联 AdminUserDO 的 id 编号
+     */
+    private Long auditUserId;
+    /**
+     * 审批备注
+     *
+     * 注意,只有审批不通过才会填写
+     */
+    private String auditReason;
+
     // ========== 退款相关 ==========
     /**
      * 退款金额,单位:分。

+ 11 - 8
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;
 
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -41,13 +42,19 @@ public class TradeOrderItemDO extends BaseDO {
      */
     private Long orderId;
 
-    // ========== 商品基本信息 ==========
+    // ========== 商品基本信息; 冗余较多字段,减少关联查询 ==========
     /**
      * 商品 SPU 编号
      *
      * 关联 ProductSkuDO 的 spuId 编号
      */
     private Long spuId;
+    /**
+     * 商品 SPU 名称
+     *
+     * 冗余 ProductSkuDO 的 spuName 编号
+     */
+    private String spuName;
     /**
      * 商品 SKU 编号
      *
@@ -56,15 +63,11 @@ public class TradeOrderItemDO extends BaseDO {
     private Long skuId;
     /**
      * 规格值数组,JSON 格式
+     *
+     * 冗余 ProductSkuDO 的 properties 字段
      */
     @TableField(typeHandler = PropertyTypeHandler.class)
     private List<Property> properties;
-    /**
-     * 商品名称
-     *
-     * 冗余 ProductSpuDO 的 name 字段
-     */
-    private String name;
     /**
      * 商品图片
      */
@@ -142,7 +145,7 @@ public class TradeOrderItemDO extends BaseDO {
      *
      * 枚举 {@link TradeOrderItemAfterSaleStatusEnum}
      *
-     * @see cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO
+     * @see TradeAfterSaleDO
      */
     private Integer afterSaleStatus;
 

+ 1 - 1
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 {
         // TODO 芋艿:超过一定时间,不允许售后
 
         // 申请的退款金额,不能超过商品的价格
-        if (createReqVO.getApplyPrice() > orderItem.getOrderDividePrice()) {
+        if (createReqVO.getRefundPrice() > orderItem.getOrderDividePrice()) {
             throw exception(AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR);
         }
 

+ 87 - 0
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java

@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.module.trade.service.aftersale;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
+import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper;
+import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
+import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
+import static java.util.Arrays.asList;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link TradeAfterSaleService} 的单元测试
+ *
+ * @author 芋道源码
+ */
+@Import(TradeAfterSaleServiceImpl.class)
+public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
+
+    @Resource
+    private TradeAfterSaleServiceImpl tradeAfterSaleService;
+
+    @Resource
+    private TradeAfterSaleMapper tradeAfterSaleMapper;
+
+    @MockBean
+    private TradeOrderService tradeOrderService;
+    @MockBean
+    private PayRefundApi payRefundApi;
+
+    @MockBean
+    private TradeOrderProperties tradeOrderProperties;
+
+    @Test
+    public void testCreateAfterSale() {
+        // 准备参数
+        Long userId = 1024L;
+        AppTradeAfterSaleCreateReqVO createReqVO = new AppTradeAfterSaleCreateReqVO()
+                .setOrderItemId(1L).setRefundPrice(100).setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType())
+                .setApplyReason("退钱").setApplyDescription("快退")
+                .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png"));
+        // mock 方法(交易订单项)
+        TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> {
+            o.setOrderId(111L).setUserId(userId).setOrderDividePrice(200);
+            o.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
+        });
+        when(tradeOrderService.getOrderItem(eq(1024L), eq(1L)))
+                .thenReturn(orderItem);
+        // mock 方法(交易订单)
+        TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> o.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()));
+        when(tradeOrderService.getOrder(eq(1024L), eq(111L))).thenReturn(order);
+
+        // 调用
+        Long afterSaleId = tradeAfterSaleService.createAfterSale(userId, createReqVO);
+        // 断言
+        TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId);
+        assertNotNull(afterSale.getNo());
+        assertEquals(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus());
+        assertPojoEquals(afterSale, createReqVO);
+        assertEquals(afterSale.getUserId(), 1024L);
+        assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime");
+        assertNull(afterSale.getPayRefundId());
+        assertNull(afterSale.getRefundTime());
+        assertNull(afterSale.getLogisticsId());
+        assertNull(afterSale.getLogisticsNo());
+        assertNull(afterSale.getDeliveryTime());
+        assertNull(afterSale.getReceiveReason());
+    }
+
+}

+ 3 - 3
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;
  * @since 2022-09-07
  */
 @Import({TradeOrderServiceImpl.class, TradeOrderConfig.class})
-class TradeOrderServiceTest extends BaseDbUnitTest {
+public class TradeOrderServiceTest extends BaseDbUnitTest {
 
     @Resource
     private TradeOrderServiceImpl tradeOrderService;
@@ -196,7 +196,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
         assertEquals(tradeOrderItemDO01.getProperties().size(), 1);
         assertEquals(tradeOrderItemDO01.getProperties().get(0).getPropertyId(), 111L);
         assertEquals(tradeOrderItemDO01.getProperties().get(0).getValueId(), 222L);
-        assertEquals(tradeOrderItemDO01.getName(), sku01.getName());
+        assertEquals(tradeOrderItemDO01.getSpuName(), sku01.getSpuName());
         assertEquals(tradeOrderItemDO01.getPicUrl(), sku01.getPicUrl());
         assertEquals(tradeOrderItemDO01.getCount(), 3);
         assertEquals(tradeOrderItemDO01.getOriginalPrice(), 150);
@@ -216,7 +216,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
         assertEquals(tradeOrderItemDO02.getProperties().size(), 1);
         assertEquals(tradeOrderItemDO02.getProperties().get(0).getPropertyId(), 333L);
         assertEquals(tradeOrderItemDO02.getProperties().get(0).getValueId(), 444L);
-        assertEquals(tradeOrderItemDO02.getName(), sku02.getName());
+        assertEquals(tradeOrderItemDO02.getSpuName(), sku02.getSpuName());
         assertEquals(tradeOrderItemDO02.getPicUrl(), sku02.getPicUrl());
         assertEquals(tradeOrderItemDO02.getCount(), 4);
         assertEquals(tradeOrderItemDO02.getOriginalPrice(), 80);

+ 2 - 1
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql

@@ -1,2 +1,3 @@
 DELETE FROM trade_order;
-DELETE FROM trade_order_item;
+DELETE FROM trade_order_item;
+DELETE FROM trade_after_sale;

+ 37 - 1
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

@@ -50,9 +50,9 @@ CREATE TABLE IF NOT EXISTS "trade_order_item" (
       "user_id" bigint NOT NULL,
       "order_id" bigint NOT NULL,
       "spu_id" bigint NOT NULL,
+      "spu_name" varchar NOT NULL,
       "sku_id" bigint NOT NULL,
       "properties" varchar,
-      "name" varchar NOT NULL,
       "pic_url" varchar,
       "count" int NOT NULL,
       "original_price" int NOT NULL,
@@ -69,3 +69,39 @@ CREATE TABLE IF NOT EXISTS "trade_order_item" (
       "deleted" bit NOT NULL DEFAULT FALSE,
       PRIMARY KEY ("id")
 ) COMMENT '交易订单明细表';
+
+CREATE TABLE IF NOT EXISTS "trade_after_sale" (
+    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "no" varchar NOT NULL,
+    "status" int NOT NULL,
+    "type" int NOT NULL,
+    "user_id" bigint NOT NULL,
+    "apply_reason" varchar NOT NULL,
+    "apply_description" varchar,
+    "apply_pic_urls" varchar,
+    "order_id" bigint NOT NULL,
+    "order_item_id" bigint NOT NULL,
+    "spu_id" bigint NOT NULL,
+    "spu_name" varchar NOT NULL,
+    "sku_id" bigint NOT NULL,
+    "properties" varchar,
+    "pic_url" varchar,
+    "count" int NOT NULL,
+    "audit_time" varchar,
+    "audit_user_id" bigint,
+    "audit_reason" varchar,
+    "refund_price" int NOT NULL,
+    "pay_refund_id" bigint,
+    "refund_time" varchar,
+    "logistics_id" bigint,
+    "logistics_no" varchar,
+    "delivery_time" varchar,
+    "receive_time" varchar,
+    "receive_reason" varchar,
+    "creator" varchar DEFAULT '',
+    "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updater" varchar DEFAULT '',
+    "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    "deleted" bit NOT NULL DEFAULT FALSE,
+    PRIMARY KEY ("id")
+) COMMENT '交易售后表';