【云岚到家】-day07-1-退款服务功能初实现


4 家政订单退款功能

4.1 取消订单功能分析设计

目标:

设计取消订单接口。

退款流程设计。

1)需求分析

用户下单成功可以取消订单,在订单的不同状态下去取消订单其执行的逻辑是不同的:

待支付状态下取消订单:

更改订单的状态为已取消。

订单已支付,状态为待派单时取消订单:

更改订单的状态为已关闭。

请求支付服务自动退款。

完整的取消订单功能将在后续章节讲解,由于订单的状态非常多,取消订单的逻辑也非常多,后期我们使用策略模式实现取消订单的逻辑。

本节实现上边两种状态下的订单取消操作。

用户在订单列表点击订单信息进入订单详情页面,点击“取消订单”

在这里插入图片描述

进入取消订单界面:

在这里插入图片描述

选择取消原因,点击“提交”。

2)接口定义

前端传入的参数:订单id、取消原因。

响应参数:无,前端根据状态码判断是否成功。

接口名称:取消订单

接口路径PUT /orders-manager/consumer/orders/cancel

在这里插入图片描述

在这里插入图片描述

定义controller方法:

@RestController("consumerOrdersController")
@Api(tags = "用户端-订单相关接口")
@RequestMapping("/consumer/orders")
public class ConsumerOrdersController {

@PutMapping("/cancel")
@ApiOperation("取消订单")
public void cancel(@RequestBody OrderCancelReqDTO orderCancelReqDTO) {
   
}

3)退款流程设计

根据需求分析,当订单已支付状态为派单中时取消订单后进行自动退款,此时需要调用支付服务的申请退款接口。

流程如下:

在这里插入图片描述

取消订单执行如下操作:

1、更新订单状态

待支付状态下取消订单后更新订单状态为“已取消”

派单中状态下取消订单后更新订单状态为“已关闭”

2、保存取消订单记录,记录取消的原因等信息。

3、远程调用支付服务的退款接口申请退款。

取消派单中的订单存在如下问题:

远程调用退款接口操作不放在事务方法中,避免影响数据库性能。

如果远程调用退款接口失败了将无法退款,这个怎么处理?

以上问题采用异步退款的方式来解决:

如下图:

在这里插入图片描述

取消订单执行如下操作:

1、使用数据库事务控制,保存以下数据,这三个事情由一个事务进行控制。

更新订单状态。

保存取消订单记录表,记录取消的原因等信息。

保存退款记录表。

2、事务提交后先启动一个线程请求支付服务的退款接口(为了及时退款)

3、定时任务扫描退款记录表,对未退款的记录请求支付服务进行退款,退款成功更新订单的退款状态,并删除退款记录。

说明:

第2步的作用为了第一时间申请退款,因为定时任务会有一定的延迟。

第3步的作用是由定时任务去更新退款的状态,因为调用了退款接口只是申请退款了,退款结果可能还没有拿到,通过定时任务再次请求支付服务的退款接口,拿到退款结果。

4)表结构

订单取消记录表:

create table `jzo2o-orders`.orders_canceled
(
    id             bigint                             not null comment '订单id'
        constraint `PRIMARY`
        primary key,
    canceller_id   bigint                             null comment '取消人',
    canceler_name  varchar(50)                        null comment '取消人名称',
    canceller_type int                                null comment '取消人类型,1:普通用户,4:运营人员',
    cancel_reason  varchar(50)                        null comment '取消原因',
    cancel_time    datetime                           null comment '取消时间',
    create_time    datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    update_time    datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间'
)
    comment '订单取消表' charset = utf8mb4;

订单退款记录表:存储 了待退款的记录

create table `jzo2o-orders`.orders_refund
(
    id               bigint                             not null comment '订单id'
        constraint `PRIMARY`
        primary key,
    trading_order_no bigint                             null comment '支付服务交易单号',
    real_pay_amount  decimal(10, 2)                     null comment '实付金额',
    create_time      datetime default CURRENT_TIMESTAMP null comment '创建时间'
)
    comment '订单退款表' charset = utf8mb4;

4.2 取消未支付订单实现

根据需求,取消订单需要实现两部分功能:

针对未支付订单的取消操作:

修改订单的状态为已取消。

保存取消订单的记录。

针对已支付订单,状态为派单中的订单的取消操作。

下边实现针对未支付订单的取消操作。

1)定义controller

因为前端传入的OrderCancelReqDTO只有id和原因,而我们后续的操作涉及用户及金额等等,所以使用一个新的DTO来进行管理OrderCancelDTO

