浏览代码

trade:【交易售后】增加售后日志

YunaiV 2 年之前
父节点
当前提交
ed9c8d4a78

+ 28 - 8
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java

@@ -6,6 +6,8 @@ import lombok.Getter;
 
 import java.util.Arrays;
 
+import static cn.hutool.core.util.ArrayUtil.firstMatch;
+
 /**
  * 售后状态的枚举
  *
@@ -17,15 +19,23 @@ import java.util.Arrays;
 @Getter
 public enum TradeAfterSaleStatusEnum implements IntArrayValuable {
 
-    APPLY(10,"申请中"), // 【申请售后】
-    SELLER_AGREE(20, "卖家通过"), // 卖家通过售后;【商品待退货】
-    BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货;【商家待收货】
-    WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款;等待退款【等待退款】
-    COMPLETE(50, "完成"), // 完成退款【退款成功】
+    APPLY(10,"申请中", // 【申请售后】
+            "会员申请退款"),
+    SELLER_AGREE(20, "卖家通过", // 卖家通过售后;【商品待退货】
+            "商家同意退款"),
+    BUYER_DELIVERY(30,"待卖家收货", // 买家已退货,等待卖家收货;【商家待收货】
+            "会员填写退货物流信息"),
+    WAIT_REFUND(40, "等待平台退款", // 卖家已收货,等待平台退款;等待退款【等待退款】
+            "商家收货"),
+    COMPLETE(50, "完成", // 完成退款【退款成功】
+            "商家确认退款"),
 
-    BUYER_CANCEL(61, "买家取消售后"), // 【买家取消】
-    SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后;商家拒绝【商家拒绝】
-    SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后;【商家拒收货】
+    BUYER_CANCEL(61, "买家取消售后", // 【买家取消】
+            "会员取消退款"),
+    SELLER_DISAGREE(62,"卖家拒绝", // 卖家拒绝售后;商家拒绝【商家拒绝】
+            "商家拒绝退款"),
+    SELLER_REFUSE(63,"卖家拒绝收货", // 卖家拒绝收货,终止售后;【商家拒收货】
+            "商家拒绝收货"),
     ;
 
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleStatusEnum::getStatus).toArray();
@@ -38,10 +48,20 @@ public enum TradeAfterSaleStatusEnum implements IntArrayValuable {
      * 状态名
      */
     private final String name;
+    /**
+     * 操作内容
+     *
+     * 目的:记录售后日志的内容
+     */
+    private final String content;
 
     @Override
     public int[] array() {
         return ARRAYS;
     }
 
+    public static TradeAfterSaleStatusEnum valueOf(Integer status) {
+        return firstMatch(value -> value.getStatus().equals(status), values());
+    }
+
 }

+ 51 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/log/TradeAfterSaleLogRespVO.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+@ApiModel("管理后台 - 交易售后日志 Response VO")
+@Data
+public class TradeAfterSaleLogRespVO {
+
+    @ApiModelProperty(value = "编号", required = true, example = "20669")
+    private Long id;
+
+    @ApiModelProperty(value = "用户编号", required = true, example = "22634")
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+
+    @ApiModelProperty(value = "用户类型", required = true, example = "2")
+    @NotNull(message = "用户类型不能为空")
+    private Integer userType;
+
+    @ApiModelProperty(value = "售后编号", required = true, example = "3023")
+    @NotNull(message = "售后编号不能为空")
+    private Long afterSaleId;
+
+    @ApiModelProperty(value = "订单编号", required = true, example = "25870")
+    @NotNull(message = "订单编号不能为空")
+    private Long orderId;
+
+    @ApiModelProperty(value = "订单项编号", required = true, example = "23154")
+    @NotNull(message = "订单项编号不能为空")
+    private Long orderItemId;
+
+    @ApiModelProperty(value = "售后状态(之前)", example = "2", notes = "参见 TradeAfterSaleStatusEnum 枚举")
+    private Integer beforeStatus;
+
+    @ApiModelProperty(value = "售后状态(之后)", required = true, example = "1", notes = "参见 TradeAfterSaleStatusEnum 枚举")
+    @NotNull(message = "售后状态(之后)不能为空")
+    private Integer afterStatus;
+
+    @ApiModelProperty(value = "操作明细", required = true, example = "维权完成,退款金额:¥37776.00")
+    @NotNull(message = "操作明细不能为空")
+    private String content;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private LocalDateTime createTime;
+
+}

