package com.tourguide.modules.order.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.tourguide.modules.operation.service.PlatformSettingsService; import com.tourguide.modules.order.domain.OrderStatus; import com.tourguide.modules.order.domain.RefundStatus; import com.tourguide.modules.order.entity.TourOrder; import com.tourguide.modules.order.mapper.TourOrderMapper; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.List; @Service public class OrderAutoRefundService { private static final int BATCH_SIZE = 100; private final TourOrderMapper orderMapper; private final PlatformSettingsService platformSettingsService; private final OrderRefundService orderRefundService; public OrderAutoRefundService(TourOrderMapper orderMapper, PlatformSettingsService platformSettingsService, OrderRefundService orderRefundService) { this.orderMapper = orderMapper; this.platformSettingsService = platformSettingsService; this.orderRefundService = orderRefundService; } @Scheduled(fixedDelayString = "${tourguide.order.auto-refund-scan-delay-millis:10000}") @Transactional public void refundExpiredUnacceptedOrders() { Integer configuredMinutes = platformSettingsService.getSettings().getUnacceptedAutoRefundMinutes(); int timeoutMinutes = configuredMinutes == null || configuredMinutes < 1 ? 5 : configuredMinutes; LocalDateTime expiredBefore = LocalDateTime.now().minusMinutes(timeoutMinutes); List orders = orderMapper.selectList( new LambdaQueryWrapper() .eq(TourOrder::getStatus, OrderStatus.PENDING_ACCEPT.getCode()) .isNotNull(TourOrder::getPaymentTime) .le(TourOrder::getPaymentTime, expiredBefore) .and(wrapper -> wrapper.isNull(TourOrder::getRefundStatus) .or().eq(TourOrder::getRefundStatus, RefundStatus.NONE.getCode())) .orderByAsc(TourOrder::getPaymentTime) .last("LIMIT " + BATCH_SIZE)); for (TourOrder order : orders) { refundIfStillUnaccepted(order.getId()); } } void refundIfStillUnaccepted(Long orderId) { if (orderMapper.claimUnacceptedOrderForRefund(orderId) != 1) { return; } TourOrder order = orderMapper.selectById(orderId); orderRefundService.requestRefund(order); } }