com.jzo2o.orders.manager.model.dto.OrderCancelDTO包含

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderCancelDTO {
    /**
     * 订单id
     */
    private Long id;

    /**
     * 用户id
     */
    private Long userId;

    /**
     * 当前用户id
     */
    private Long currentUserId;

    /**
     * 当前用户名称
     */
    private String currentUserName;

    /**
     * 当前用户类型
     */
    private Integer currentUserType;

    /**
     * 取消原因
     */
    private String cancelReason;

    /**
     * 预约服务开始时间
     */
    private LocalDateTime serveStartTime;

    /**
     * 实际支付金额
     */
    private BigDecimal realPayAmount;

    /**
     * 城市编码
     */
    private String cityCode;

    /**
     * 支付服务交易单号
     */
    private Long tradingOrderNo;
}

这样我们在controller中,直接用OrderCancelReqDTO来构建我们的OrderCancelDTO

controller代码如下

@PutMapping("/cancel")
@ApiOperation("取消订单")
public void cancel(@RequestBody OrderCancelReqDTO orderCancelReqDTO) {
    OrderCancelDTO orderCancelDTO = BeanUtil.toBean(orderCancelReqDTO, OrderCancelDTO.class);
    CurrentUserInfo currentUserInfo = UserContext.currentUser();
    orderCancelDTO.setCurrentUserId(currentUserInfo.getId());
    orderCancelDTO.setCurrentUserName(currentUserInfo.getName());
    orderCancelDTO.setCurrentUserType(currentUserInfo.getUserType());
    ordersManagerService.cancel(orderCancelDTO);
}

2)定义取消订单的service(总入口 )

该service是取消订单的总入口,此service上判断订单状态去执行不同的取消操作逻辑。

定义取消订单的service方法,代码如下:

public interface IOrdersManagerService extends IService<Orders> {

/**
 * 取消订单
 *
 * @param orderCancelDTO 取消订单模型
 */
void cancel(OrderCancelDTO orderCancelDTO);
...

方法实现:

/**
 * 取消订单
 *
 * @param orderCancelDTO 取消订单模型
 */
@Override
public void cancel(OrderCancelDTO orderCancelDTO) {
    //查询订单信息
    Orders orders = getById(orderCancelDTO.getId());

    if (ObjectUtil.isNull(orders)) {
        throw new DbRuntimeException("找不到要取消的订单,订单号:{}",orderCancelDTO.getId());
    }
    //订单状态
    Integer ordersStatus = orders.getOrdersStatus();
    //根据订单状态执行取消逻辑
    if(Objects.equals(OrderStatusEnum.NO_PAY.getStatus(), ordersStatus)){ //订单状态为待支付

    }else if(Objects.equals(OrderStatusEnum.DISPATCHING.getStatus(), ordersStatus)){ //订单状态为派单中

    }else{
        throw new CommonException("当前订单状态不支持取消");
    }
}

3)定义取消未支付订单service

当判断订单状态为未支付,调用 此service执行以下操作:

添加取消订单记录。

更新订单状态为“已取消”。

代码如下:

//未支付状态取消订单
@Transactional(rollbackFor = Exception.class)
public void cancelByNoPay(OrderCancelDTO orderCancelDTO) {
    //保存取消订单记录
    OrdersCanceled ordersCanceled = BeanUtil.toBean(orderCancelDTO, OrdersCanceled.class);
    ordersCanceled.setCancellerId(orderCancelDTO.getCurrentUserId());
    ordersCanceled.setCancelerName(orderCancelDTO.getCurrentUserName());
    ordersCanceled.setCancellerType(orderCancelDTO.getCurrentUserType());
    ordersCanceled.setCancelTime(LocalDateTime.now());
    ordersCanceledService.save(ordersCanceled);
    //更新订单状态为取消订单
    OrderUpdateStatusDTO orderUpdateStatusDTO = OrderUpdateStatusDTO.builder()
            .id(orderCancelDTO.getId())
            .originStatus(OrderStatusEnum.NO_PAY.getStatus())
            .targetStatus(OrderStatusEnum.CANCELED.getStatus())
            .build();
    int result = ordersCommonService.updateStatus(orderUpdateStatusDTO);
    if (result <= 0) {
        throw new DbRuntimeException("订单取消事件处理失败");
    }

}

4)完善取消订单的service

在总入口 service中调用 “取消未支付订单service方法”。

/**
 * 取消订单
 *
 * @param orderCancelDTO 取消订单模型
 */
