package com.tourguide.modules.finance.service; import com.tourguide.common.exception.BusinessException; 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.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; /** 将到期且未分账的订单收益幂等计入导游余额。 */ @Service public class GuideBalanceSettlementService { private final TourOrderMapper orderMapper; private final GuideWithdrawableBalanceService balanceService; public GuideBalanceSettlementService(TourOrderMapper orderMapper, GuideWithdrawableBalanceService balanceService) { this.orderMapper = orderMapper; this.balanceService = balanceService; } @Transactional public boolean settle(Long orderId, LocalDateTime settledAt) { TourOrder order = orderMapper.selectForUpdate(orderId); if (!canSettle(order, settledAt)) return false; BigDecimal earning = order.getGuideEarningAmount(); if (earning.signum() > 0) { balanceService.credit(order.getGuideId(), earning); } order.setSettledAt(settledAt); if (orderMapper.updateById(order) != 1) { throw new BusinessException(500, "订单分账状态更新失败"); } return true; } private boolean canSettle(TourOrder order, LocalDateTime now) { return order != null && OrderStatus.COMPLETED.matches(order.getStatus()) && order.getSettledAt() == null && order.getSettlementDueAt() != null && !order.getSettlementDueAt().isAfter(now) && order.getGuideId() != null && order.getGuideEarningAmount() != null && order.getGuideEarningAmount().signum() >= 0 && !RefundStatus.REFUNDED.matches(order.getRefundStatus()); } }