| | |
| | | package com.tourguide.modules.order.service; |
| | | |
| | | 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.domain.RefundAmountCalculator; |
| | | import com.tourguide.modules.order.domain.RefundStatus; |
| | | import com.tourguide.modules.order.entity.TourOrder; |
| | | import com.tourguide.modules.order.mapper.TourOrderMapper; |
| | |
| | | this.paymentRefundGateway = paymentRefundGateway; |
| | | } |
| | | |
| | | public void requestRefund(TourOrder order) { |
| | | if (order.getPaymentTime() == null || RefundStatus.REFUNDED.matches(order.getRefundStatus())) { |
| | | return; |
| | | public boolean requestRefund(TourOrder order) { |
| | | if (order == null) return false; |
| | | BigDecimal refundAmount = RefundAmountCalculator.refundableAmount(order); |
| | | return requestRefund(order, refundAmount); |
| | | } |
| | | |
| | | public boolean requestRefund(TourOrder order, BigDecimal refundAmount) { |
| | | if (order == null || order.getPaymentTime() == null) { |
| | | return false; |
| | | } |
| | | if (RefundStatus.REFUNDED.matches(order.getRefundStatus()) |
| | | || OrderStatus.REFUNDED.matches(order.getStatus())) { |
| | | return true; |
| | | } |
| | | if (RefundStatus.REFUNDING.matches(order.getRefundStatus()) |
| | | && StringUtils.hasText(order.getRefundOrderNo())) { |
| | | return; |
| | | return true; |
| | | } |
| | | BigDecimal refundAmount = order.getPaymentAmount() == null |
| | | ? order.getAmount() : order.getPaymentAmount(); |
| | | if (!StringUtils.hasText(order.getRefundOrderNo())) { |
| | | if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return false; |
| | | } |
| | | BigDecimal refundableAmount = RefundAmountCalculator.refundableAmount(order); |
| | | if (refundAmount.compareTo(refundableAmount) > 0) { |
| | | return false; |
| | | } |
| | | order.setRefundOrderNo(RequestSeqUtil.generateForBusiness("RF")); |
| | | } |
| | | order.setRefundStatus(RefundStatus.REFUNDING.getCode()); |
| | | order.setRefundAmount(refundAmount); |
| | | order.setRefundMethod(order.getPaymentMethod()); |
| | | if (PaymentMethod.TEMPORARY_BYPASS.matches(order.getPaymentMethod())) { |
| | | order.setRefundStatus(RefundStatus.REFUNDED.getCode()); |
| | | if (order.getCancelledAt() == null) order.setCancelledAt(LocalDateTime.now()); |
| | | completeLocalRefund(order, refundAmount); |
| | | order.setRefundTime(LocalDateTime.now()); |
| | | orderMapper.updateById(order); |
| | | return; |
| | | return true; |
| | | } |
| | | orderMapper.updateById(order); |
| | | try { |
| | | paymentRefundGateway.refund(order, refundAmount); |
| | | String refundRequestNo = paymentRefundGateway.refund(order, refundAmount); |
| | | if (!StringUtils.hasText(refundRequestNo)) { |
| | | throw new IllegalStateException("Payment provider did not accept refund request"); |
| | | } |
| | | if (!OrderStatus.CANCELLED.matches(order.getStatus())) { |
| | | order.setStatus(OrderStatus.CANCELLED.getCode()); |
| | | } |
| | | if (order.getCancelledAt() == null) order.setCancelledAt(LocalDateTime.now()); |
| | | orderMapper.updateById(order); |
| | | return true; |
| | | } catch (RuntimeException exception) { |
| | | order.setRefundStatus(RefundStatus.REFUND_FAILED.getCode()); |
| | | orderMapper.updateById(order); |
| | | log.error("Order refund request failed, orderId={}, orderNo={}, refundOrderNo={}", |
| | | order.getId(), order.getOrderNo(), order.getRefundOrderNo(), exception); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | private void completeLocalRefund(TourOrder order, BigDecimal refundAmount) { |
| | | BigDecimal refundedAmount = RefundAmountCalculator.refundedAmount(order).add(refundAmount); |
| | | order.setRefundedAmount(refundedAmount); |
| | | if (refundedAmount.compareTo(RefundAmountCalculator.paidAmount(order)) >= 0) { |
| | | order.setRefundStatus(RefundStatus.REFUNDED.getCode()); |
| | | order.setStatus(OrderStatus.REFUNDED.getCode()); |
| | | } else { |
| | | order.setRefundStatus(RefundStatus.PARTIAL.getCode()); |
| | | order.setStatus(OrderStatus.CANCELLED.getCode()); |
| | | } |
| | | } |
| | | } |