@Override
public void cancel(OrderCancelDTO orderCancelDTO) {
    //查询订单信息
    Orders orders = getById(orderCancelDTO.getId());
    BeanUtils.copyProperties(orders,orderCancelDTO);
    if (ObjectUtil.isNull(orders)) {
        throw new DbRuntimeException("找不到要取消的订单,订单号:{}",orderCancelDTO.getId());
    }
    //订单状态
    Integer ordersStatus = orders.getOrdersStatus();

    if(Objects.equals(OrderStatusEnum.NO_PAY.getStatus(), ordersStatus)){ //订单状态为待支付
        owner.cancelByNoPay(orderCancelDTO);
    }else if(Objects.equals(OrderStatusEnum.DISPATCHING.getStatus(), ordersStatus)){ //订单状态为待服务

    }else{
        throw new CommonException("当前订单状态不支持取消");
    }
}

5)测试

测试流程:

新创建一个订单,不进行支付。

进入订单列表,点击订单信息进入订单详情页面,点击“取消订单”

预期结果:

查看订单表中订单状态改为600(已取消)

订单取消记录表orders_canceled是否成功插入一条记录。

搞个码农洗碗但不支付。随后取消订单

在这里插入图片描述

在这里插入图片描述

查看数据库,在order_canceled表中有码农洗碗

在这里插入图片描述

查看order表,码农洗碗的状态变为600

在这里插入图片描述

4.3 自动取消未支付订单(1)

1)技术方案

取消未支付订单除了人工操作外还可以自动取消,下单超过15分钟未支付则自动取消订单。这个需求在很多业务场景都有用到,比如:购买火车票、购买电影票在一定时间内未支付将自动取消。

如何实现自动取消订单操作呢?

这里最关键有一个定时的要求,从下单开始计算15分钟后取消订单。

如果要分秒不差执行取消订单操作就需要使用定时器每秒去判断是否到达过期时间。

如果订单较多使用多个定时器会耗费CPU。

其实,我们可以不用分秒不差执行取消操作,从用户的角度去思考,通常是用户点击订单查看的时候发现不能支付,因为到达支付过期时间。

所以,我们可以通过定时任务和懒加载方式。

定时任务方式:每分钟将支付过期的订单查询出来进行取消操作。

懒加载方式:当用户查看订单详情时判断如果订单未支付且支付超时,此时触发订单取消操作

2)实现定时任务取消订单

  1. 定义service查询支付超时订单
public interface IOrdersCreateService extends IService<Orders> {

/**
 * 查询超时订单id列表
 *
 * @param count 数量
 * @return 订单id列表
 */
public List<Orders> queryOverTimePayOrdersListByCount(Integer count);
...

实现方法:

/**
 * 查询超时订单id列表
 *
 * @param count 数量
 * @return 订单id列表
 */
@Override
public List<Orders> queryOverTimePayOrdersListByCount(Integer count) {
    //根据订单创建时间查询超过15分钟未支付的订单
    List<Orders> list = lambdaQuery()
        //查询待支付状态的订单
        .eq(Orders::getOrdersStatus, OrderStatusEnum.NO_PAY.getStatus())
        //小于当前时间减去15分钟,即待支付状态已过15分钟
        .lt(Orders::getCreateTime, LocalDateTime.now().minusMinutes(15))
        .last("limit " + count)
        .list();
    return list;
}
  1. 定义定时任务

创建com.jzo2o.orders.manager.handler.OrdersHandler

@Component
public class OrdersHandler {

    @Resource
    private IOrdersCreateService ordersCreateService;
    @Resource
    private IOrdersManagerService ordersManagerService;

    /**
     * 支付超时取消订单
     * 每分钟执行一次
     */
    @XxlJob(value = "cancelOverTimePayOrder")
    public void cancelOverTimePayOrder() {
        //查询支付超时状态订单
        List<Orders> ordersList = ordersCreateService.queryOverTimePayOrdersListByCount(100);
        if (CollUtil.isEmpty(ordersList)) {
            XxlJobHelper.log("查询超时订单列表为空!");
            return;
        }
        for (Orders order : ordersList) {
            //取消订单
            OrderCancelDTO orderCancelDTO = BeanUtil.toBean(order, OrderCancelDTO.class);
            orderCancelDTO.setCurrentUserType(UserType.SYSTEM);
            orderCancelDTO.setCancelReason("订单超时支付,自动取消");
            ordersManagerService.cancel(orderCancelDTO);
        }
    }
}

xxl-job注册任务,在订单管理中新增一个,为了测试方便我们5s已查询,然后手动修改时间即可

在这里插入图片描述

注册好后直接启动

在这里插入图片描述

3)测试