+ 83 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleLogDO.java

@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.trade.dal.dataobject.aftersale;
+
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+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.enums.aftersale.TradeAfterSaleStatusEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * 交易售后日志 DO
+ *
+ * // TODO 可优化:参考淘宝或者有赞:1)增加 action 表示什么操作;2)content 记录每个操作的明细
+ *
+ * @author 芋道源码
+ */
+@TableName("trade_after_sale_log")
+@KeySequence("trade_after_sale_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class TradeAfterSaleLogDO extends BaseDO {
+
+    /**
+     * 编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 用户编号
+     *
+     * 关联 1:AdminUserDO 的 id 字段
+     * 关联 2:MemberUserDO 的 id 字段
+     */
+    private Long userId;
+    /**
+     * 用户类型
+     *
+     * 枚举 {@link UserTypeEnum}
+     */
+    private Integer userType;
+    /**
+     * 售后编号
+     *
+     * 关联 {@link TradeAfterSaleDO#getId()}
+     */
+    private Long afterSaleId;
+    /**
+     * 订单编号
+     *
+     * 关联 {@link TradeOrderDO#getId()}
+     */
+    private Long orderId;
+    /**
+     * 订单项编号
+     *
+     * 关联 {@link TradeOrderItemDO#getId()}
+     */
+    private Long orderItemId;
+    /**
+     * 售后状态(之前)
+     *
+     * 枚举 {@link TradeAfterSaleStatusEnum}
+     */
+    private Integer beforeStatus;
+    /**
+     * 售后状态(之后)
+     *
+     * 枚举 {@link TradeAfterSaleStatusEnum}
+     */
+    private Integer afterStatus;
+    /**
+     * 操作明细
+     */
+    private String content;
+
+}

+ 9 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleLogMapper.java

@@ -0,0 +1,9 @@
+package cn.iocoder.yudao.module.trade.dal.mysql.aftersale;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleLogDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface TradeAfterSaleLogMapper extends BaseMapperX<TradeAfterSaleLogDO> {
+}

+ 35 - 7
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.service.aftersale;
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
@@ -12,8 +13,10 @@ import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSa
 import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert;
 import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleLogDO;
 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.TradeAfterSaleLogMapper;
 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;
@@ -48,6 +51,8 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
 
     @Resource
     private TradeAfterSaleMapper tradeAfterSaleMapper;
+    @Resource
+    private TradeAfterSaleLogMapper tradeAfterSaleLogMapper;
 
     @Resource
     private PayRefundApi payRefundApi;
@@ -136,7 +141,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
                 TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(),
                 TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), null);
 
-        // TODO 记录售后日志
+        // 记录售后日志
+        createAfterSaleLog(orderItem.getUserId(), UserTypeEnum.MEMBER.getValue(),
+                afterSale, null, afterSale.getStatus());
 
         // TODO 发送售后消息
         return afterSale;
@@ -156,7 +163,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
         updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
                 .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()));
 
-        // TODO 记录售后日志
+        // 记录售后日志
+        createAfterSaleLog(userId, UserTypeEnum.ADMIN.getValue(),
+                afterSale, afterSale.getStatus(), newStatus);
 
         // TODO 发送售后消息
     }
@@ -173,7 +182,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
                 .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())
                 .setAuditReason(auditReqVO.getAuditReason()));
 
-        // TODO 记录售后日志
+        // 记录售后日志
+        createAfterSaleLog(userId, UserTypeEnum.ADMIN.getValue(),
+                afterSale, afterSale.getStatus(), newStatus);
 
         // TODO 发送售后消息
 
@@ -225,7 +236,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
                 .setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo())
                 .setDeliveryTime(deliveryReqVO.getDeliveryTime()));
 
-        // TODO 记录售后日志
+        // 记录售后日志
+        createAfterSaleLog(userId, UserTypeEnum.MEMBER.getValue(),
+                afterSale, afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus());
 
         // TODO 发送售后消息
     }
@@ -240,7 +253,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
         updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO()
                 .setStatus(TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now()));
 
