trade:完善退款详情

This commit is contained in:
YunaiV 2023-10-02 15:44:41 +08:00
parent 0c1f5c9582
commit 6f4c04d944
49 changed files with 647 additions and 689 deletions

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.common.util.spring;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.DefaultParameterNameDiscoverer;
@ -87,47 +86,4 @@ public class SpringExpressionUtils {
return result; return result;
} }
/**
* JoinPoint 切面 批量解析 EL 表达式转换 jspl参数
*
* @param joinPoint 切面点
* @param info 返回值
* @param expressionStrings EL 表达式数组
* @return Map<String, Object> 结果
* @author 陈賝
* @since 2023/6/18 11:20
*/
// TODO @chenchen: 这个方法 parseExpressions 比较接近是不是可以合并下
public static Map<String, Object> parseExpression(JoinPoint joinPoint, Object info, List<String> expressionStrings) {
// 如果为空则不进行解析
if (CollUtil.isEmpty(expressionStrings)) {
return MapUtil.newHashMap();
}
// 第一步构建解析的上下文 EvaluationContext
// 通过 joinPoint 获取被注解方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 使用 spring ParameterNameDiscoverer 获取方法形参名数组
String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
// Spring 的表达式上下文对象
EvaluationContext context = new StandardEvaluationContext();
if (ArrayUtil.isNotEmpty(parameterNames)) {
//获取方法参数值
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
// 替换 SP EL 里的变量值为实际值 比如 #user --> user对象
context.setVariable(parameterNames[i], args[i]);
}
context.setVariable("info", info);
}
// 第二步逐个参数解析
Map<String, Object> result = MapUtil.newHashMap(expressionStrings.size(), true);
expressionStrings.forEach(key -> {
Object value = EXPRESSION_PARSER.parseExpression(key).getValue(context);
result.put(key, value);
});
return result;
}
} }

View File