我们创建个未支付订单(码农扫地)然后修改时间到15分钟以前,我们在查询超时订单这里打个断点

在这里插入图片描述

在这里插入图片描述

然后修改数据库的下单时间,再查看数据库

在这里插入图片描述

立刻捕获到我们的超时订单

在这里插入图片描述

查看cancel表

在这里插入图片描述

4.4 自动取消未支付订单(2)

1)懒加载方式取消订单

在订单详情service中添加

/**
 * 根据订单id查询
 *
 * @param id 订单id
 * @return 订单详情
 */
@Override
public OrderResDTO getDetail(Long id) {
    //查询订单
    Orders orders = queryById(id);
    //如果支付过期则取消订单
    orders = canalIfPayOvertime(orders);
    OrderResDTO orderResDTO = BeanUtil.toBean(orders, OrderResDTO.class);

    return orderResDTO;
}
/**
 * 如果支付过期则取消订单
 * @param orders
 */
private Orders canalIfPayOvertime(Orders orders){
    //创建订单未支付15分钟后自动取消
    if(Objects.equals(orders.getOrdersStatus(), OrderStatusEnum.NO_PAY.getStatus()) && orders.getCreateTime().plusMinutes(15).isBefore(LocalDateTime.now())){
        //查询支付结果,如果支付最新状态仍是未支付进行取消订单
        OrdersPayResDTO ordersPayResDTO = ordersCreateService.getPayResultFromTradServer(orders.getId());
        int payResultFromTradServer = ordersPayResDTO.getPayStatus();
        if(payResultFromTradServer != OrderPayStatusEnum.PAY_SUCCESS.getStatus()){
            //取消订单
            OrderCancelDTO orderCancelDTO = BeanUtil.toBean(orders, OrderCancelDTO.class);
            orderCancelDTO.setCurrentUserType(UserType.SYSTEM);
            orderCancelDTO.setCancelReason("订单超时支付,自动取消");
            cancel(orderCancelDTO);
            orders = getById(orders.getId());
        }
    }
    return orders;
}

2)测试

原理比较简单我们就不测试了

4.5 取消派单中订单实现

1)定义取消派单中订单service

当订单状态为派单中,取消此类订单需要进行退款操作,根据退款流程,需要作以下操作:

  1. 添加取消订单记录。
  2. 更新订单状态为“已关闭”。
  3. 添加退款记录。

定义service方法实现上边3个操作,并且进行事务控制。

代码如下:

public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersManagerService {

@Resource
private IOrdersRefundService ordersRefundService;

//派单中状态取消订单
@Transactional(rollbackFor = Exception.class)
public void cancelByDispatching(OrderCancelDTO orderCancelDTO) {
    //保存取消订单记录
    OrdersCanceled ordersCanceled = BeanUtil.toBean(orderCancelDTO, OrdersCanceled.class);
    ordersCanceled.setCancellerId(orderCancelDTO.getCurrentUserId());
    ordersCanceled.setCancelerName(orderCancelDTO.getCurrentUserName());
    ordersCanceled.setCancellerType(orderCancelDTO.getCurrentUserType());
    ordersCanceled.setCancelTime(LocalDateTime.now());
    ordersCanceledService.save(ordersCanceled);
    //更新订单状态为关闭订单
    OrderUpdateStatusDTO orderUpdateStatusDTO = OrderUpdateStatusDTO.builder().id(orderCancelDTO.getId())
            .originStatus(OrderStatusEnum.DISPATCHING.getStatus())
            .targetStatus(OrderStatusEnum.CLOSED.getStatus())
            .refundStatus(OrderRefundStatusEnum.REFUNDING.getStatus())//退款状态为退款中
            .build();
    int result = ordersCommonService.updateStatus(orderUpdateStatusDTO);
    if (result <= 0) {
        throw new DbRuntimeException("待服务订单关闭事件处理失败");
    }
    //添加退款记录
    OrdersRefund ordersRefund = new OrdersRefund();
    ordersRefund.setId(orderCancelDTO.getId());
    ordersRefund.setTradingOrderNo(orderCancelDTO.getTradingOrderNo());
    ordersRefund.setRealPayAmount(orderCancelDTO.getRealPayAmount());
    ordersRefundService.save(ordersRefund);
}
...

完善取消订单service

/**
 * 取消订单
 *
 * @param orderCancelDTO 取消订单模型
 */
@Override
public void cancel(OrderCancelDTO orderCancelDTO) {
    //查询订单信息
    Orders orders = getById(orderCancelDTO.getId());
    BeanUtils.copyProperties(orders,orderCancelDTO);
    if (ObjectUtil.isNull(orders)) {
        throw new DbRuntimeException("找不到要取消的订单,订单号:{}",orderCancelDTO.getId());
    }
    //订单状态
    Integer ordersStatus = orders.getOrdersStatus();

    if(Objects.equals(OrderStatusEnum.NO_PAY.getStatus(), ordersStatus)){ //订单状态为待支付
        owner.cancelByNoPay(orderCancelDTO);
    }else if(Objects.equals(OrderStatusEnum.DISPATCHING.getStatus(), ordersStatus)){ //订单状态为待服务
        owner.cancelByDispatching(orderCancelDTO);
    }else{
        throw new CommonException("当前订单状态不支持取消");
    }
}

2)定时任务请求退款接口

