feat(orders.manager):新增取消未支付订单的功能
1. 手动访问取消 2. 自动轮询取消 3. 查询时自动取消
This commit is contained in:
@@ -1,23 +1,26 @@
|
||||
package com.jzo2o.orders.base.model.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import java.io.Serializable;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author itcast
|
||||
* @since 2023-08-19
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("orders_canceled")
|
||||
@@ -65,4 +68,4 @@ public class OrdersCanceled implements Serializable {
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.jzo2o.orders.manager.controller.consumer;
|
||||
|
||||
import com.jzo2o.api.orders.dto.request.OrderCancelReqDTO;
|
||||
import com.jzo2o.api.orders.dto.response.OrderResDTO;
|
||||
import com.jzo2o.api.orders.dto.response.OrderSimpleResDTO;
|
||||
import com.jzo2o.common.expcetions.RequestUnauthorizedException;
|
||||
import com.jzo2o.common.model.CurrentUserInfo;
|
||||
import com.jzo2o.common.utils.ObjectUtils;
|
||||
import com.jzo2o.mvc.utils.UserContext;
|
||||
import com.jzo2o.orders.manager.model.dto.OrderCancelDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.request.OrdersPayReqDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.request.PlaceOrderReqDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.response.OrdersPayResDTO;
|
||||
@@ -81,4 +85,21 @@ public class ConsumerOrdersController {
|
||||
public OrdersPayResDTO payResult(@PathVariable("id") Long id) {
|
||||
return ordersCreateService.getPayResult(id);
|
||||
}
|
||||
|
||||
@PutMapping("/cancel")
|
||||
@ApiOperation("取消订单")
|
||||
public void cancel(@RequestBody OrderCancelReqDTO orderCancelReqDTO) {
|
||||
CurrentUserInfo currentUser = UserContext.currentUser();
|
||||
if (ObjectUtils.isEmpty(currentUser) || ObjectUtils.isEmpty(currentUser.getId())) {
|
||||
throw new RequestUnauthorizedException("无法获取当前用户信息");
|
||||
}
|
||||
|
||||
ordersManagerService.cancel(OrderCancelDTO.builder()
|
||||
.id(orderCancelReqDTO.getId())
|
||||
.cancelReason(orderCancelReqDTO.getCancelReason())
|
||||
.currentUserId(currentUser.getId())
|
||||
.currentUserName(currentUser.getName())
|
||||
.currentUserType(currentUser.getUserType())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class InnerOrdersController implements OrdersApi {
|
||||
@ApiImplicitParam(name = "id", value = "订单id", required = true, dataTypeClass = Long.class),
|
||||
})
|
||||
public OrderResDTO queryById(@PathVariable("id") Long id) {
|
||||
Orders orders = ordersManagerService.queryById(id);
|
||||
Orders orders = ordersManagerService.getById(id);
|
||||
return BeanUtil.toBean(orders, OrderResDTO.class);
|
||||
}
|
||||
|
||||
@@ -57,4 +57,4 @@ public class InnerOrdersController implements OrdersApi {
|
||||
public void evaluate(@PathVariable("id") Long id) {
|
||||
ordersManagerService.evaluationOrder(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.jzo2o.orders.manager.job;
|
||||
|
||||
import com.jzo2o.common.utils.CollUtils;
|
||||
import com.jzo2o.orders.base.model.domain.Orders;
|
||||
import com.jzo2o.orders.manager.service.IOrdersManagerService;
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自动轮询取消订单
|
||||
* @author JIAN
|
||||
*/
|
||||
@Component
|
||||
@SuppressWarnings("unused")
|
||||
public class OrderCancelJob {
|
||||
@Resource
|
||||
private IOrdersManagerService ordersManagerService;
|
||||
@Resource
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@XxlJob("cancelPayOverTimeOrder")
|
||||
public void cancelPayOverTimeOrder() {
|
||||
List<Orders> orderList = ordersManagerService.getPayOverTimeOrder(100);
|
||||
if (CollUtils.isEmpty(orderList)) {
|
||||
XxlJobHelper.log("没有超时订单");
|
||||
return;
|
||||
}
|
||||
|
||||
// 取消所有超时未支付订单
|
||||
transactionTemplate.executeWithoutResult(status ->
|
||||
orderList.forEach(order -> ordersManagerService.cancelPayOverTimeOrder(order.getId())));
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,10 @@
|
||||
package com.jzo2o.orders.manager.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.jzo2o.api.market.dto.request.CouponUseBackReqDTO;
|
||||
import com.jzo2o.api.market.dto.response.AvailableCouponsResDTO;
|
||||
import com.jzo2o.api.orders.dto.response.OrderResDTO;
|
||||
import com.jzo2o.api.orders.dto.response.OrderSimpleResDTO;
|
||||
import com.jzo2o.common.model.PageResult;
|
||||
import com.jzo2o.common.model.msg.TradeStatusMsg;
|
||||
import com.jzo2o.orders.base.model.domain.Orders;
|
||||
import com.jzo2o.orders.manager.model.dto.OrderCancelDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.request.OrderPageQueryReqDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.request.OrdersPayReqDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.request.PlaceOrderReqDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.response.OperationOrdersDetailResDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.response.OrdersPayResDTO;
|
||||
import com.jzo2o.orders.manager.model.dto.response.PlaceOrderResDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -23,23 +12,17 @@ import java.util.List;
|
||||
* <p>
|
||||
* 订单表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author itcast
|
||||
* @since 2023-07-10
|
||||
*/
|
||||
public interface IOrdersManagerService extends IService<Orders> {
|
||||
|
||||
/**
|
||||
* @param ids
|
||||
* @return
|
||||
* 查询对应订单id的所有订单信息
|
||||
*/
|
||||
List<Orders> batchQuery(List<Long> ids);
|
||||
|
||||
Orders queryById(Long id);
|
||||
|
||||
/**
|
||||
* 滚动分页查询
|
||||
*
|
||||
* @param currentUserId 当前用户id
|
||||
* @param ordersStatus 订单状态,0:待支付,100:派单中,200:待服务,300:服务中,400:待评价,500:订单完成,600:已取消,700:已关闭
|
||||
* @param sortBy 排序字段
|
||||
@@ -47,19 +30,33 @@ public interface IOrdersManagerService extends IService<Orders> {
|
||||
*/
|
||||
List<OrderSimpleResDTO> consumerQueryList(Long currentUserId, Integer ordersStatus, Long sortBy);
|
||||
|
||||
|
||||
/**
|
||||
* 根据订单id查询
|
||||
*
|
||||
* @param id 订单id
|
||||
* @return 订单详情
|
||||
*/
|
||||
OrderResDTO getDetail(Long id);
|
||||
|
||||
/**
|
||||
* 订单评价
|
||||
*
|
||||
* @param ordersId 订单id
|
||||
*/
|
||||
void evaluationOrder(Long ordersId);
|
||||
|
||||
}
|
||||
/**
|
||||
* 取消订单
|
||||
*/
|
||||
void cancel(OrderCancelDTO orderCancelDTO);
|
||||
|
||||
/**
|
||||
* 系统取消超时订单(无前置判断)
|
||||
* <br><b>仅内部使用!!!</b>
|
||||
*/
|
||||
void cancelPayOverTimeOrder(Long id);
|
||||
|
||||
/**
|
||||
* 获取支付超时订单
|
||||
* @param count 订单数量
|
||||
*/
|
||||
List<Orders> getPayOverTimeOrder(Integer count);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.jzo2o.orders.manager.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
@@ -9,16 +8,30 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.jzo2o.api.orders.dto.response.OrderResDTO;
|
||||
import com.jzo2o.api.orders.dto.response.OrderSimpleResDTO;
|
||||
import com.jzo2o.api.trade.TradingApi;
|
||||
import com.jzo2o.api.trade.dto.response.TradingResDTO;
|
||||
import com.jzo2o.api.trade.enums.TradingStateEnum;
|
||||
import com.jzo2o.common.constants.UserType;
|
||||
import com.jzo2o.common.enums.EnableStatusEnum;
|
||||
import com.jzo2o.common.expcetions.DBException;
|
||||
import com.jzo2o.common.expcetions.ForbiddenOperationException;
|
||||
import com.jzo2o.common.utils.ObjectUtils;
|
||||
import com.jzo2o.orders.base.enums.OrderStatusEnum;
|
||||
import com.jzo2o.orders.base.mapper.OrdersMapper;
|
||||
import com.jzo2o.orders.base.model.domain.Orders;
|
||||
import com.jzo2o.orders.base.model.dto.OrderSnapshotDTO;
|
||||
import com.jzo2o.orders.base.model.domain.OrdersCanceled;
|
||||
import com.jzo2o.orders.base.model.dto.OrderUpdateStatusDTO;
|
||||
import com.jzo2o.orders.base.service.IOrdersCommonService;
|
||||
import com.jzo2o.orders.manager.model.dto.OrderCancelDTO;
|
||||
import com.jzo2o.orders.manager.service.IOrdersCanceledService;
|
||||
import com.jzo2o.orders.manager.service.IOrdersManagerService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static com.jzo2o.orders.base.constants.FieldConstants.SORT_BY;
|
||||
@@ -27,28 +40,36 @@ import static com.jzo2o.orders.base.constants.FieldConstants.SORT_BY;
|
||||
* <p>
|
||||
* 订单表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author itcast
|
||||
* @since 2023-07-10
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersManagerService {
|
||||
@Resource
|
||||
private IOrdersCommonService ordersCommonService;
|
||||
@Resource
|
||||
private IOrdersCanceledService ordersCanceledService;
|
||||
@Resource
|
||||
private TransactionTemplate transactionTemplate;
|
||||
@Resource
|
||||
private TradingApi tradingApi;
|
||||
|
||||
/**
|
||||
* 订单超时时间
|
||||
*/
|
||||
private final long PAY_OVERTIME_MINUTE = 15;
|
||||
|
||||
@Override
|
||||
public List<Orders> batchQuery(List<Long> ids) {
|
||||
LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery().in(Orders::getId, ids).ge(Orders::getUserId, 0);
|
||||
LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
|
||||
.in(Orders::getId, ids)
|
||||
.ge(Orders::getUserId, 0);
|
||||
return baseMapper.selectList(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Orders queryById(Long id) {
|
||||
return baseMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动分页查询
|
||||
*
|
||||
* @param currentUserId 当前用户id
|
||||
* @param ordersStatus 订单状态,0:待支付,100:派单中,200:待服务,300:服务中,400:待评价,500:订单完成,600:已取消,700:已关闭
|
||||
* @param sortBy 排序字段
|
||||
@@ -56,7 +77,7 @@ public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders>
|
||||
*/
|
||||
@Override
|
||||
public List<OrderSimpleResDTO> consumerQueryList(Long currentUserId, Integer ordersStatus, Long sortBy) {
|
||||
//1.构件查询条件
|
||||
// 1.构造查询条件
|
||||
LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
|
||||
.eq(ObjectUtils.isNotNull(ordersStatus), Orders::getOrdersStatus, ordersStatus)
|
||||
.lt(ObjectUtils.isNotNull(sortBy), Orders::getSortBy, sortBy)
|
||||
@@ -66,29 +87,46 @@ public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders>
|
||||
queryPage.addOrder(OrderItem.desc(SORT_BY));
|
||||
queryPage.setSearchCount(false);
|
||||
|
||||
//2.查询订单列表
|
||||
// 2.查询订单列表
|
||||
Page<Orders> ordersPage = baseMapper.selectPage(queryPage, queryWrapper);
|
||||
List<Orders> records = ordersPage.getRecords();
|
||||
List<OrderSimpleResDTO> orderSimpleResDTOS = BeanUtil.copyToList(records, OrderSimpleResDTO.class);
|
||||
return orderSimpleResDTOS;
|
||||
|
||||
return BeanUtil.copyToList(records, OrderSimpleResDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据订单id查询
|
||||
*
|
||||
* @param id 订单id
|
||||
* @return 订单详情
|
||||
*/
|
||||
@Override
|
||||
public OrderResDTO getDetail(Long id) {
|
||||
Orders orders = queryById(id);
|
||||
Orders orders = baseMapper.selectById(id);
|
||||
if (ObjectUtils.isEmpty(orders)) {
|
||||
return new OrderResDTO();
|
||||
}
|
||||
|
||||
OrderResDTO orderResDTO = BeanUtil.toBean(orders, OrderResDTO.class);
|
||||
// 订单超过15分钟未支付则自动取消
|
||||
if (OrderStatusEnum.NO_PAY.getStatus().equals(orders.getOrdersStatus())
|
||||
&& orders.getCreateTime().isBefore(LocalDateTime.now().minusMinutes(PAY_OVERTIME_MINUTE))) {
|
||||
cancelPayOverTimeOrder(id);
|
||||
orderResDTO.setOrdersStatus(OrderStatusEnum.CANCELED.getStatus());
|
||||
}
|
||||
|
||||
// 订单取消/关闭获取取消/关闭原因
|
||||
Integer ordersStatus = orderResDTO.getOrdersStatus();
|
||||
if (OrderStatusEnum.CANCELED.getStatus().equals(ordersStatus)
|
||||
|| OrderStatusEnum.CLOSED.getStatus().equals(ordersStatus)) {
|
||||
OrdersCanceled canceledDetail = ordersCanceledService.getById(id);
|
||||
orderResDTO.setCancelTime(canceledDetail.getCancelTime());
|
||||
orderResDTO.setCancelReason(canceledDetail.getCancelReason());
|
||||
}
|
||||
|
||||
return orderResDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单评价
|
||||
*
|
||||
* @param ordersId 订单id
|
||||
*/
|
||||
@Override
|
||||
@@ -106,4 +144,80 @@ public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders>
|
||||
// orderStateMachine.changeStatus(orders.getUserId(), orders.getId().toString(), OrderStatusChangeEventEnum.EVALUATE, orderSnapshotDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void cancel(OrderCancelDTO orderCancelDTO) {
|
||||
Long orderId = orderCancelDTO.getId();
|
||||
Orders orders = baseMapper.selectById(orderId);
|
||||
if (ObjectUtils.isEmpty(orders)) {
|
||||
throw new ForbiddenOperationException("订单不存在无法取消");
|
||||
}
|
||||
// 补充前端无法确定的字段
|
||||
orderCancelDTO.setServeStartTime(orders.getServeStartTime());
|
||||
orderCancelDTO.setRealPayAmount(orders.getRealPayAmount());
|
||||
orderCancelDTO.setCityCode(orders.getCityCode());
|
||||
orderCancelDTO.setTradingOrderNo(orders.getTradingOrderNo());
|
||||
|
||||
Integer ordersStatus = orders.getOrdersStatus();
|
||||
if (OrderStatusEnum.NO_PAY.getStatus().equals(ordersStatus)) {
|
||||
// 1. 未支付订单 -> 取消状态
|
||||
cancelNoPayOrder(orderCancelDTO);
|
||||
} else if (OrderStatusEnum.DISPATCHING.getStatus().equals(ordersStatus)) {
|
||||
// 2. 已支付订单 -> 关闭状态 + 退款
|
||||
cancelDispatchingOrder(orderCancelDTO);
|
||||
} else {
|
||||
throw new ForbiddenOperationException("订单无法取消");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Orders> getPayOverTimeOrder(Integer count) {
|
||||
return lambdaQuery()
|
||||
.eq(Orders::getOrdersStatus, OrderStatusEnum.NO_PAY.getStatus())
|
||||
.lt(Orders::getCreateTime, LocalDateTime.now().minusMinutes(PAY_OVERTIME_MINUTE))
|
||||
.last("LIMIT " + count)
|
||||
.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelPayOverTimeOrder(Long id) {
|
||||
// 二次确认防止在此期间支付
|
||||
TradingResDTO tradingResDTO = tradingApi.findTradResultByTradingOrderNo(id);
|
||||
if (ObjectUtils.isEmpty(tradingResDTO) || tradingResDTO.getTradingState() != TradingStateEnum.YJS) {
|
||||
cancelNoPayOrder(OrderCancelDTO.builder()
|
||||
.id(id)
|
||||
.cancelReason("订单超时未支付自动取消")
|
||||
.currentUserId(-1L)
|
||||
.currentUserName("SYSTEM")
|
||||
.currentUserType(UserType.SYSTEM)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelNoPayOrder(OrderCancelDTO orderCancelDTO) {
|
||||
Long orderId = orderCancelDTO.getId();
|
||||
transactionTemplate.executeWithoutResult(status -> {
|
||||
if (!ordersCanceledService.save(OrdersCanceled.builder()
|
||||
.id(orderId)
|
||||
.cancellerId(orderCancelDTO.getCurrentUserId())
|
||||
.cancelerName(orderCancelDTO.getCurrentUserName())
|
||||
.cancellerType(orderCancelDTO.getCurrentUserType())
|
||||
.cancelReason(orderCancelDTO.getCancelReason())
|
||||
.cancelTime(LocalDateTime.now())
|
||||
.build())) {
|
||||
throw new DBException("订单取消表更新失败");
|
||||
}
|
||||
|
||||
if (!ordersCommonService.updateStatus(OrderUpdateStatusDTO.builder()
|
||||
.id(orderId)
|
||||
.originStatus(OrderStatusEnum.NO_PAY.getStatus())
|
||||
.targetStatus(OrderStatusEnum.CANCELED.getStatus())
|
||||
.build())) {
|
||||
throw new DBException("订单表订单状态更新失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void cancelDispatchingOrder(OrderCancelDTO orderCancelDTO) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user