@ -18,7 +18,7 @@ import static cn.hutool.core.util.ArrayUtil.firstMatch;
*/ */
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter
public enum TradeAfterSaleStatusEnum implements IntArrayValuable { public enum AfterSaleStatusEnum implements IntArrayValuable {
/** /**
* 申请售后 * 申请售后
@ -54,7 +54,7 @@ public enum TradeAfterSaleStatusEnum implements IntArrayValuable {
SELLER_REFUSE(63,"卖家拒绝收货", "商家拒绝收货"), // 有赞的状态提示商家拒绝收货不同意退款 SELLER_REFUSE(63,"卖家拒绝收货", "商家拒绝收货"), // 有赞的状态提示商家拒绝收货不同意退款
; ;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleStatusEnum::getStatus).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleStatusEnum::getStatus).toArray();
/** /**
* 进行中的售后状态 * 进行中的售后状态
@ -88,7 +88,7 @@ public enum TradeAfterSaleStatusEnum implements IntArrayValuable {
return ARRAYS; return ARRAYS;
} }
public static TradeAfterSaleStatusEnum valueOf(Integer status) { public static AfterSaleStatusEnum valueOf(Integer status) {
return firstMatch(value -> value.getStatus().equals(status), values()); return firstMatch(value -> value.getStatus().equals(status), values());
} }

View File

@ -13,12 +13,12 @@ import java.util.Arrays;
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Getter @Getter
public enum TradeAfterSaleTypeEnum implements IntArrayValuable { public enum AfterSaleTypeEnum implements IntArrayValuable {
IN_SALE(10, "售中退款"), // 交易完成前买家申请退款 IN_SALE(10, "售中退款"), // 交易完成前买家申请退款
AFTER_SALE(20, "售后退款"); // 交易完成后买家申请退款 AFTER_SALE(20, "售后退款"); // 交易完成后买家申请退款
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleTypeEnum::getType).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleTypeEnum::getType).toArray();
/** /**
* 类型 * 类型

View File

@ -13,12 +13,12 @@ import java.util.Arrays;
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Getter @Getter
public enum TradeAfterSaleWayEnum implements IntArrayValuable { public enum AfterSaleWayEnum implements IntArrayValuable {
REFUND(10, "仅退款"), REFUND(10, "仅退款"),
RETURN_AND_REFUND(20, "退货退款"); RETURN_AND_REFUND(20, "退货退款");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleWayEnum::getWay).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleWayEnum::getWay).toArray();
/** /**
* 方式 * 方式

View File

@ -8,13 +8,13 @@ import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.*; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.*;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.TradeAfterSaleLogRespVO; import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert;
import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 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.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service.AfterSaleLogService; import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService;
import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@ -27,8 +27,6 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.annotation.security.PermitAll; import javax.annotation.security.PermitAll;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -42,10 +40,10 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
@RequestMapping("/trade/after-sale") @RequestMapping("/trade/after-sale")
@Validated @Validated
@Slf4j @Slf4j
public class TradeAfterSaleController { public class AfterSaleController {
@Resource @Resource
private TradeAfterSaleService afterSaleService; private AfterSaleService afterSaleService;
@Resource @Resource
private TradeOrderQueryService tradeOrderQueryService; private TradeOrderQueryService tradeOrderQueryService;
@Resource @Resource
@ -56,26 +54,26 @@ public class TradeAfterSaleController {
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得售后订单分页") @Operation(summary = "获得售后订单分页")
@PreAuthorize("@ss.hasPermission('trade:after-sale:query')") @PreAuthorize("@ss.hasPermission('trade:after-sale:query')")
public CommonResult<PageResult<TradeAfterSaleRespPageItemVO>> getAfterSalePage(@Valid TradeAfterSalePageReqVO pageVO) { public CommonResult<PageResult<AfterSaleRespPageItemVO>> getAfterSalePage(@Valid AfterSalePageReqVO pageVO) {
// 查询售后 // 查询售后
PageResult<TradeAfterSaleDO> pageResult = afterSaleService.getAfterSalePage(pageVO); PageResult<AfterSaleDO> pageResult = afterSaleService.getAfterSalePage(pageVO);
if (CollUtil.isEmpty(pageResult.getList())) { if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty()); return success(PageResult.empty());
} }
// 查询会员 // 查询会员
Map<Long, MemberUserRespDTO> memberUsers = memberUserApi.getUserMap( Map<Long, MemberUserRespDTO> memberUsers = memberUserApi.getUserMap(
convertSet(pageResult.getList(), TradeAfterSaleDO::getUserId)); convertSet(pageResult.getList(), AfterSaleDO::getUserId));
return success(TradeAfterSaleConvert.INSTANCE.convertPage(pageResult, memberUsers)); return success(AfterSaleConvert.INSTANCE.convertPage(pageResult, memberUsers));
} }
@GetMapping("/get-detail") @GetMapping("/get-detail")
@Operation(summary = "获得售后订单详情") @Operation(summary = "获得售后订单详情")
@Parameter(name = "id", description = "售后编号", required = true, example = "1") @Parameter(name = "id", description = "售后编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('trade:after-sale:query')") @PreAuthorize("@ss.hasPermission('trade:after-sale:query')")
public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { public CommonResult<AfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
// 查询订单 // 查询订单
TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id); AfterSaleDO afterSale = afterSaleService.getAfterSale(id);
if (afterSale == null) { if (afterSale == null) {
return success(null); return success(null);
} }
@ -83,34 +81,11 @@ public class TradeAfterSaleController {
// 查询订单 // 查询订单
TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId()); TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
// 查询订单项 // 查询订单项
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(afterSale.getOrderItemId());
// 拼接数据 // 拼接数据
MemberUserRespDTO user = memberUserApi.getUser(afterSale.getUserId()); MemberUserRespDTO user = memberUserApi.getUser(afterSale.getUserId());
// 获取售后日志 List<AfterSaleLogDO> logs = afterSaleLogService.getAfterSaleLogList(afterSale.getId());
List<TradeAfterSaleLogRespVO> logs = afterSaleLogService.getLog(afterSale.getId()); return success(AfterSaleConvert.INSTANCE.convert(afterSale, order, orderItem, user, logs));
// TODO 方便测试看效果review 后移除
if (logs == null) {
logs = new ArrayList<>();
}
for (int i = 1; i <= 6; i++) {
TradeAfterSaleLogRespVO respVO = new TradeAfterSaleLogRespVO();
respVO.setId((long) i);
respVO.setUserId((long) i);
respVO.setUserType(i % 2 == 0 ? 2 : 1);
// 模拟系统操作
if (i == 2) {
respVO.setUserType(3);
}
respVO.setAfterSaleId(id);
respVO.setOrderId((long) i);
respVO.setOrderItemId((long) i);
respVO.setBeforeStatus((i - 1) * 10);
respVO.setAfterStatus(i * 10);
respVO.setContent("66+6");
respVO.setCreateTime(LocalDateTime.now());
logs.add(respVO);
}
return success(TradeAfterSaleConvert.INSTANCE.convert(afterSale, order, orderItems, user, logs));
} }
@PutMapping("/agree") @PutMapping("/agree")
@ -125,7 +100,7 @@ public class TradeAfterSaleController {
@PutMapping("/disagree") @PutMapping("/disagree")
@Operation(summary = "拒绝售后") @Operation(summary = "拒绝售后")
@PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')") @PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')")
public CommonResult<Boolean> disagreeAfterSale(@RequestBody TradeAfterSaleDisagreeReqVO confirmReqVO) { public CommonResult<Boolean> disagreeAfterSale(@RequestBody AfterSaleDisagreeReqVO confirmReqVO) {
afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO); afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO);
return success(true); return success(true);
} }
@ -143,7 +118,7 @@ public class TradeAfterSaleController {
@Operation(summary = "拒绝收货") @Operation(summary = "拒绝收货")
@Parameter(name = "id", description = "售后编号", required = true, example = "1") @Parameter(name = "id", description = "售后编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('trade:after-sale:receive')") @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')")
public CommonResult<Boolean> refuseAfterSale(TradeAfterSaleRefuseReqVO refuseReqVO) { public CommonResult<Boolean> refuseAfterSale(AfterSaleRefuseReqVO refuseReqVO) {
afterSaleService.refuseAfterSale(getLoginUserId(), refuseReqVO); afterSaleService.refuseAfterSale(getLoginUserId(), refuseReqVO);
return success(true); return success(true);
} }

View File

@ -15,7 +15,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成 * 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/ */
@Data @Data
public class TradeAfterSaleBaseVO { public class AfterSaleBaseVO {
@Schema(description = "售后流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "202211190847450020500077") @Schema(description = "售后流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "202211190847450020500077")
@NotNull(message = "售后流水号不能为空") @NotNull(message = "售后流水号不能为空")
@ -53,7 +53,7 @@ public class TradeAfterSaleBaseVO {
@Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022111917190001") @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022111917190001")
@NotNull(message = "订单流水号不能为空") @NotNull(message = "订单流水号不能为空")
private Long orderNo; private String orderNo;
@Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "572") @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "572")
@NotNull(message = "订单项编号不能为空") @NotNull(message = "订单项编号不能为空")

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.TradeAfterSaleLogRespVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.AfterSaleLogRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO;
@ -12,20 +12,21 @@ import java.util.List;
@Schema(description = "管理后台 - 售后订单的详情 Response VO") @Schema(description = "管理后台 - 售后订单的详情 Response VO")
@Data @Data
public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO { public class AfterSaleDetailRespVO extends AfterSaleBaseVO {
@Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id; private Long id;
/**
* 订单项列表
*/
private List<Item> items;
/** /**
* 订单基本信息 * 订单基本信息
*/ */
private TradeOrderBaseVO order; private TradeOrderBaseVO order;
/**
* 订单项列表
*/
private OrderItem orderItem;
/** /**
* 用户信息 * 用户信息
@ -35,11 +36,11 @@ public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO {
/** /**
* 售后日志 * 售后日志
*/ */
private List<TradeAfterSaleLogRespVO> logs; private List<AfterSaleLogRespVO> logs;
@Schema(description = "管理后台 - 交易订单的详情的订单项目") @Schema(description = "管理后台 - 交易订单的详情的订单项目")
@Data @Data
public static class Item extends TradeOrderItemBaseVO { public static class OrderItem extends TradeOrderItemBaseVO {
/** /**
* 属性数组 * 属性数组

View File

@ -8,7 +8,7 @@ import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 交易售后拒绝 Request VO") @Schema(description = "管理后台 - 交易售后拒绝 Request VO")
@Data @Data
public class TradeAfterSaleDisagreeReqVO { public class AfterSaleDisagreeReqVO {
@Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "售后编号不能为空") @NotNull(message = "售后编号不能为空")

View File

@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -19,21 +19,21 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
public class TradeAfterSalePageReqVO extends PageParam { public class AfterSalePageReqVO extends PageParam {
@Schema(description = "售后流水号", example = "202211190847450020500077") @Schema(description = "售后流水号", example = "202211190847450020500077")
private String no; private String no;
@Schema(description = "售后状态", example = "10") @Schema(description = "售后状态", example = "10")
@InEnum(value = TradeAfterSaleStatusEnum.class, message = "售后状态必须是 {value}") @InEnum(value = AfterSaleStatusEnum.class, message = "售后状态必须是 {value}")
private Integer status; private Integer status;
@Schema(description = "售后类型", example = "20") @Schema(description = "售后类型", example = "20")
@InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}") @InEnum(value = AfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
private Integer type; private Integer type;
@Schema(description = "售后方式", example = "10") @Schema(description = "售后方式", example = "10")
@InEnum(value = TradeAfterSaleWayEnum.class, message = "售后方式必须是 {value}") @InEnum(value = AfterSaleWayEnum.class, message = "售后方式必须是 {value}")
private Integer way; private Integer way;
@Schema(description = "订单编号", example = "18078") @Schema(description = "订单编号", example = "18078")

View File

@ -7,7 +7,7 @@ import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 交易售后拒绝收货 Request VO") @Schema(description = "管理后台 - 交易售后拒绝收货 Request VO")
@Data @Data
public class TradeAfterSaleRefuseReqVO { public class AfterSaleRefuseReqVO {
@Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "售后编号不能为空") @NotNull(message = "售后编号不能为空")

View File

@ -14,7 +14,7 @@ import java.util.List;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
public class TradeAfterSaleRespPageItemVO extends TradeAfterSaleBaseVO { public class AfterSaleRespPageItemVO extends AfterSaleBaseVO {
@Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27630") @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27630")
private Long id; private Long id;

View File

@ -8,7 +8,7 @@ import java.time.LocalDateTime;
@Schema(description = "管理后台 - 交易售后日志 Response VO") @Schema(description = "管理后台 - 交易售后日志 Response VO")
@Data @Data
public class TradeAfterSaleLogRespVO { public class AfterSaleLogRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20669") @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20669")
private Long id; private Long id;
@ -25,14 +25,6 @@ public class TradeAfterSaleLogRespVO {
@NotNull(message = "售后编号不能为空") @NotNull(message = "售后编号不能为空")
private Long afterSaleId; private Long afterSaleId;
@Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25870")
@NotNull(message = "订单编号不能为空")
private Long orderId;
@Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23154")
@NotNull(message = "订单项编号不能为空")
private Long orderItemId;
@Schema(description = "售后状态(之前)", example = "2") @Schema(description = "售后状态(之前)", example = "2")
private Integer beforeStatus; private Integer beforeStatus;

View File

@ -3,15 +3,11 @@ package cn.iocoder.yudao.module.trade.controller.app.aftersale;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleRespVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO;
import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert;
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum; import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations.AfterSaleLog;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.util.AfterSaleLogUtils;
import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -29,23 +25,23 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
@RequestMapping("/trade/after-sale") @RequestMapping("/trade/after-sale")
@Validated @Validated
@Slf4j @Slf4j
public class AppTradeAfterSaleController { public class AppAfterSaleController {
@Resource @Resource
private TradeAfterSaleService afterSaleService; private AfterSaleService afterSaleService;
@GetMapping(value = "/page") @GetMapping(value = "/page")
@Operation(summary = "获得售后分页") @Operation(summary = "获得售后分页")
public CommonResult<PageResult<AppTradeAfterSaleRespVO>> getAfterSalePage(PageParam pageParam) { public CommonResult<PageResult<AppAfterSaleRespVO>> getAfterSalePage(PageParam pageParam) {
return success(TradeAfterSaleConvert.INSTANCE.convertPage02( return success(AfterSaleConvert.INSTANCE.convertPage02(
afterSaleService.getAfterSalePage(getLoginUserId(), pageParam))); afterSaleService.getAfterSalePage(getLoginUserId(), pageParam)));
} }
@GetMapping(value = "/get") @GetMapping(value = "/get")
@Operation(summary = "获得售后订单") @Operation(summary = "获得售后订单")
@Parameter(name = "id", description = "售后编号", required = true, example = "1") @Parameter(name = "id", description = "售后编号", required = true, example = "1")
public CommonResult<AppTradeAfterSaleRespVO> getAfterSale(@RequestParam("id") Long id) { public CommonResult<AppAfterSaleRespVO> getAfterSale(@RequestParam("id") Long id) {
return success(TradeAfterSaleConvert.INSTANCE.convert(afterSaleService.getAfterSale(getLoginUserId(), id))); return success(AfterSaleConvert.INSTANCE.convert(afterSaleService.getAfterSale(getLoginUserId(), id)));
} }
@GetMapping(value = "/get-applying-count") @GetMapping(value = "/get-applying-count")
@ -56,16 +52,13 @@ public class AppTradeAfterSaleController {
@PostMapping(value = "/create") @PostMapping(value = "/create")
@Operation(summary = "申请售后") @Operation(summary = "申请售后")
@AfterSaleLog(id = "#info.data", content = "'申请售后:售后编号['+#info.data+'],订单编号['+#createReqVO.orderItemId+'], '", operateType = AfterSaleOperateTypeEnum.MEMBER_CREATE) public CommonResult<Long> createAfterSale(@RequestBody AppAfterSaleCreateReqVO createReqVO) {
public CommonResult<Long> createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) {
AfterSaleLogUtils.setBeforeStatus(0);
AfterSaleLogUtils.setAfterStatus(TradeAfterSaleStatusEnum.APPLY.getStatus());
return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO));
} }
@PutMapping(value = "/delivery") @PutMapping(value = "/delivery")
@Operation(summary = "退回货物") @Operation(summary = "退回货物")
public CommonResult<Boolean> deliveryAfterSale(@RequestBody AppTradeAfterSaleDeliveryReqVO deliveryReqVO) { public CommonResult<Boolean> deliveryAfterSale(@RequestBody AppAfterSaleDeliveryReqVO deliveryReqVO) {
afterSaleService.deliveryAfterSale(getLoginUserId(), deliveryReqVO); afterSaleService.deliveryAfterSale(getLoginUserId(), deliveryReqVO);
return success(true); return success(true);
} }

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -11,7 +11,7 @@ import java.util.List;
@Schema(description = "用户 App - 交易售后创建 Request VO") @Schema(description = "用户 App - 交易售后创建 Request VO")
@Data @Data
public class AppTradeAfterSaleCreateReqVO { public class AppAfterSaleCreateReqVO {
@Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "订单项编号不能为空") @NotNull(message = "订单项编号不能为空")
@ -19,7 +19,7 @@ public class AppTradeAfterSaleCreateReqVO {
@Schema(description = "售后方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "售后方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "售后方式不能为空") @NotNull(message = "售后方式不能为空")
@InEnum(value = TradeAfterSaleWayEnum.class, message = "售后方式必须是 {value}") @InEnum(value = AfterSaleWayEnum.class, message = "售后方式必须是 {value}")
private Integer way; private Integer way;
@Schema(description = "退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")

View File

@ -7,7 +7,7 @@ import javax.validation.constraints.NotNull;
@Schema(description = "用户 App - 交易售后退回货物 Request VO") @Schema(description = "用户 App - 交易售后退回货物 Request VO")
@Data @Data
public class AppTradeAfterSaleDeliveryReqVO { public class AppAfterSaleDeliveryReqVO {
@Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "售后编号不能为空") @NotNull(message = "售后编号不能为空")

View File

@ -9,7 +9,7 @@ import java.util.List;
@Schema(description = "用户 App - 交易售后 Response VO") @Schema(description = "用户 App - 交易售后 Response VO")
@Data @Data
public class AppTradeAfterSaleRespVO { public class AppAfterSaleRespVO {
@Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id; private Long id;

View File

@ -4,16 +4,16 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDetailRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRespPageItemVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRespPageItemVO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.TradeAfterSaleLogRespVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.AfterSaleLogRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleRespVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleLogDO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 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.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
@ -26,9 +26,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
@Mapper @Mapper
public interface TradeAfterSaleConvert { public interface AfterSaleConvert {
TradeAfterSaleConvert INSTANCE = Mappers.getMapper(TradeAfterSaleConvert.class); AfterSaleConvert INSTANCE = Mappers.getMapper(AfterSaleConvert.class);
@Mappings({ @Mappings({
@Mapping(target = "id", ignore = true), @Mapping(target = "id", ignore = true),
@ -37,7 +37,7 @@ public interface TradeAfterSaleConvert {
@Mapping(target = "creator", ignore = true), @Mapping(target = "creator", ignore = true),
@Mapping(target = "updater", ignore = true), @Mapping(target = "updater", ignore = true),
}) })
TradeAfterSaleDO convert(AppTradeAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem); AfterSaleDO convert(AppAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem);
@Mappings({ @Mappings({
@Mapping(source = "afterSale.orderId", target = "merchantOrderId"), @Mapping(source = "afterSale.orderId", target = "merchantOrderId"),
@ -45,16 +45,16 @@ public interface TradeAfterSaleConvert {
@Mapping(source = "afterSale.applyReason", target = "reason"), @Mapping(source = "afterSale.applyReason", target = "reason"),
@Mapping(source = "afterSale.refundPrice", target = "price") @Mapping(source = "afterSale.refundPrice", target = "price")
}) })
PayRefundCreateReqDTO convert(String userIp, TradeAfterSaleDO afterSale, PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale,
TradeOrderProperties orderProperties); TradeOrderProperties orderProperties);
MemberUserRespVO convert(MemberUserRespDTO bean); MemberUserRespVO convert(MemberUserRespDTO bean);
PageResult<TradeAfterSaleRespPageItemVO> convertPage(PageResult<TradeAfterSaleDO> page); PageResult<AfterSaleRespPageItemVO> convertPage(PageResult<AfterSaleDO> page);
default PageResult<TradeAfterSaleRespPageItemVO> convertPage(PageResult<TradeAfterSaleDO> pageResult, default PageResult<AfterSaleRespPageItemVO> convertPage(PageResult<AfterSaleDO> pageResult,
Map<Long, MemberUserRespDTO> memberUsers) { Map<Long, MemberUserRespDTO> memberUsers) {
PageResult<TradeAfterSaleRespPageItemVO> voPageResult = convertPage(pageResult); PageResult<AfterSaleRespPageItemVO> voPageResult = convertPage(pageResult);
// 处理会员 // 处理会员
voPageResult.getList().forEach(afterSale -> afterSale.setUser( voPageResult.getList().forEach(afterSale -> afterSale.setUser(
convert(memberUsers.get(afterSale.getUserId())))); convert(memberUsers.get(afterSale.getUserId()))));
@ -63,27 +63,26 @@ public interface TradeAfterSaleConvert {
ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean);
AppTradeAfterSaleRespVO convert(TradeAfterSaleDO bean); AppAfterSaleRespVO convert(AfterSaleDO bean);
PageResult<AppTradeAfterSaleRespVO> convertPage02(PageResult<TradeAfterSaleDO> page); PageResult<AppAfterSaleRespVO> convertPage02(PageResult<AfterSaleDO> page);
List<TradeAfterSaleLogRespVO> convertList(List<TradeAfterSaleLogDO> list); default AfterSaleDetailRespVO convert(AfterSaleDO afterSale, TradeOrderDO order, TradeOrderItemDO orderItem,
MemberUserRespDTO user, List<AfterSaleLogDO> logs) {
default TradeAfterSaleDetailRespVO convert(TradeAfterSaleDO afterSale, TradeOrderDO order, List<TradeOrderItemDO> orderItems, AfterSaleDetailRespVO respVO = convert02(afterSale);
MemberUserRespDTO user, List<TradeAfterSaleLogRespVO> logs) {
TradeAfterSaleDetailRespVO respVO = convert(afterSale, orderItems);
// 处理用户信息 // 处理用户信息
respVO.setUser(convert(user)); respVO.setUser(convert(user));
// 处理订单信息 // 处理订单信息
respVO.setOrder(convert(order)); respVO.setOrder(convert(order));
respVO.setOrderItem(convert02(orderItem));
// 处理售后日志 // 处理售后日志
respVO.setLogs(convertList1(logs)); respVO.setLogs(convertList1(logs));
return respVO; return respVO;
} }
List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespVO> list); List<AfterSaleLogRespVO> convertList1(List<AfterSaleLogDO> list);
@Mapping(target = "id", source = "afterSale.id") AfterSaleDetailRespVO convert02(AfterSaleDO bean);
TradeAfterSaleDetailRespVO convert(TradeAfterSaleDO afterSale, List<TradeOrderItemDO> orderItems); AfterSaleDetailRespVO.OrderItem convert02(TradeOrderItemDO bean);
TradeOrderBaseVO convert(TradeOrderDO order); TradeOrderBaseVO convert(TradeOrderDO bean);
} }

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.trade.convert.aftersale;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface AfterSaleLogConvert {
AfterSaleLogConvert INSTANCE = Mappers.getMapper(AfterSaleLogConvert.class);
AfterSaleLogDO convert(AfterSaleLogCreateReqBO bean);
}

View File

@ -10,6 +10,6 @@ public interface TradeOrderLogConvert {
TradeOrderLogConvert INSTANCE = Mappers.getMapper(TradeOrderLogConvert.class); TradeOrderLogConvert INSTANCE = Mappers.getMapper(TradeOrderLogConvert.class);
TradeOrderLogDO convert(TradeOrderLogCreateReqBO createReqBO); TradeOrderLogDO convert(TradeOrderLogCreateReqBO bean);
} }

View File

@ -3,9 +3,9 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.aftersale;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
@ -25,7 +25,7 @@ import java.util.List;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
public class TradeAfterSaleDO extends BaseDO { public class AfterSaleDO extends BaseDO {
/** /**
* 售后编号主键自增 * 售后编号主键自增
@ -40,19 +40,19 @@ public class TradeAfterSaleDO extends BaseDO {
/** /**
* 退款状态 * 退款状态
* *
* 枚举 {@link TradeAfterSaleStatusEnum} * 枚举 {@link AfterSaleStatusEnum}
*/ */
private Integer status; private Integer status;
/** /**
* 售后方式 * 售后方式
* *
* 枚举 {@link TradeAfterSaleWayEnum} * 枚举 {@link AfterSaleWayEnum}
*/ */
private Integer way; private Integer way;
/** /**
* 售后类型 * 售后类型
* *
* 枚举 {@link TradeAfterSaleTypeEnum} * 枚举 {@link AfterSaleTypeEnum}
*/ */
private Integer type; private Integer type;
/** /**

View File

@ -11,8 +11,6 @@ import lombok.*;
/** /**
* 交易售后日志 DO * 交易售后日志 DO
* *
* // TODO 可优化参考淘宝或者有赞1增加 action 表示什么操作2content 记录每个操作的明细
*
* @author 芋道源码 * @author 芋道源码
*/ */
@TableName("trade_after_sale_log") @TableName("trade_after_sale_log")
@ -23,7 +21,7 @@ import lombok.*;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class TradeAfterSaleLogDO extends BaseDO { public class AfterSaleLogDO extends BaseDO {
/** /**
* 编号 * 编号
@ -43,19 +41,28 @@ public class TradeAfterSaleLogDO extends BaseDO {
* 枚举 {@link UserTypeEnum} * 枚举 {@link UserTypeEnum}
*/ */
private Integer userType; private Integer userType;
/** /**
* 售后编号 * 售后编号
* *
* 关联 {@link TradeAfterSaleDO#getId()} * 关联 {@link AfterSaleDO#getId()}
*/ */
private Long afterSaleId; private Long afterSaleId;
// todo @CHENCHEN: 改成 Integer 主要未来改文案不好洗 log 存的字段 /**
* 操作前状态
*/
private Integer beforeStatus;
/**
* 操作后状态
*/
private Integer afterStatus;
/** /**
* 操作类型 * 操作类型
* *
* 枚举 {@link AfterSaleOperateTypeEnum} * 枚举 {@link AfterSaleOperateTypeEnum}
*/ */
private String operateType; private Integer operateType;
/** /**
* 操作明细 * 操作明细
*/ */

View File

@ -2,7 +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.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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.dal.dataobject.aftersale.AfterSaleDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
@ -166,7 +166,7 @@ public class TradeOrderItemDO extends BaseDO {
/** /**
* 售后单编号 * 售后单编号
* *
* 关联 {@link TradeAfterSaleDO#getId()} 字段 * 关联 {@link AfterSaleDO#getId()} 字段
*/ */
private Long afterSaleId; private Long afterSaleId;
/** /**

View File

@ -0,0 +1,16 @@
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.AfterSaleLogDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface AfterSaleLogMapper extends BaseMapperX<AfterSaleLogDO> {
default List<AfterSaleLogDO> selectListByAfterSaleId(Long afterSaleId) {
return selectList(AfterSaleLogDO::getAfterSaleId, afterSaleId);
}
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.trade.dal.mysql.aftersale;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
@Mapper
public interface AfterSaleMapper extends BaseMapperX<AfterSaleDO> {
default PageResult<AfterSaleDO> selectPage(AfterSalePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<AfterSaleDO>()
.likeIfPresent(AfterSaleDO::getNo, reqVO.getNo())
.eqIfPresent(AfterSaleDO::getStatus, reqVO.getStatus())
.eqIfPresent(AfterSaleDO::getType, reqVO.getType())
.eqIfPresent(AfterSaleDO::getWay, reqVO.getWay())
.likeIfPresent(AfterSaleDO::getOrderNo, reqVO.getOrderNo())
.likeIfPresent(AfterSaleDO::getSpuName, reqVO.getSpuName())
.betweenIfPresent(AfterSaleDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(AfterSaleDO::getId));
}
default PageResult<AfterSaleDO> selectPage(Long userId, PageParam pageParam) {
return selectPage(pageParam, new LambdaQueryWrapperX<AfterSaleDO>()
.eqIfPresent(AfterSaleDO::getUserId, userId)
.orderByDesc(AfterSaleDO::getId));
}
default int updateByIdAndStatus(Long id, Integer status, AfterSaleDO update) {
return update(update, new LambdaUpdateWrapper<AfterSaleDO>()
.eq(AfterSaleDO::getId, id).eq(AfterSaleDO::getStatus, status));
}
default AfterSaleDO selectByIdAndUserId(Long id, Long userId) {
return selectOne(AfterSaleDO::getId, id,
AfterSaleDO::getUserId, userId);
}
default Long selectCountByUserIdAndStatus(Long userId, Collection<Integer> statuses) {
return selectCount(new LambdaQueryWrapperX<AfterSaleDO>()
.eq(AfterSaleDO::getUserId, userId)
.in(AfterSaleDO::getStatus, statuses));
}
}

View File

@ -1,9 +0,0 @@
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> {
}

View File

@ -1,51 +0,0 @@
package cn.iocoder.yudao.module.trade.dal.mysql.aftersale;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSalePageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
@Mapper
public interface TradeAfterSaleMapper extends BaseMapperX<TradeAfterSaleDO> {
default PageResult<TradeAfterSaleDO> selectPage(TradeAfterSalePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<TradeAfterSaleDO>()
.likeIfPresent(TradeAfterSaleDO::getNo, reqVO.getNo())
.eqIfPresent(TradeAfterSaleDO::getStatus, reqVO.getStatus())
.eqIfPresent(TradeAfterSaleDO::getType, reqVO.getType())
.eqIfPresent(TradeAfterSaleDO::getWay, reqVO.getWay())
.likeIfPresent(TradeAfterSaleDO::getOrderNo, reqVO.getOrderNo())
.likeIfPresent(TradeAfterSaleDO::getSpuName, reqVO.getSpuName())
.betweenIfPresent(TradeAfterSaleDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(TradeAfterSaleDO::getId));
}
default PageResult<TradeAfterSaleDO> selectPage(Long userId, PageParam pageParam) {
return selectPage(pageParam, new LambdaQueryWrapperX<TradeAfterSaleDO>()
.eqIfPresent(TradeAfterSaleDO::getUserId, userId)
.orderByDesc(TradeAfterSaleDO::getId));
}
default int updateByIdAndStatus(Long id, Integer status, TradeAfterSaleDO update) {
return update(update, new LambdaUpdateWrapper<TradeAfterSaleDO>()
.eq(TradeAfterSaleDO::getId, id).eq(TradeAfterSaleDO::getStatus, status));
}
default TradeAfterSaleDO selectByIdAndUserId(Long id, Long userId) {
return selectOne(TradeAfterSaleDO::getId, id,
TradeAfterSaleDO::getUserId, userId);
}
default Long selectCountByUserIdAndStatus(Long userId, Collection<Integer> statuses) {
return selectCount(new LambdaQueryWrapperX<TradeAfterSaleDO>()
.eq(TradeAfterSaleDO::getUserId, userId)
.in(TradeAfterSaleDO::getStatus, statuses));
}
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.trade.dal.redis;
/**
* 交易 Redis Key 枚举类
*
* @author 芋道源码
*/
public interface RedisKeyConstants {
/**
* 交易序号的缓存
*
* KEY 格式trade_no:{prefix}
* VALUE 数据格式编号自增
*/
String TRADE_NO = "trade_no:";
}

View File

@ -2,10 +2,12 @@ package cn.iocoder.yudao.module.trade.dal.redis.no;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.module.trade.dal.redis.RedisKeyConstants;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
@ -14,9 +16,11 @@ import java.time.LocalDateTime;
* @author HUIHUI * @author HUIHUI
*/ */
@Repository @Repository
public class TradeOrderNoRedisDAO { public class TradeNoRedisDAO {
public static final String TRADE_ORDER_NO_PREFIX = "O"; public static final String TRADE_ORDER_NO_PREFIX = "o";
public static final String AFTER_SALE_NO_PREFIX = "r";
@Resource @Resource
private StringRedisTemplate stringRedisTemplate; private StringRedisTemplate stringRedisTemplate;
@ -28,8 +32,12 @@ public class TradeOrderNoRedisDAO {
* @return 序号 * @return 序号
*/ */
public String generate(String prefix) { public String generate(String prefix) {
// 递增序号
String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN); String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
Long no = stringRedisTemplate.opsForValue().increment(noPrefix); String key = RedisKeyConstants.TRADE_NO + noPrefix;
Long no = stringRedisTemplate.opsForValue().increment(key);
// 设置过期时间
stringRedisTemplate.expire(key, Duration.ofMinutes(1L));
return noPrefix + no; return noPrefix + no;
} }

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.trade.framework.aftersalelog.config; package cn.iocoder.yudao.module.trade.framework.aftersale.config;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.aop.AfterSaleLogAspect; import cn.iocoder.yudao.module.trade.framework.aftersale.core.aop.AfterSaleLogAspect;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations; package cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations;
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum;
import cn.iocoder.yudao.module.trade.framework.aftersale.core.aop.AfterSaleLogAspect;
import java.lang.annotation.*; import java.lang.annotation.*;
@ -11,28 +12,16 @@ import java.lang.annotation.*;
* *
* @author 陈賝 * @author 陈賝
* @since 2023/6/8 17:04 * @since 2023/6/8 17:04
* @see cn.iocoder.yudao.module.trade.framework.aftersalelog.core.aop.AfterSaleLogAspect * @see AfterSaleLogAspect
*/ */
@Target({ElementType.METHOD, ElementType.TYPE}) @Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
public @interface AfterSaleLog { public @interface AfterSaleLog {
/**
* 售后 ID
*/
@Deprecated
String id() default "";
/** /**
* 操作类型 * 操作类型
*/ */
AfterSaleOperateTypeEnum operateType(); AfterSaleOperateTypeEnum operateType();
/**
* 日志内容
*/
@Deprecated
String content() default "";
} }

View File

@ -0,0 +1,133 @@
package cn.iocoder.yudao.module.trade.framework.aftersale.core.aop;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO;
import cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations.AfterSaleLog;
import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService;
import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import javax.annotation.Resource;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static java.util.Collections.emptyMap;
/**
* 售后订单的操作记录的 AOP 切面
*
* @author 陈賝
* @since 2023/6/13 13:54
*/
@Slf4j
@Aspect
public class AfterSaleLogAspect {
/**
* 用户编号
*
* 目前的使用场景支付回调时需要强制设置下用户编号
*/
private static final ThreadLocal<Long> USER_ID = new ThreadLocal<>();
/**
* 用户类型
*/
private static final ThreadLocal<Integer> USER_TYPE = new ThreadLocal<>();
/**
* 订单编号
*/
private static final ThreadLocal<Long> AFTER_SALE_ID = new ThreadLocal<>();
/**
* 操作前的状态
*/
private static final ThreadLocal<Integer> BEFORE_STATUS = new ThreadLocal<>();
/**
* 操作后的状态
*/
private static final ThreadLocal<Integer> AFTER_STATUS = new ThreadLocal<>();
/**
* 拓展参数 Map用于格式化操作内容
*/
private static final ThreadLocal<Map<String, Object>> EXTS = new ThreadLocal<>();
@Resource
private AfterSaleLogService afterSaleLogService;
@AfterReturning(pointcut = "@annotation(afterSaleLog)")
public void doAfterReturning(JoinPoint joinPoint, AfterSaleLog afterSaleLog) {
try {
// 1.1 操作用户
Integer userType = getUserType();
Long userId = getUserId();
// 1.2 售后信息
Long afterSaleId = AFTER_SALE_ID.get();
if (afterSaleId == null) { // 如果未设置只有注解说明不需要记录日志
return;
}
Integer beforeStatus = BEFORE_STATUS.get();
Integer afterStatus = AFTER_STATUS.get();
Map<String, Object> exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap());
String content = StrUtil.format(afterSaleLog.operateType().getContent(), exts);
// 2. 记录日志
AfterSaleLogCreateReqBO createBO = new AfterSaleLogCreateReqBO()
.setUserId(userId).setUserType(userType)
.setAfterSaleId(afterSaleId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus)
.setOperateType(afterSaleLog.operateType().getType()).setContent(content);
afterSaleLogService.createAfterSaleLog(createBO);
} catch (Exception exception) {
log.error("[doAfterReturning][afterSaleLog({}) 日志记录错误]", toJsonString(afterSaleLog), exception);
} finally {
clear();
}
}
/**
* 获得用户类型
*
* 如果没有则约定为 {@link TradeOrderLogDO#getUserType()} 系统
*
* @return 用户类型
*/
private static Integer getUserType() {
return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserType(), TradeOrderLogDO.USER_TYPE_SYSTEM);
}
/**
* 获得用户编号
*
* 如果没有则约定为 {@link TradeOrderLogDO#getUserId()} 系统
*
* @return 用户类型
*/
private static Long getUserId() {
return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM);
}
public static void setAfterSale(Long id, Integer beforeStatus, Integer afterStatus, Map<String, Object> exts) {
AFTER_SALE_ID.set(id);
BEFORE_STATUS.set(beforeStatus);
AFTER_STATUS.set(afterStatus);
EXTS.set(exts);
}
public static void setUserInfo(Long userId, Integer userType) {
USER_ID.set(userId);
USER_TYPE.set(userType);
}
private static void clear() {
USER_ID.remove();
USER_TYPE.remove();
AFTER_SALE_ID.remove();
BEFORE_STATUS.remove();
AFTER_STATUS.remove();
EXTS.remove();
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.util; package cn.iocoder.yudao.module.trade.framework.aftersale.core.utils;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.aop.AfterSaleLogAspect; import cn.iocoder.yudao.module.trade.framework.aftersale.core.aop.AfterSaleLogAspect;
import java.util.Map; import java.util.Map;
@ -13,21 +13,13 @@ import java.util.Map;
*/ */
public class AfterSaleLogUtils { public class AfterSaleLogUtils {
public static void setBeforeStatus(Integer status) {
AfterSaleLogAspect.setBeforeStatus(status);
}
public static void setAfterStatus(Integer status) {
AfterSaleLogAspect.setAfterStatus(status);
}
public static void setAfterSaleInfo(Long id, Integer beforeStatus, Integer afterStatus) { public static void setAfterSaleInfo(Long id, Integer beforeStatus, Integer afterStatus) {
setAfterSaleInfo(id, beforeStatus, afterStatus, null); setAfterSaleInfo(id, beforeStatus, afterStatus, null);
} }
public static void setAfterSaleInfo(Long id, Integer beforeStatus, Integer afterStatus, public static void setAfterSaleInfo(Long id, Integer beforeStatus, Integer afterStatus,
Map<String, Object> exts) { Map<String, Object> exts) {
// TODO 待实现 AfterSaleLogAspect.setAfterSale(id, beforeStatus, afterStatus, exts);
} }
} }

View File

@ -1,122 +0,0 @@
package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.aop;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations.AfterSaleLog;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service.AfterSaleLogService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static java.util.Arrays.asList;
/**
* 记录售后日志的 AOP 切面
*
* @author 陈賝
* @since 2023/6/13 13:54
*/
@Slf4j
@Aspect
public class AfterSaleLogAspect {
@Resource
private AfterSaleLogService afterSaleLogService;
/**
* 售前状态
*/
private static final ThreadLocal<Integer> BEFORE_STATUS = new ThreadLocal<>();
/**
* 售后状态
*/
private static final ThreadLocal<Integer> AFTER_STATUS = new ThreadLocal<>();
/**
* 操作类型
*/
private final static String OPERATE_TYPE = "operateType";
/**
* ID
*/
private final static String ID = "id";
/**
* 操作明细
*/
private final static String CONTENT = "content";
/**
* 切面存入日志
*/
@AfterReturning(pointcut = "@annotation(afterSaleLog)", returning = "info")
public void doAfterReturning(JoinPoint joinPoint, AfterSaleLog afterSaleLog, Object info) {
try {
// 日志对象拼接
Integer userType = WebFrameworkUtils.getLoginUserType();
Long id = WebFrameworkUtils.getLoginUserId();
Map<String, String> formatObj = spelFormat(joinPoint, info);
TradeAfterSaleLogCreateReqDTO dto = new TradeAfterSaleLogCreateReqDTO()
.setUserId(id)
.setUserType(userType)
.setAfterSaleId(MapUtil.getLong(formatObj, ID))
.setOperateType(MapUtil.getStr(formatObj, OPERATE_TYPE))
.setBeforeStatus(BEFORE_STATUS.get())
.setAfterStatus(AFTER_STATUS.get())
.setContent(MapUtil.getStr(formatObj, CONTENT));
// 异步存入数据库
afterSaleLogService.createLog(dto);
} catch (Exception exception) {
log.error("[doAfterReturning][afterSaleLog({}) 日志记录错误]", toJsonString(afterSaleLog), exception);
}finally {
clearThreadLocal();
}
}
/**
* 获取描述信息
*/
public static Map<String, String> spelFormat(JoinPoint joinPoint, Object info) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
AfterSaleLog afterSaleLogPoint = signature.getMethod().getAnnotation(AfterSaleLog.class);
HashMap<String, String> result = Maps.newHashMapWithExpectedSize(2);
Map<String, Object> spelMap = SpringExpressionUtils.parseExpression(joinPoint, info,
asList(afterSaleLogPoint.id(), afterSaleLogPoint.content()));
// TODO @chenchen是不是抽成 3 个方法好点毕竟 map 太抽象了
// 售后ID
String id = MapUtil.getStr(spelMap, afterSaleLogPoint.id());
result.put(ID, id);
// 操作类型
String operateType = afterSaleLogPoint.operateType().getContent();
result.put(OPERATE_TYPE, operateType);
// 日志内容
String content = MapUtil.getStr(spelMap, afterSaleLogPoint.content());
if (ObjectUtil.isNotNull(afterSaleLogPoint.operateType())) {
content += operateType;
}
result.put(CONTENT, content);
return result;
}
public static void setBeforeStatus(Integer beforestatus) {
BEFORE_STATUS.set(beforestatus);
}
public static void setAfterStatus(Integer afterStatus) {
AFTER_STATUS.set(afterStatus);
}
private static void clearThreadLocal() {
AFTER_STATUS.remove();
BEFORE_STATUS.remove();
}
}

View File

@ -1,54 +0,0 @@
package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 售后日志的创建 Request DTO
*
* @author 陈賝
* @since 2023/6/19 09:54
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TradeAfterSaleLogCreateReqDTO {
/**
* 编号
*/
private Long id;
/**
* 用户编号
*
* 关联 1AdminUserDO id 字段
* 关联 2MemberUserDO id 字段
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 售后编号
*/
private Long afterSaleId;
/**
* 操作类型
*/
private String operateType;
/**
* 操作明细
*/
private String content;
/**
* 售前状态
*/
private Integer beforeStatus;
/**
* 售后状态
*/
private Integer afterStatus;
}

View File

@ -1,34 +0,0 @@
package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.TradeAfterSaleLogRespVO;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO;
import java.util.List;
/**
* 交易售后日志 Service 接口
*
* @author 陈賝
* @since 2023/6/12 14:18
*/
public interface AfterSaleLogService {
/**
* 创建售后日志
*
* @param logDTO 日志记录
* @author 陈賝
* @since 2023/6/12 14:18
*/
void createLog(TradeAfterSaleLogCreateReqDTO logDTO);
/**
* 获取售后日志
*
* @param afterSaleId 售后编号
* @return 售后日志
*/
List<TradeAfterSaleLogRespVO> getLog(Long afterSaleId);
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.trade.framework.order.core.annotations; package cn.iocoder.yudao.module.trade.framework.order.core.annotations;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
import cn.iocoder.yudao.module.trade.framework.order.core.aop.TradeOrderLogAspect;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -15,6 +16,7 @@ import static java.lang.annotation.ElementType.METHOD;
* *
* @author 陈賝 * @author 陈賝
* @since 2023/7/6 15:37 * @since 2023/7/6 15:37
* @see TradeOrderLogAspect
*/ */
@Target({METHOD, ANNOTATION_TYPE}) @Target({METHOD, ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

View File

@ -73,7 +73,7 @@ public class TradeOrderLogAspect {
Long userId = getUserId(); Long userId = getUserId();
// 1.2 订单信息 // 1.2 订单信息
Long orderId = ORDER_ID.get(); Long orderId = ORDER_ID.get();
if (orderId == null) { // 如果未设置只有注解说明不需要记录订单日志 if (orderId == null) { // 如果未设置只有注解说明不需要记录日志
return; return;
} }
Integer beforeStatus = BEFORE_STATUS.get(); Integer beforeStatus = BEFORE_STATUS.get();
@ -81,7 +81,7 @@ public class TradeOrderLogAspect {
Map<String, Object> exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap()); Map<String, Object> exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap());
String content = StrUtil.format(orderLog.operateType().getContent(), exts); String content = StrUtil.format(orderLog.operateType().getContent(), exts);
// 2.1 记录日志 // 2. 记录日志
TradeOrderLogCreateReqBO createBO = new TradeOrderLogCreateReqBO() TradeOrderLogCreateReqBO createBO = new TradeOrderLogCreateReqBO()
.setUserId(userId).setUserType(userType) .setUserId(userId).setUserType(userType)
.setOrderId(orderId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus) .setOrderId(orderId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus)

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.trade.service.aftersale;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO;
import java.util.List;
/**
* 交易售后日志 Service 接口
*
* @author 陈賝
* @since 2023/6/12 14:18
*/
public interface AfterSaleLogService {
/**
* 创建售后日志
*
* @param createReqBO 日志记录
* @author 陈賝
* @since 2023/6/12 14:18
*/
void createAfterSaleLog(AfterSaleLogCreateReqBO createReqBO);
/**
* 获取售后日志
*
* @param afterSaleId 售后编号
* @return 售后日志
*/
List<AfterSaleLogDO> getAfterSaleLogList(Long afterSaleId);
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.trade.service.aftersale;
import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleLogConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleLogMapper;
import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
/**
* 交易售后日志 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class AfterSaleLogServiceImpl implements AfterSaleLogService {
@Resource
private AfterSaleLogMapper afterSaleLogMapper;
@Override
public void createAfterSaleLog(AfterSaleLogCreateReqBO createReqBO) {
AfterSaleLogDO afterSaleLog = AfterSaleLogConvert.INSTANCE.convert(createReqBO);
afterSaleLogMapper.insert(afterSaleLog);
}
@Override
public List<AfterSaleLogDO> getAfterSaleLogList(Long afterSaleId) {
return afterSaleLogMapper.selectListByAfterSaleId(afterSaleId);
}
}

View File

@ -2,19 +2,19 @@ package cn.iocoder.yudao.module.trade.service.aftersale;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSalePageReqVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
/** /**
* 售后订单 Service 接口 * 售后订单 Service 接口
* *
* @author 芋道源码 * @author 芋道源码
*/ */
public interface TradeAfterSaleService { public interface AfterSaleService {
/** /**
* 管理员获得售后订单分页 * 管理员获得售后订单分页
@ -22,7 +22,7 @@ public interface TradeAfterSaleService {
* @param pageReqVO 分页查询 * @param pageReqVO 分页查询
* @return 售后订单分页 * @return 售后订单分页
*/ */
PageResult<TradeAfterSaleDO> getAfterSalePage(TradeAfterSalePageReqVO pageReqVO); PageResult<AfterSaleDO> getAfterSalePage(AfterSalePageReqVO pageReqVO);
/** /**
* 会员获得售后订单分页 * 会员获得售后订单分页
@ -31,7 +31,7 @@ public interface TradeAfterSaleService {
* @param pageParam 分页参数 * @param pageParam 分页参数
* @return 售后订单分页 * @return 售后订单分页
*/ */
PageResult<TradeAfterSaleDO> getAfterSalePage(Long userId, PageParam pageParam); PageResult<AfterSaleDO> getAfterSalePage(Long userId, PageParam pageParam);
/** /**
* 会员获得售后单 * 会员获得售后单
@ -40,7 +40,7 @@ public interface TradeAfterSaleService {
* @param id 售后编号 * @param id 售后编号
* @return 售后订单 * @return 售后订单
*/ */
TradeAfterSaleDO getAfterSale(Long userId, Long id); AfterSaleDO getAfterSale(Long userId, Long id);
/** /**
* 管理员获得售后单 * 管理员获得售后单
@ -48,7 +48,7 @@ public interface TradeAfterSaleService {
* @param id 售后编号 * @param id 售后编号
* @return 售后订单 * @return 售后订单
*/ */
TradeAfterSaleDO getAfterSale(Long id); AfterSaleDO getAfterSale(Long id);
/** /**
* 会员创建售后订单 * 会员创建售后订单
@ -57,7 +57,7 @@ public interface TradeAfterSaleService {
* @param createReqVO 创建 Request 信息 * @param createReqVO 创建 Request 信息
* @return 售后编号 * @return 售后编号
*/ */
Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO); Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO);
/** /**
* 管理员同意售后订单 * 管理员同意售后订单
@ -73,7 +73,7 @@ public interface TradeAfterSaleService {
* @param userId 管理员用户编号 * @param userId 管理员用户编号
* @param auditReqVO 审批 Request 信息 * @param auditReqVO 审批 Request 信息
*/ */
void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO); void disagreeAfterSale(Long userId, AfterSaleDisagreeReqVO auditReqVO);
/** /**
* 会员退回货物 * 会员退回货物
@ -81,7 +81,7 @@ public interface TradeAfterSaleService {
* @param userId 会员用户编号 * @param userId 会员用户编号
* @param deliveryReqVO 退货 Request 信息 * @param deliveryReqVO 退货 Request 信息
*/ */
void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO); void deliveryAfterSale(Long userId, AppAfterSaleDeliveryReqVO deliveryReqVO);
/** /**
* 管理员确认收货 * 管理员确认收货
@ -97,7 +97,7 @@ public interface TradeAfterSaleService {
* @param userId 管理员用户编号 * @param userId 管理员用户编号
* @param refuseReqVO 拒绝收货 Request 信息 * @param refuseReqVO 拒绝收货 Request 信息
*/ */
void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO refuseReqVO); void refuseAfterSale(Long userId, AfterSaleRefuseReqVO refuseReqVO);
/** /**
* 管理员确认退款 * 管理员确认退款
@ -119,7 +119,7 @@ public interface TradeAfterSaleService {
/** /**
* 会员获得正在进行中的售后订单数量 * 会员获得正在进行中的售后订单数量
* *
* @param userId * @param userId 用户编号
* @return 数量 * @return 数量
*/ */
Long getApplyingAfterSaleCount(Long userId); Long getApplyingAfterSaleCount(Long userId);

View File

@ -2,42 +2,36 @@ package cn.iocoder.yudao.module.trade.service.aftersale;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSalePageReqVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.TradeAfterSaleLogRespVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO; import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert;
import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
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.delivery.DeliveryExpressDO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 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.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleLogMapper; import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper; import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations.AfterSaleLog; import cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations.AfterSaleLog;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO; import cn.iocoder.yudao.module.trade.framework.aftersale.core.utils.AfterSaleLogUtils;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service.AfterSaleLogService;
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.util.AfterSaleLogUtils;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronization;
@ -46,10 +40,8 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
/** /**
@ -60,7 +52,7 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@Slf4j @Slf4j
@Service @Service
@Validated @Validated
public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSaleLogService { public class AfterSaleServiceImpl implements AfterSaleService {
@Resource @Resource
private TradeOrderUpdateService tradeOrderUpdateService; private TradeOrderUpdateService tradeOrderUpdateService;
@ -70,9 +62,9 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
private DeliveryExpressService deliveryExpressService; private DeliveryExpressService deliveryExpressService;
@Resource @Resource
private TradeAfterSaleMapper tradeAfterSaleMapper; private AfterSaleMapper tradeAfterSaleMapper;
@Resource @Resource
private TradeAfterSaleLogMapper tradeAfterSaleLogMapper; private TradeNoRedisDAO tradeNoRedisDAO;
@Resource @Resource
private PayRefundApi payRefundApi; private PayRefundApi payRefundApi;
@ -81,34 +73,34 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
private TradeOrderProperties tradeOrderProperties; private TradeOrderProperties tradeOrderProperties;
@Override @Override
public PageResult<TradeAfterSaleDO> getAfterSalePage(TradeAfterSalePageReqVO pageReqVO) { public PageResult<AfterSaleDO> getAfterSalePage(AfterSalePageReqVO pageReqVO) {
return tradeAfterSaleMapper.selectPage(pageReqVO); return tradeAfterSaleMapper.selectPage(pageReqVO);
} }
@Override @Override
public PageResult<TradeAfterSaleDO> getAfterSalePage(Long userId, PageParam pageParam) { public PageResult<AfterSaleDO> getAfterSalePage(Long userId, PageParam pageParam) {
return tradeAfterSaleMapper.selectPage(userId, pageParam); return tradeAfterSaleMapper.selectPage(userId, pageParam);
} }
@Override @Override
public TradeAfterSaleDO getAfterSale(Long userId, Long id) { public AfterSaleDO getAfterSale(Long userId, Long id) {
return tradeAfterSaleMapper.selectByIdAndUserId(id, userId); return tradeAfterSaleMapper.selectByIdAndUserId(id, userId);
} }
@Override @Override
public TradeAfterSaleDO getAfterSale(Long id) { public AfterSaleDO getAfterSale(Long id) {
return tradeAfterSaleMapper.selectById(id); return tradeAfterSaleMapper.selectById(id);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CREATE) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CREATE)
public Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { public Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO) {
// 第一步前置校验 // 第一步前置校验
TradeOrderItemDO tradeOrderItem = validateOrderItemApplicable(userId, createReqVO); TradeOrderItemDO tradeOrderItem = validateOrderItemApplicable(userId, createReqVO);
// 第二步存储售后订单 // 第二步存储售后订单
TradeAfterSaleDO afterSale = createAfterSale(createReqVO, tradeOrderItem); AfterSaleDO afterSale = createAfterSale(createReqVO, tradeOrderItem);
return afterSale.getId(); return afterSale.getId();
} }
@ -119,7 +111,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
* @param createReqVO 售后创建信息 * @param createReqVO 售后创建信息
* @return 交易订单项 * @return 交易订单项
*/ */
private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppAfterSaleCreateReqVO createReqVO) {
// 校验订单项存在 // 校验订单项存在
TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(userId, createReqVO.getOrderItemId()); TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(userId, createReqVO.getOrderItemId());
if (orderItem == null) { if (orderItem == null) {
@ -149,24 +141,24 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID); throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID);
} }
// 如果是退货退款的情况需要额外校验是否发货 // 如果是退货退款的情况需要额外校验是否发货
if (createReqVO.getWay().equals(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()) if (createReqVO.getWay().equals(AfterSaleWayEnum.RETURN_AND_REFUND.getWay())
&& !TradeOrderStatusEnum.haveDelivered(order.getStatus())) { && !TradeOrderStatusEnum.haveDelivered(order.getStatus())) {
throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED); throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED);
} }
return orderItem; return orderItem;
} }
private TradeAfterSaleDO createAfterSale(AppTradeAfterSaleCreateReqVO createReqVO, private AfterSaleDO createAfterSale(AppAfterSaleCreateReqVO createReqVO,
TradeOrderItemDO orderItem) { TradeOrderItemDO orderItem) {
// 创建售后单 // 创建售后单
TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, orderItem); AfterSaleDO afterSale = AfterSaleConvert.INSTANCE.convert(createReqVO, orderItem);
afterSale.setNo(RandomUtil.randomString(10)); // TODO 芋艿优化 no 生成逻辑 afterSale.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.AFTER_SALE_NO_PREFIX));
afterSale.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus()); afterSale.setStatus(AfterSaleStatusEnum.APPLY.getStatus());
// 标记是售中还是售后 // 标记是售中还是售后
TradeOrderDO order = tradeOrderQueryService.getOrder(orderItem.getUserId(), orderItem.getOrderId()); TradeOrderDO order = tradeOrderQueryService.getOrder(orderItem.getUserId(), orderItem.getOrderId());
afterSale.setOrderNo(order.getNo()); // 记录 orderNo 订单流水方便后续检索 afterSale.setOrderNo(order.getNo()); // 记录 orderNo 订单流水方便后续检索
afterSale.setType(TradeOrderStatusEnum.isCompleted(order.getStatus()) afterSale.setType(TradeOrderStatusEnum.isCompleted(order.getStatus())
? TradeAfterSaleTypeEnum.AFTER_SALE.getType() : TradeAfterSaleTypeEnum.IN_SALE.getType()); ? AfterSaleTypeEnum.AFTER_SALE.getType() : AfterSaleTypeEnum.IN_SALE.getType());
tradeAfterSaleMapper.insert(afterSale); tradeAfterSaleMapper.insert(afterSale);
// 更新交易订单项的售后状态 // 更新交易订单项的售后状态
@ -174,7 +166,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
// 记录售后日志 // 记录售后日志
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), null, AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), null,
TradeAfterSaleStatusEnum.APPLY.getStatus()); AfterSaleStatusEnum.APPLY.getStatus());
// TODO 发送售后消息 // TODO 发送售后消息
return afterSale; return afterSale;
@ -185,14 +177,14 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_APPLY) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_APPLY)
public void agreeAfterSale(Long userId, Long id) { public void agreeAfterSale(Long userId, Long id) {
// 校验售后单存在并状态未审批 // 校验售后单存在并状态未审批
TradeAfterSaleDO afterSale = validateAfterSaleAuditable(id); AfterSaleDO afterSale = validateAfterSaleAuditable(id);
// 更新售后单的状态 // 更新售后单的状态
// 情况一退款标记为 WAIT_REFUND 状态后续等退款发起成功后在标记为 COMPLETE 状态 // 情况一退款标记为 WAIT_REFUND 状态后续等退款发起成功后在标记为 COMPLETE 状态
// 情况二退货退款需要等用户退货后才能发起退款 // 情况二退货退款需要等用户退货后才能发起退款
Integer newStatus = afterSale.getWay().equals(TradeAfterSaleWayEnum.REFUND.getWay()) ? Integer newStatus = afterSale.getWay().equals(AfterSaleWayEnum.REFUND.getWay()) ?
TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(); AfterSaleStatusEnum.WAIT_REFUND.getStatus() : AfterSaleStatusEnum.SELLER_AGREE.getStatus();
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.APPLY.getStatus(), new AfterSaleDO()
.setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())); .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()));
// 记录售后日志 // 记录售后日志
@ -204,13 +196,13 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_APPLY) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_APPLY)
public void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO) { public void disagreeAfterSale(Long userId, AfterSaleDisagreeReqVO auditReqVO) {
// 校验售后单存在并状态未审批 // 校验售后单存在并状态未审批
TradeAfterSaleDO afterSale = validateAfterSaleAuditable(auditReqVO.getId()); AfterSaleDO afterSale = validateAfterSaleAuditable(auditReqVO.getId());
// 更新售后单的状态 // 更新售后单的状态
Integer newStatus = TradeAfterSaleStatusEnum.SELLER_DISAGREE.getStatus(); Integer newStatus = AfterSaleStatusEnum.SELLER_DISAGREE.getStatus();
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.APPLY.getStatus(), new AfterSaleDO()
.setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()) .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())
.setAuditReason(auditReqVO.getAuditReason())); .setAuditReason(auditReqVO.getAuditReason()));
@ -229,18 +221,18 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
* @param id 售后编号 * @param id 售后编号
* @return 售后单 * @return 售后单
*/ */
private TradeAfterSaleDO validateAfterSaleAuditable(Long id) { private AfterSaleDO validateAfterSaleAuditable(Long id) {
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
if (afterSale == null) { if (afterSale == null) {
throw exception(AFTER_SALE_NOT_FOUND); throw exception(AFTER_SALE_NOT_FOUND);
} }
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) { if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus())) {
throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY); throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY);
} }
return afterSale; return afterSale;
} }
private void updateAfterSaleStatus(Long id, Integer status, TradeAfterSaleDO updateObj) { private void updateAfterSaleStatus(Long id, Integer status, AfterSaleDO updateObj) {
int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj); int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj);
if (updateCount == 0) { if (updateCount == 0) {
throw exception(AFTER_SALE_UPDATE_STATUS_FAIL); throw exception(AFTER_SALE_UPDATE_STATUS_FAIL);
@ -250,26 +242,26 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_DELIVERY) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_DELIVERY)
public void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO) { public void deliveryAfterSale(Long userId, AppAfterSaleDeliveryReqVO deliveryReqVO) {
// 校验售后单存在并状态未退货 // 校验售后单存在并状态未退货
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId()); AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId());
if (afterSale == null) { if (afterSale == null) {
throw exception(AFTER_SALE_NOT_FOUND); throw exception(AFTER_SALE_NOT_FOUND);
} }
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus())) { if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.SELLER_AGREE.getStatus())) {
throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE); throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE);
} }
DeliveryExpressDO express = deliveryExpressService.validateDeliveryExpress(deliveryReqVO.getLogisticsId()); DeliveryExpressDO express = deliveryExpressService.validateDeliveryExpress(deliveryReqVO.getLogisticsId());
// 更新售后单的物流信息 // 更新售后单的物流信息
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(), new TradeAfterSaleDO() updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.SELLER_AGREE.getStatus(), new AfterSaleDO()
.setStatus(TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus()) .setStatus(AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())
.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo()) .setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo())
.setDeliveryTime(LocalDateTime.now())); .setDeliveryTime(LocalDateTime.now()));
// 记录售后日志 // 记录售后日志
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(),
MapUtil.<String, Object>builder().put("expressName", express.getName()) MapUtil.<String, Object>builder().put("expressName", express.getName())
.put("logisticsNo", deliveryReqVO.getLogisticsNo()).build()); .put("logisticsNo", deliveryReqVO.getLogisticsNo()).build());
@ -281,15 +273,15 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_RECEIVE) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_RECEIVE)
public void receiveAfterSale(Long userId, Long id) { public void receiveAfterSale(Long userId, Long id) {
// 校验售后单存在并状态为已退货 // 校验售后单存在并状态为已退货
TradeAfterSaleDO afterSale = validateAfterSaleReceivable(id); AfterSaleDO afterSale = validateAfterSaleReceivable(id);
// 更新售后单的状态 // 更新售后单的状态
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO() updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO()
.setStatus(TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now())); .setStatus(AfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now()));
// 记录售后日志 // 记录售后日志
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus()); AfterSaleStatusEnum.WAIT_REFUND.getStatus());
// TODO 发送售后消息 // TODO 发送售后消息
} }
@ -297,24 +289,24 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_RECEIVE) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_RECEIVE)
public void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO refuseReqVO) { public void refuseAfterSale(Long userId, AfterSaleRefuseReqVO refuseReqVO) {
// 校验售后单存在并状态为已退货 // 校验售后单存在并状态为已退货
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(refuseReqVO.getId()); AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(refuseReqVO.getId());
if (afterSale == null) { if (afterSale == null) {
throw exception(AFTER_SALE_NOT_FOUND); throw exception(AFTER_SALE_NOT_FOUND);
} }
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY); throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
} }
// 更新售后单的状态 // 更新售后单的状态
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO() updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO()
.setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now()) .setStatus(AfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now())
.setReceiveReason(refuseReqVO.getRefuseMemo())); .setReceiveReason(refuseReqVO.getRefuseMemo()));
// 记录售后日志 // 记录售后日志
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus(), AfterSaleStatusEnum.SELLER_REFUSE.getStatus(),
MapUtil.of("reason", refuseReqVO.getRefuseMemo())); MapUtil.of("reason", refuseReqVO.getRefuseMemo()));
// TODO 发送售后消息 // TODO 发送售后消息
@ -329,12 +321,12 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
* @param id 售后编号 * @param id 售后编号
* @return 售后单 * @return 售后单
*/ */
private TradeAfterSaleDO validateAfterSaleReceivable(Long id) { private AfterSaleDO validateAfterSaleReceivable(Long id) {
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
if (afterSale == null) { if (afterSale == null) {
throw exception(AFTER_SALE_NOT_FOUND); throw exception(AFTER_SALE_NOT_FOUND);
} }
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY); throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
} }
return afterSale; return afterSale;
@ -345,11 +337,11 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_REFUND) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_REFUND)
public void refundAfterSale(Long userId, String userIp, Long id) { public void refundAfterSale(Long userId, String userIp, Long id) {
// 校验售后单的状态并状态待退款 // 校验售后单的状态并状态待退款
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
if (afterSale == null) { if (afterSale == null) {
throw exception(AFTER_SALE_NOT_FOUND); throw exception(AFTER_SALE_NOT_FOUND);
} }
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus())) { if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.WAIT_REFUND.getStatus())) {
throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND); throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND);
} }
@ -357,12 +349,12 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
createPayRefund(userIp, afterSale); createPayRefund(userIp, afterSale);
// 更新售后单的状态为已完成 // 更新售后单的状态为已完成
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(), new TradeAfterSaleDO() updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), new AfterSaleDO()
.setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now())); .setStatus(AfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now()));
// 记录售后日志 // 记录售后日志
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
TradeAfterSaleStatusEnum.COMPLETE.getStatus()); AfterSaleStatusEnum.COMPLETE.getStatus());
// TODO 发送售后消息 // TODO 发送售后消息
@ -370,16 +362,16 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice()); tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice());
} }
private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) { private void createPayRefund(String userIp, AfterSaleDO afterSale) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override @Override
public void afterCommit() { public void afterCommit() {
// 创建退款单 // 创建退款单
PayRefundCreateReqDTO createReqDTO = TradeAfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties); PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties);
Long payRefundId = payRefundApi.createRefund(createReqDTO); Long payRefundId = payRefundApi.createRefund(createReqDTO);
// 更新售后单的退款单号 // 更新售后单的退款单号
tradeAfterSaleMapper.updateById(new TradeAfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));
} }
}); });
} }
@ -389,23 +381,23 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CANCEL) @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CANCEL)
public void cancelAfterSale(Long userId, Long id) { public void cancelAfterSale(Long userId, Long id) {
// 校验售后单的状态并状态待退款 // 校验售后单的状态并状态待退款
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
if (afterSale == null) { if (afterSale == null) {
throw exception(AFTER_SALE_NOT_FOUND); throw exception(AFTER_SALE_NOT_FOUND);
} }
if (!ObjectUtils.equalsAny(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus(), if (!ObjectUtils.equalsAny(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus(),
TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(), AfterSaleStatusEnum.SELLER_AGREE.getStatus(),
TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
throw exception(AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY); throw exception(AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY);
} }
// 更新售后单的状态为已取消 // 更新售后单的状态为已取消
updateAfterSaleStatus(afterSale.getId(), afterSale.getStatus(), new TradeAfterSaleDO() updateAfterSaleStatus(afterSale.getId(), afterSale.getStatus(), new AfterSaleDO()
.setStatus(TradeAfterSaleStatusEnum.BUYER_CANCEL.getStatus())); .setStatus(AfterSaleStatusEnum.BUYER_CANCEL.getStatus()));
// 记录售后日志 // 记录售后日志
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
TradeAfterSaleStatusEnum.BUYER_CANCEL.getStatus()); AfterSaleStatusEnum.BUYER_CANCEL.getStatus());
// TODO 发送售后消息 // TODO 发送售后消息
@ -415,52 +407,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
@Override @Override
public Long getApplyingAfterSaleCount(Long userId) { public Long getApplyingAfterSaleCount(Long userId) {
return tradeAfterSaleMapper.selectCountByUserIdAndStatus(userId, TradeAfterSaleStatusEnum.APPLYING_STATUSES); return tradeAfterSaleMapper.selectCountByUserIdAndStatus(userId, AfterSaleStatusEnum.APPLYING_STATUSES);
}
@Deprecated
private void createAfterSaleLog(Long userId, Integer userType, TradeAfterSaleDO afterSale,
Integer beforeStatus, Integer afterStatus) {
TradeAfterSaleLogCreateReqDTO logDTO = new TradeAfterSaleLogCreateReqDTO()
.setUserId(userId)
.setUserType(userType)
.setAfterSaleId(afterSale.getId())
.setOperateType(afterStatus.toString());
// TODO 废弃待删除
this.createLog(logDTO);
}
// TODO @CHENCHEN这个注释写在接口就好了补充重复写哈@date 应该是 @since
/**
* 日志记录
*
* @param logDTO 日志记录
* @author 陈賝
* @date 2023/6/12 14:18
*/
@Override
@Async
public void createLog(TradeAfterSaleLogCreateReqDTO logDTO) {
try {
TradeAfterSaleLogDO afterSaleLog = new TradeAfterSaleLogDO()
.setUserId(logDTO.getUserId())
.setUserType(logDTO.getUserType())
.setAfterSaleId(logDTO.getAfterSaleId())
.setOperateType(logDTO.getOperateType())
.setContent(logDTO.getContent());
tradeAfterSaleLogMapper.insert(afterSaleLog);
// TODO @CHENCHEN代码排版哈空格要正确
}catch (Exception exception){
log.error("[createLog][request({}) 日志记录错误]", toJsonString(logDTO), exception);
}
}
// TODO @puhui999应该返回 do
@Override
public List<TradeAfterSaleLogRespVO> getLog(Long afterSaleId) {
// TODO 不熟悉流程先这么滴
List<TradeAfterSaleLogDO> saleLogDOs = tradeAfterSaleLogMapper.selectList(TradeAfterSaleLogDO::getAfterSaleId, afterSaleId);
return TradeAfterSaleConvert.INSTANCE.convertList(saleLogDOs);
} }
} }

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.trade.service.aftersale.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 售后日志的创建 Request BO
*
* @author 陈賝
* @since 2023/6/19 09:54
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AfterSaleLogCreateReqBO {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 售后编号
*/
@NotNull(message = "售后编号不能为空")
private Long afterSaleId;
/**
* 操作前状态
*/
private Integer beforeStatus;
/**
* 操作后状态
*/
@NotNull(message = "操作后的状态不能为空")
private Integer afterStatus;
/**
* 操作类型
*/
@NotNull(message = "操作类型不能为空")
private Integer operateType;
/**
* 操作明细
*/
@NotEmpty(message = "操作明细不能为空")
private String content;
}