-        // TODO 记录售后日志
+        // 记录售后日志
+        createAfterSaleLog(userId, UserTypeEnum.ADMIN.getValue(),
+                afterSale, afterSale.getStatus(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus());
 
         // TODO 发送售后消息
     }
@@ -262,7 +277,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
                 .setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now())
                 .setReceiveReason(confirmReqVO.getRefuseMemo()));
 
-        // TODO 记录售后日志
+        // 记录售后日志
+        createAfterSaleLog(userId, UserTypeEnum.ADMIN.getValue(),
+                afterSale, afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus());
 
         // TODO 发送售后消息
 
@@ -308,7 +325,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
         updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(), new TradeAfterSaleDO()
                 .setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now()));
 
-        // TODO 记录售后日志
+        // 记录售后日志
+        createAfterSaleLog(userId, UserTypeEnum.ADMIN.getValue(),
+                afterSale, afterSale.getStatus(), TradeAfterSaleStatusEnum.COMPLETE.getStatus());
 
         // TODO 发送售后消息
 
@@ -332,4 +351,13 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
         });
     }
 
+    private void createAfterSaleLog(Long userId, Integer userType, TradeAfterSaleDO afterSale,
+                                    Integer beforeStatus, Integer afterStatus) {
+        TradeAfterSaleLogDO afterSaleLog = new TradeAfterSaleLogDO().setUserId(userId).setUserType(userType)
+                .setAfterSaleId(afterSale.getId()).setOrderId(afterSale.getOrderId())
+                .setOrderItemId(afterSale.getOrderItemId()).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus)
+                .setContent(TradeAfterSaleStatusEnum.valueOf(afterStatus).getContent());
+        tradeAfterSaleLogMapper.insert(afterSaleLog);
+    }
+
 }

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

@@ -1,13 +1,16 @@
 package cn.iocoder.yudao.module.trade.service.aftersale;
 
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 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.admin.aftersale.vo.TradeAfterSalePageReqVO;
 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.aftersale.TradeAfterSaleLogDO;
 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.TradeAfterSaleLogMapper;
 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;
@@ -45,6 +48,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
 
     @Resource
     private TradeAfterSaleMapper tradeAfterSaleMapper;
+    @Resource
+    private TradeAfterSaleLogMapper tradeAfterSaleLogMapper;
 
     @MockBean
     private TradeOrderService tradeOrderService;
@@ -76,7 +81,7 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
 
         // 调用
         Long afterSaleId = tradeAfterSaleService.createAfterSale(userId, createReqVO);
-        // 断言
+        // 断言(TradeAfterSaleDO)
         TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId);
         assertNotNull(afterSale.getNo());
         assertEquals(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus());
@@ -91,6 +96,15 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         assertNull(afterSale.getLogisticsNo());
         assertNull(afterSale.getDeliveryTime());
         assertNull(afterSale.getReceiveReason());
+        // 断言(TradeAfterSaleLogDO)
+        TradeAfterSaleLogDO afterSaleLog = tradeAfterSaleLogMapper.selectList().get(0);
+        assertEquals(afterSaleLog.getUserId(), userId);
+        assertEquals(afterSaleLog.getUserType(), UserTypeEnum.MEMBER.getValue());
+        assertEquals(afterSaleLog.getAfterSaleId(), afterSaleId);
+        assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime");
+        assertNull(afterSaleLog.getBeforeStatus());
+        assertEquals(afterSaleLog.getAfterStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus());
+        assertEquals(afterSaleLog.getContent(), TradeAfterSaleStatusEnum.APPLY.getContent());
     }
 
     @Test

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

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

+ 18 - 0
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

@@ -107,3 +107,21 @@ CREATE TABLE IF NOT EXISTS "trade_after_sale" (
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
 ) COMMENT '交易售后表';
+
+CREATE TABLE IF NOT EXISTS "trade_after_sale_log" (
+    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "user_id" bigint NOT NULL,
+    "user_type" int NOT NULL,
+    "after_sale_id" bigint NOT NULL,
+    "order_id" bigint NOT NULL,
+    "order_item_id" bigint NOT NULL,
+    "before_status" int,
+    "after_status" int NOT NULL,
+    "content" varchar NOT NULL,
+    "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 '交易售后日志';