取消派单中的订单进行自动退款,这里通过定时任务请求退款接口:

在OrdersHandler 类中定义定时任务方法。

定时任务根据退款记录去请求第三方支付服务的退款接口,根据退款结果进行处理,如果退款成功将更新订单的退款状态、删除退款记录。

@Component
public class OrdersHandler {

    @Resource
    private IOrdersCreateService ordersCreateService;
    @Resource
    private IOrdersManagerService ordersManagerService;

    @Resource
    private RefundRecordApi refundRecordApi;

    //解决同级方法调用,事务失效问题
    @Resource
    private OrdersHandler owner;

    @Resource
    private IOrdersRefundService ordersRefundService;
    
    @Resource
    private OrdersMapper ordersMapper;

    /**
     * 支付超时取消订单
     * 每分钟执行一次
     */
    @XxlJob(value = "cancelOverTimePayOrder")
    public void cancelOverTimePayOrder() {
        //查询支付超时状态订单
        List<Orders> ordersList = ordersCreateService.queryOverTimePayOrdersListByCount(100);
        if (CollUtil.isEmpty(ordersList)) {
            XxlJobHelper.log("查询超时订单列表为空!");
            return;
        }
        for (Orders order : ordersList) {
            //取消订单
            OrderCancelDTO orderCancelDTO = BeanUtil.toBean(order, OrderCancelDTO.class);
            orderCancelDTO.setCurrentUserType(UserType.SYSTEM);
            orderCancelDTO.setCancelReason("订单超时支付,自动取消");
            ordersManagerService.cancel(orderCancelDTO);
        }
    }