View File

@ -94,12 +94,12 @@ public interface TradeOrderQueryService {
TradeOrderItemDO getOrderItem(Long userId, Long itemId); TradeOrderItemDO getOrderItem(Long userId, Long itemId);
/** /**
* 根据交易订单项编号数组查询交易订单项 * 获得交易订单项
* *
* @param ids 交易订单项编号数组 * @param id 交易订单项编号 itemId
* @return 交易订单项数组 * @return 交易订单项
*/ */
List<TradeOrderItemDO> getOrderItemList(Collection<Long> ids); TradeOrderItemDO getOrderItem(Long id);
/** /**
* 根据交易订单编号查询交易订单项 * 根据交易订单编号查询交易订单项
@ -119,5 +119,4 @@ public interface TradeOrderQueryService {
*/ */
List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds); List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
} }

View File

@ -156,8 +156,8 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
} }
@Override @Override
public List<TradeOrderItemDO> getOrderItemList(Collection<Long> ids) { public TradeOrderItemDO getOrderItem(Long id) {
return tradeOrderItemMapper.selectBatchIds(ids); return tradeOrderItemMapper.selectById(id);
} }
@Override @Override

View File

@ -47,7 +47,7 @@ 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.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO; import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.*; import cn.iocoder.yudao.module.trade.enums.order.*;
@ -97,7 +97,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Resource @Resource
private TradeOrderItemMapper tradeOrderItemMapper; private TradeOrderItemMapper tradeOrderItemMapper;
@Resource @Resource
private TradeOrderNoRedisDAO orderNoRedisDAO; private TradeNoRedisDAO tradeNoRedisDAO;
@Resource @Resource
private List<TradeOrderHandler> tradeOrderHandlers; private List<TradeOrderHandler> tradeOrderHandlers;
@ -215,7 +215,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
TradePriceCalculateRespBO calculateRespBO) { TradePriceCalculateRespBO calculateRespBO) {
TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO); TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO);
order.setType(calculateRespBO.getType()); order.setType(calculateRespBO.getType());
order.setNo(orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX)); order.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX));
order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));

