package com.tourguide.modules.order.service; import com.tourguide.common.exception.BusinessException; import com.tourguide.common.huifu.RequestSeqUtil; import com.tourguide.modules.order.domain.OrderStatus; import com.tourguide.modules.order.domain.PaymentMethod; import com.tourguide.modules.order.entity.TourOrder; import com.tourguide.modules.order.entity.TourOrderPaymentAttempt; import com.tourguide.modules.order.mapper.TourOrderMapper; import com.tourguide.modules.order.mapper.TourOrderPaymentAttemptMapper; import com.tourguide.modules.order.payment.HuifuPaymentNotice; import com.tourguide.modules.order.payment.OrderPaymentPreparation; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @Service public class TourOrderPaymentService { private static final DateTimeFormatter REQUEST_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd"); private static final String ATTEMPT_CREATED = "CREATED"; private static final String ATTEMPT_SUCCEEDED = "SUCCEEDED"; private final TourOrderMapper orderMapper; private final TourOrderPaymentAttemptMapper paymentAttemptMapper; private final GuideOrderMatchingService matchingService; public TourOrderPaymentService(TourOrderMapper orderMapper, TourOrderPaymentAttemptMapper paymentAttemptMapper, GuideOrderMatchingService matchingService) { this.orderMapper = orderMapper; this.paymentAttemptMapper = paymentAttemptMapper; this.matchingService = matchingService; } @Transactional public OrderPaymentPreparation prepare(Long visitorId, Long orderId) { TourOrder order = orderMapper.selectForUpdate(orderId); if (order == null || visitorId == null || !visitorId.equals(order.getVisitorId())) { throw new BusinessException(404, "订单不存在"); } if (!OrderStatus.PENDING_PAYMENT.matches(order.getStatus())) { throw new BusinessException(409, "当前订单状态不支持支付"); } LocalDateTime now = LocalDateTime.now(); String reqDate = now.format(REQUEST_DATE_FORMAT); String reqSeqId = RequestSeqUtil.generateForBusiness("PY"); TourOrderPaymentAttempt attempt = new TourOrderPaymentAttempt(); attempt.setOrderId(order.getId()); attempt.setReqSeqId(reqSeqId); attempt.setReqDate(reqDate); attempt.setAmount(order.getAmount()); attempt.setStatus(ATTEMPT_CREATED); paymentAttemptMapper.insert(attempt); order.setPaymentMethod(PaymentMethod.WECHAT.getCode()); order.setPaymentOrderNo(reqSeqId); orderMapper.updateById(order); String goodsDescription = StringUtils.hasText(order.getPackageName()) ? order.getScenicName() + "-" + order.getPackageName() : order.getScenicName() + "-讲解服务"; return new OrderPaymentPreparation(order.getId(), reqSeqId, reqDate, order.getAmount(), goodsDescription); } @Transactional public boolean confirm(HuifuPaymentNotice notice) { TourOrderPaymentAttempt attempt = paymentAttemptMapper.selectByReqSeqIdForUpdate(notice.getReqSeqId()); if (attempt == null) throw new BusinessException(404, "支付流水不存在"); TourOrder order = orderMapper.selectForUpdate(attempt.getOrderId()); if (order == null) throw new BusinessException(404, "支付订单不存在"); validateAmount(attempt.getAmount(), notice.getAmount()); validateAmount(order.getAmount(), notice.getAmount()); if (ATTEMPT_SUCCEEDED.equals(attempt.getStatus())) { return false; } LocalDateTime paidAt = notice.getPaidAt() == null ? LocalDateTime.now() : notice.getPaidAt(); attempt.setStatus(ATTEMPT_SUCCEEDED); attempt.setProviderTransactionId(notice.getProviderTransactionId()); attempt.setPaidAt(paidAt); paymentAttemptMapper.updateById(attempt); if (order.getPaymentTime() != null && !OrderStatus.PENDING_PAYMENT.matches(order.getStatus())) { return false; } if (!OrderStatus.PENDING_PAYMENT.matches(order.getStatus())) { throw new BusinessException(409, "订单状态不允许确认支付"); } order.setPaymentMethod(PaymentMethod.WECHAT.getCode()); order.setPaymentOrderNo(notice.getReqSeqId()); order.setPaymentAmount(notice.getAmount()); order.setPaymentTime(paidAt); order.setStatus(OrderStatus.PENDING_ACCEPT.getCode()); orderMapper.updateById(order); matchingService.match(order.getId()); return true; } private void validateAmount(BigDecimal expectedAmount, BigDecimal paidAmount) { if (expectedAmount == null || paidAmount == null || expectedAmount.compareTo(paidAmount) != 0) { throw new BusinessException(409, "支付金额与订单金额不一致"); } } }