| | |
| | | /** 小程序讲解订单创建及状态流转服务。 */ |
| | | @Service |
| | | public class MiniTourOrderCommandService { |
| | | private static final int DEFAULT_UNPAID_CANCEL_MINUTES = 15; |
| | | private final TourOrderMapper orderMapper; |
| | | private final MiniUserService miniUserService; |
| | | private final OperationScenicSpotMapper scenicSpotMapper; |
| | |
| | | private final GuideNotificationService notificationService; |
| | | private final OrderRefundService orderRefundService; |
| | | private final GuideOrderMatchingService matchingService; |
| | | private final GuideSessionTransitionService sessionTransitionService; |
| | | private final boolean skipPayment; |
| | | |
| | | public MiniTourOrderCommandService(TourOrderMapper orderMapper, |
| | |
| | | GuideNotificationService notificationService, |
| | | OrderRefundService orderRefundService, |
| | | GuideOrderMatchingService matchingService, |
| | | GuideSessionTransitionService sessionTransitionService, |
| | | @Value("${tourguide.order.skip-payment:false}") boolean skipPayment) { |
| | | this.orderMapper = orderMapper; |
| | | this.miniUserService = miniUserService; |
| | |
| | | this.notificationService = notificationService; |
| | | this.orderRefundService = orderRefundService; |
| | | this.matchingService = matchingService; |
| | | this.sessionTransitionService = sessionTransitionService; |
| | | this.skipPayment = skipPayment; |
| | | } |
| | | |
| | |
| | | .orderByDesc(ScenicPricing::getId) |
| | | .last("LIMIT 1")); |
| | | GuideUser guide = order.getGuideId() == null ? null : guideUserMapper.selectById(order.getGuideId()); |
| | | int unpaidCancelMinutes = scenicSpot == null || scenicSpot.getUnpaidCancelMinutes() == null |
| | | || scenicSpot.getUnpaidCancelMinutes() < 1 |
| | | ? DEFAULT_UNPAID_CANCEL_MINUTES : scenicSpot.getUnpaidCancelMinutes(); |
| | | cancelExpiredUnpaidIfNeeded(order, unpaidCancelMinutes); |
| | | return TourOrderResponse.from(order) |
| | | .enrich(scenicSpot, meetingPoint, pricing, guide) |
| | | .withUnpaidCancelMinutes(unpaidCancelMinutes) |
| | | .withUnacceptedAutoRefundMinutes( |
| | | platformSettingsService.getSettings().getUnacceptedAutoRefundMinutes()); |
| | | } |
| | | |
| | | /** 读取订单时惰性取消已超时的未支付订单,避免等待定时任务扫描延迟。 */ |
| | | private void cancelExpiredUnpaidIfNeeded(TourOrder order, int unpaidCancelMinutes) { |
| | | if (!OrderStatus.PENDING_PAYMENT.matches(order.getStatus())) return; |
| | | LocalDateTime baseTime = order.getPlacedAt() == null ? order.getCreatedAt() : order.getPlacedAt(); |
| | | if (baseTime == null || baseTime.plusMinutes(unpaidCancelMinutes).isAfter(LocalDateTime.now())) return; |
| | | if (orderMapper.cancelUnpaid(order.getId()) > 0) { |
| | | order.setStatus(OrderStatus.CANCELLED.getCode()); |
| | | order.setCancelledAt(LocalDateTime.now()); |
| | | } |
| | | } |
| | | |
| | | @Transactional |
| | |
| | | throw new BusinessException(409, "当前订单状态不支持取消"); |
| | | } |
| | | order.setStatus(OrderStatus.CANCELLED.getCode()); |
| | | order.setCancelledAt(LocalDateTime.now()); |
| | | if (order.getPaymentTime() == null) { |
| | | orderMapper.updateById(order); |
| | | } else { |
| | | orderRefundService.requestRefund(order); |
| | | } |
| | | if (notifyGuide) sessionTransitionService.restoreAfterOrderCancellation(order); |
| | | if (notifyGuide) notificationService.notifyVisitorCancelledOrder(order); |
| | | return TourOrderResponse.from(order); |
| | | } |