View File

@ -28,7 +28,7 @@ public class TradeOrderLogCreateReqBO {
/** /**
* 订单编号 * 订单编号
*/ */
@NotNull(message = "订单编号") @NotNull(message = "订单编号不能为空")
private Long orderId; private Long orderId;
/** /**
* 操作前状态 * 操作前状态

View File

@ -4,17 +4,17 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; 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.admin.aftersale.vo.AfterSalePageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleLogDO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; 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.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleLogMapper; import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleLogMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper; import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleMapper;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 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.framework.order.config.TradeOrderProperties;
@ -37,20 +37,20 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
/** /**
* {@link TradeAfterSaleService} 的单元测试 * {@link AfterSaleService} 的单元测试
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@Import(TradeAfterSaleServiceImpl.class) @Import(AfterSaleServiceImpl.class)
public class TradeAfterSaleServiceTest extends BaseDbUnitTest { public class AfterSaleServiceTest extends BaseDbUnitTest {
@Resource @Resource
private TradeAfterSaleServiceImpl tradeAfterSaleService; private AfterSaleServiceImpl tradeAfterSaleService;
@Resource @Resource
private TradeAfterSaleMapper tradeAfterSaleMapper; private AfterSaleMapper tradeAfterSaleMapper;
@Resource @Resource
private TradeAfterSaleLogMapper tradeAfterSaleLogMapper; private AfterSaleLogMapper tradeAfterSaleLogMapper;
@MockBean @MockBean
private TradeOrderUpdateService tradeOrderUpdateService; private TradeOrderUpdateService tradeOrderUpdateService;
@ -67,8 +67,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
public void testCreateAfterSale() { public void testCreateAfterSale() {
// 准备参数 // 准备参数
Long userId = 1024L; Long userId = 1024L;
AppTradeAfterSaleCreateReqVO createReqVO = new AppTradeAfterSaleCreateReqVO() AppAfterSaleCreateReqVO createReqVO = new AppAfterSaleCreateReqVO()
.setOrderItemId(1L).setRefundPrice(100).setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()) .setOrderItemId(1L).setRefundPrice(100).setWay(AfterSaleWayEnum.RETURN_AND_REFUND.getWay())
.setApplyReason("退钱").setApplyDescription("快退") .setApplyReason("退钱").setApplyDescription("快退")
.setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png")); .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png"));
// mock 方法交易订单项 // mock 方法交易订单项
@ -86,10 +86,10 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
// 调用 // 调用
Long afterSaleId = tradeAfterSaleService.createAfterSale(userId, createReqVO); Long afterSaleId = tradeAfterSaleService.createAfterSale(userId, createReqVO);
// 断言TradeAfterSaleDO // 断言TradeAfterSaleDO
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId); AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId);
assertNotNull(afterSale.getNo()); assertNotNull(afterSale.getNo());
assertEquals(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus()); assertEquals(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus());
assertEquals(afterSale.getType(), TradeAfterSaleTypeEnum.IN_SALE.getType()); assertEquals(afterSale.getType(), AfterSaleTypeEnum.IN_SALE.getType());
assertPojoEquals(afterSale, createReqVO); assertPojoEquals(afterSale, createReqVO);
assertEquals(afterSale.getUserId(), 1024L); assertEquals(afterSale.getUserId(), 1024L);
assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime"); assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime");
@ -101,22 +101,22 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
assertNull(afterSale.getDeliveryTime()); assertNull(afterSale.getDeliveryTime());
assertNull(afterSale.getReceiveReason()); assertNull(afterSale.getReceiveReason());
// 断言TradeAfterSaleLogDO // 断言TradeAfterSaleLogDO
TradeAfterSaleLogDO afterSaleLog = tradeAfterSaleLogMapper.selectList().get(0); AfterSaleLogDO afterSaleLog = tradeAfterSaleLogMapper.selectList().get(0);
assertEquals(afterSaleLog.getUserId(), userId); assertEquals(afterSaleLog.getUserId(), userId);
assertEquals(afterSaleLog.getUserType(), UserTypeEnum.MEMBER.getValue()); assertEquals(afterSaleLog.getUserType(), UserTypeEnum.MEMBER.getValue());
assertEquals(afterSaleLog.getAfterSaleId(), afterSaleId); assertEquals(afterSaleLog.getAfterSaleId(), afterSaleId);
assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime"); assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime");
assertEquals(afterSaleLog.getContent(), TradeAfterSaleStatusEnum.APPLY.getContent()); assertEquals(afterSaleLog.getContent(), AfterSaleStatusEnum.APPLY.getContent());
} }
@Test @Test
public void testGetAfterSalePage() { public void testGetAfterSalePage() {
// mock 数据 // mock 数据
TradeAfterSaleDO dbAfterSale = randomPojo(TradeAfterSaleDO.class, o -> { // 等会查询到 AfterSaleDO dbAfterSale = randomPojo(AfterSaleDO.class, o -> { // 等会查询到
o.setNo("202211190847450020500077"); o.setNo("202211190847450020500077");
o.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus()); o.setStatus(AfterSaleStatusEnum.APPLY.getStatus());
o.setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()); o.setWay(AfterSaleWayEnum.RETURN_AND_REFUND.getWay());
o.setType(TradeAfterSaleTypeEnum.IN_SALE.getType()); o.setType(AfterSaleTypeEnum.IN_SALE.getType());
o.setOrderNo("202211190847450020500011"); o.setOrderNo("202211190847450020500011");
o.setSpuName("芋艿"); o.setSpuName("芋艿");
o.setCreateTime(buildTime(2022, 1, 15)); o.setCreateTime(buildTime(2022, 1, 15));
@ -125,11 +125,11 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
// 测试 no 不匹配 // 测试 no 不匹配
tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setNo("202211190847450020500066"))); tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setNo("202211190847450020500066")));
// 测试 status 不匹配 // 测试 status 不匹配
tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus()))); tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setStatus(AfterSaleStatusEnum.SELLER_REFUSE.getStatus())));
// 测试 way 不匹配 // 测试 way 不匹配
tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setWay(TradeAfterSaleWayEnum.REFUND.getWay()))); tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setWay(AfterSaleWayEnum.REFUND.getWay())));
// 测试 type 不匹配 // 测试 type 不匹配
tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setType(TradeAfterSaleTypeEnum.AFTER_SALE.getType()))); tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setType(AfterSaleTypeEnum.AFTER_SALE.getType())));
// 测试 orderNo 不匹配 // 测试 orderNo 不匹配
tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setOrderNo("202211190847450020500022"))); tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setOrderNo("202211190847450020500022")));
// 测试 spuName 不匹配 // 测试 spuName 不匹配
@ -137,17 +137,17 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
// 测试 createTime 不匹配 // 测试 createTime 不匹配
tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setCreateTime(buildTime(2022, 1, 20)))); tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setCreateTime(buildTime(2022, 1, 20))));
// 准备参数 // 准备参数
TradeAfterSalePageReqVO reqVO = new TradeAfterSalePageReqVO(); AfterSalePageReqVO reqVO = new AfterSalePageReqVO();
reqVO.setNo("20221119084745002050007"); reqVO.setNo("20221119084745002050007");
reqVO.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus()); reqVO.setStatus(AfterSaleStatusEnum.APPLY.getStatus());
reqVO.setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()); reqVO.setWay(AfterSaleWayEnum.RETURN_AND_REFUND.getWay());
reqVO.setType(TradeAfterSaleTypeEnum.IN_SALE.getType()); reqVO.setType(AfterSaleTypeEnum.IN_SALE.getType());
reqVO.setOrderNo("20221119084745002050001"); reqVO.setOrderNo("20221119084745002050001");
reqVO.setSpuName(""); reqVO.setSpuName("");
reqVO.setCreateTime(new LocalDateTime[]{buildTime(2022, 1, 1), buildTime(2022, 1, 16)}); reqVO.setCreateTime(new LocalDateTime[]{buildTime(2022, 1, 1), buildTime(2022, 1, 16)});
// 调用 // 调用
PageResult<TradeAfterSaleDO> pageResult = tradeAfterSaleService.getAfterSalePage(reqVO); PageResult<AfterSaleDO> pageResult = tradeAfterSaleService.getAfterSalePage(reqVO);
// 断言 // 断言
assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size()); assertEquals(1, pageResult.getList().size());

View File

@ -22,6 +22,6 @@ public interface RedisKeyConstants {
* KEY 格式pay_no:{prefix} * KEY 格式pay_no:{prefix}
* VALUE 数据格式编号自增 * VALUE 数据格式编号自增
*/ */
String PAY_NO = "pay_no"; String PAY_NO = "pay_no:";
} }

View File

@ -1,9 +1,13 @@
package cn.iocoder.yudao.module.pay.dal.redis.no; package cn.iocoder.yudao.module.pay.dal.redis.no;
import cn.hutool.core.date.DatePattern;import cn.hutool.core.date.DateUtil;import org.springframework.data.redis.core.StringRedisTemplate; import cn.hutool.core.date.DatePattern;import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.module.pay.dal.redis.RedisKeyConstants;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.annotation.Resource;import java.time.LocalDateTime; import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
/** /**
* 支付序号的 Redis DAO * 支付序号的 Redis DAO
@ -23,8 +27,12 @@ public class PayNoRedisDAO {
* @return 序号 * @return 序号
*/ */
public String generate(String prefix) { public String generate(String prefix) {
// 递增序号
String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN); String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
Long no = stringRedisTemplate.opsForValue().increment(noPrefix); String key = RedisKeyConstants.PAY_NO + noPrefix;
Long no = stringRedisTemplate.opsForValue().increment(key);
// 设置过期时间
stringRedisTemplate.expire(key, Duration.ofMinutes(1L));
return noPrefix + no; return noPrefix + no;
} }