From 39f6fca28e3f78abe48f08e474ec011abb990b36 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期三, 09 九月 2026 10:39:21 +0800
Subject: [PATCH] update

---
 backend/src/main/java/com/tourguide/modules/order/service/TourOrderService.java |   59 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 38 insertions(+), 21 deletions(-)

diff --git a/backend/src/main/java/com/tourguide/modules/order/service/TourOrderService.java b/backend/src/main/java/com/tourguide/modules/order/service/TourOrderService.java
index 6f966d8..9a26247 100644
--- a/backend/src/main/java/com/tourguide/modules/order/service/TourOrderService.java
+++ b/backend/src/main/java/com/tourguide/modules/order/service/TourOrderService.java
@@ -6,37 +6,42 @@
 import com.tourguide.common.exception.BusinessException;
 import com.tourguide.modules.order.dto.TourOrderResponse;
 import com.tourguide.modules.order.domain.OrderStatus;
+import com.tourguide.modules.order.domain.RefundAmountCalculator;
 import com.tourguide.modules.order.domain.RefundStatus;
 import com.tourguide.modules.order.entity.TourOrder;
 import com.tourguide.modules.order.mapper.TourOrderMapper;
 import com.tourguide.modules.system.service.GuideNotificationService;
 import com.tourguide.modules.review.entity.OrderReview;
 import com.tourguide.modules.review.mapper.OrderReviewMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import java.math.BigDecimal;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.List;
-import java.util.UUID;
 import java.util.stream.Collectors;
 
 @Service
 public class TourOrderService {
+    private static final Logger log = LoggerFactory.getLogger(TourOrderService.class);
+
     private final TourOrderMapper orderMapper;
     private final OrderReviewMapper reviewMapper;
     private final GuideNotificationService notificationService;
+    private final OrderRefundService orderRefundService;
 
     public TourOrderService(TourOrderMapper orderMapper, OrderReviewMapper reviewMapper,
-                            GuideNotificationService notificationService) {
+                            GuideNotificationService notificationService,
+                            OrderRefundService orderRefundService) {
         this.orderMapper = orderMapper;
         this.reviewMapper = reviewMapper;
         this.notificationService = notificationService;
+        this.orderRefundService = orderRefundService;
     }
 
-    public PageResponse<TourOrderResponse> page(long page, long size, String keyword, Long visitorId,
+    public PageResponse<TourOrderResponse> page(long page, long size, String keyword, Long visitorId, Long guideId,
                                                 String scenicName, String status,
                                                 LocalDate startDate, LocalDate endDate) {
         LambdaQueryWrapper<TourOrder> query = new LambdaQueryWrapper<TourOrder>();
@@ -49,6 +54,7 @@
                     .or().like(TourOrder::getGuideMobile, searchKeyword));
         }
         query.eq(visitorId != null, TourOrder::getVisitorId, visitorId)
+                .eq(guideId != null, TourOrder::getGuideId, guideId)
                 .eq(StringUtils.hasText(scenicName), TourOrder::getScenicName, scenicName)
                 .eq(StringUtils.hasText(status), TourOrder::getStatus, status)
                 .ge(startDate != null, TourOrder::getCreatedAt, startDate == null ? null : startDate.atStartOfDay())
@@ -64,6 +70,7 @@
         TourOrder order = requireOrder(id);
         OrderReview review = reviewMapper.selectOne(new LambdaQueryWrapper<OrderReview>()
                 .eq(OrderReview::getOrderId, id)
+                .eq(OrderReview::getStatus, 1)
                 .last("LIMIT 1"));
         return TourOrderResponse.from(order, review);
     }
@@ -72,20 +79,31 @@
         return orderMapper.selectScenicOptions();
     }
 
-    @Transactional
+    @Transactional(noRollbackFor = BusinessException.class)
     public TourOrderResponse refund(Long id, BigDecimal refundAmount) {
         TourOrder order = requireOrderForUpdate(id);
         boolean notifyGuide = OrderStatus.PENDING_MEETING.matches(order.getStatus()) && order.getGuideId() != null;
         if (OrderStatus.REFUNDED.matches(order.getStatus()) || RefundStatus.REFUNDED.matches(order.getRefundStatus())) {
             throw new BusinessException(409, "订单已退款,请勿重复操作");
         }
-        if (OrderStatus.CANCELLED.matches(order.getStatus())) {
+        if (order.getPaymentTime() == null) {
+            throw new BusinessException(409, "未支付订单不能退款");
+        }
+        if (RefundStatus.REFUNDING.matches(order.getRefundStatus())) {
+            throw new BusinessException(409, "退款正在处理中,请勿重复操作");
+        }
+        if (OrderStatus.CANCELLED.matches(order.getStatus())
+                && !RefundStatus.REFUND_FAILED.matches(order.getRefundStatus())
+                && !RefundStatus.PARTIAL.matches(order.getRefundStatus())) {
             throw new BusinessException(409, "已取消订单不能退款");
         }
-        if (!OrderStatus.isRefundable(order.getStatus())) {
+        boolean followUpRefund = OrderStatus.CANCELLED.matches(order.getStatus())
+                && (RefundStatus.REFUND_FAILED.matches(order.getRefundStatus())
+                || RefundStatus.PARTIAL.matches(order.getRefundStatus()));
+        if (!OrderStatus.isRefundable(order.getStatus()) && !followUpRefund) {
             throw new BusinessException(409, "当前订单状态不支持退款");
         }
-        BigDecimal refundableAmount = order.getPaymentAmount() == null ? order.getAmount() : order.getPaymentAmount();
+        BigDecimal refundableAmount = RefundAmountCalculator.refundableAmount(order);
         if (refundableAmount == null || refundableAmount.compareTo(BigDecimal.ZERO) <= 0) {
             throw new BusinessException(409, "订单无可退金额");
         }
@@ -95,14 +113,17 @@
         if (refundAmount.compareTo(refundableAmount) > 0) {
             throw new BusinessException(400, "退款金额不能超过当前可退金额");
         }
-        order.setRefundStatus(RefundStatus.REFUNDED.getCode());
-        order.setStatus(OrderStatus.REFUNDED.getCode());
-        order.setRefundAmount(refundAmount);
-        order.setRefundTime(LocalDateTime.now());
-        order.setRefundOrderNo(generateRefundOrderNo());
-        order.setRefundMethod(order.getPaymentMethod());
-        orderMapper.updateById(order);
-        if (notifyGuide) notificationService.notifyOrderCancelled(order);
+        if (!orderRefundService.requestRefund(order, refundAmount)) {
+            throw new BusinessException(502, "支付渠道退款失败,请稍后重试");
+        }
+        if (notifyGuide) {
+            try {
+                notificationService.notifyOrderCancelled(order);
+            } catch (RuntimeException exception) {
+                log.warn("Failed to notify guide after refund submission, orderId={}, guideId={}",
+                        order.getId(), order.getGuideId(), exception);
+            }
+        }
         return TourOrderResponse.from(order);
     }
 
@@ -122,8 +143,4 @@
         return order;
     }
 
-    private String generateRefundOrderNo() {
-        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
-        return "RF" + time + UUID.randomUUID().toString().replace("-", "").substring(0, 6).toUpperCase();
-    }
 }

--
Gitblit v1.7.1