    /**
     * 订单退款异步任务
     */
    @XxlJob(value = "handleRefundOrders")
    public void handleRefundOrders() {
        //查询退款中订单
        List<OrdersRefund> ordersRefundList = ordersRefundService.queryRefundOrderListByCount(100);
        for (OrdersRefund ordersRefund : ordersRefundList) {
            //请求退款
            requestRefundOrder(ordersRefund);
        }
    }
    /**
     * 请求退款
     * @param ordersRefund 退款记录
     */
    public void requestRefundOrder(OrdersRefund ordersRefund){
        //调用第三方进行退款
        ExecutionResultResDTO executionResultResDTO = null;
        try {
            executionResultResDTO = refundRecordApi.refundTrading(ordersRefund.getTradingOrderNo(), ordersRefund.getRealPayAmount());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(executionResultResDTO!=null){
            //退款后处理订单相关信息
            owner.refundOrder(ordersRefund, executionResultResDTO);
        }
    }

    /**
     * 更新退款状态
     * @param ordersRefund
     * @param executionResultResDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void refundOrder(OrdersRefund ordersRefund, ExecutionResultResDTO executionResultResDTO) {
        //根据响应结果更新退款状态
        int refundStatus = OrderRefundStatusEnum.REFUNDING.getStatus();//退款中
        if (ObjectUtil.equal(RefundStatusEnum.SUCCESS.getCode(), executionResultResDTO.getRefundStatus())) {
            //退款成功
            refundStatus = OrderRefundStatusEnum.REFUND_SUCCESS.getStatus();
        } else if (ObjectUtil.equal(RefundStatusEnum.FAIL.getCode(), executionResultResDTO.getRefundStatus())) {
            //退款失败
            refundStatus = OrderRefundStatusEnum.REFUND_FAIL.getStatus();
        }

        //如果是退款中状态,程序结束
        if (ObjectUtil.equal(refundStatus, OrderRefundStatusEnum.REFUNDING.getStatus())) {
            return;
        }

        //非退款中状态,更新订单的退款状态
        LambdaUpdateWrapper<Orders> updateWrapper = new LambdaUpdateWrapper<Orders>()
                .eq(Orders::getId, ordersRefund.getId())
                .ne(Orders::getRefundStatus, refundStatus)
                .set(Orders::getRefundStatus, refundStatus)
                .set(ObjectUtil.isNotEmpty(executionResultResDTO.getRefundId()), Orders::getRefundId, executionResultResDTO.getRefundId())
                .set(ObjectUtil.isNotEmpty(executionResultResDTO.getRefundNo()), Orders::getRefundNo, executionResultResDTO.getRefundNo());
        int update = ordersMapper.update(null, updateWrapper);
        //非退款中状态,删除申请退款记录,删除后定时任务不再扫描
        if(update>0){
            //非退款中状态,删除申请退款记录,删除后定时任务不再扫描
            ordersRefundService.removeById(ordersRefund.getId());
        }
    }
}

配置xxl-job

在这里插入图片描述

3) 测试

新创建一个订单,并支付成功。

进入订单列表,点击订单信息进入订单详情页面,点击“取消订单”

点击取消订单预期结果:

订单取消记录表orders_canceled是否成功插入一条记录。

退款记录表orders_refund中是否成功插入一条记录

更新订单状态为已关闭(已关闭),退款状态为退款中。

定时任务执行后预期结果:

请求支付服务的退款接口成功,微信退款成功。

退款成功后删除orders_refund中记录。

更新订单表中的退款状态(退款成功或退款失败)、支付服务的退款单号、微信的退款单号。


我们把订单中所有派单的全给退了,退单的同时微信收到退款

在这里插入图片描述

4.6 及时退款实现

1)启动新线程请求退款接口

为了及时进行退款,在订单取消后启动一个新线程请求支付服务的退款接口。

代码如下:

/**
 * 新启动一个线程请求退款
 * @param ordersRefundId
 */
public void requestRefundNewThread(Long ordersRefundId){
    //启动一个线程请求第三方退款接口
    new Thread(()->{
        //查询退款记录
        OrdersRefund ordersRefund = ordersRefundService.getById(ordersRefundId);
        if(ObjectUtil.isNotNull(ordersRefund)){
            //请求退款
            requestRefundOrder(ordersRefund);
        }
    }).start();
}

2)完善取消订单service

/**
 * 取消订单
 *
 * @param orderCancelDTO 取消订单模型
 */
@Override
public void cancel(OrderCancelDTO orderCancelDTO) {
    //查询订单信息
    Orders orders = getById(orderCancelDTO.getId());
    BeanUtils.copyProperties(orders,orderCancelDTO);
    if (ObjectUtil.isNull(orders)) {
        throw new DbRuntimeException("找不到要取消的订单,订单号:{}",orderCancelDTO.getId());
    }
    //订单状态
    Integer ordersStatus = orders.getOrdersStatus();

    if(Objects.equals(OrderStatusEnum.NO_PAY.getStatus(), ordersStatus)){ //订单状态为待支付
        owner.cancelByNoPay(orderCancelDTO);
    }else if(Objects.equals(OrderStatusEnum.DISPATCHING.getStatus(), ordersStatus)){ //订单状态为待服务
        owner.cancelByDispatching(orderCancelDTO);
        //新启动一个线程请求退款
        ordersHandler.requestRefundNewThread(orders.getId());
    }else{
        throw new CommonException("当前订单状态不支持取消");
    }
}

3) 测试

暂时关闭退款定时任务。

测试流程:

新创建一个订单,并支付成功。

进入订单列表,点击订单信息进入订单详情页面,点击“取消订单”

预期结果:

订单取消记录表orders_canceled是否成功插入一条记录。

退款记录表orders_refund中是否成功插入一条记录

更新订单状态为已关闭(已关闭),退款状态为退款中。

请求支付服务的退款接口成功,微信退款成功。

注意:可能存在微信退款到账了但是订单中的退款状态未更改的情况,并且退款记录仍然存在,这是因为调用支付服务退款接口申请退款可能不会立即拿到退款成功的结果,但其它第三方已经发起退款了。

解决这个问题就需要定时任务再去请求支付服务的退款接口,如果拿到退款结果为退款完成将会更新订单的退款状态并且删除退款记录。


这里就不测试了,跟前面大同小异。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bblb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值