package com.tourguide.modules.order.service; 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 com.tourguide.modules.order.payment.PaymentRefundGateway; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.math.BigDecimal; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class OrderAutoRefundServiceTest { private TourOrderMapper orderMapper; private PaymentRefundGateway paymentRefundGateway; private OrderAutoRefundService autoRefundService; @BeforeEach void setUp() { orderMapper = mock(TourOrderMapper.class); paymentRefundGateway = mock(PaymentRefundGateway.class); autoRefundService = new OrderAutoRefundService( orderMapper, mock(PlatformSettingsService.class), paymentRefundGateway); } @Test void shouldRefundActualPaymentAmountAfterClaimingOrder() { TourOrder order = paidCancelledOrder(); when(orderMapper.claimUnacceptedOrderForRefund(9L)).thenReturn(1); when(orderMapper.selectById(9L)).thenReturn(order); when(paymentRefundGateway.refund(order, new BigDecimal("36.00"))).thenReturn("LOCALRF001"); autoRefundService.refundIfStillUnaccepted(9L); assertThat(order.getStatus()).isEqualTo(OrderStatus.CANCELLED.getCode()); assertThat(order.getRefundStatus()).isEqualTo(RefundStatus.REFUNDED.getCode()); assertThat(order.getRefundAmount()).isEqualByComparingTo("36.00"); assertThat(order.getRefundOrderNo()).isEqualTo("LOCALRF001"); assertThat(order.getRefundMethod()).isEqualTo("WECHAT"); assertThat(order.getRefundTime()).isNotNull(); verify(orderMapper).updateById(order); } @Test void shouldSkipRefundWhenOrderWasAlreadyAccepted() { when(orderMapper.claimUnacceptedOrderForRefund(9L)).thenReturn(0); autoRefundService.refundIfStillUnaccepted(9L); verify(orderMapper, never()).selectById(9L); verify(paymentRefundGateway, never()).refund(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any()); } @Test void shouldRecordFailureWhenPaymentGatewayIsUnavailable() { TourOrder order = paidCancelledOrder(); when(orderMapper.claimUnacceptedOrderForRefund(9L)).thenReturn(1); when(orderMapper.selectById(9L)).thenReturn(order); when(paymentRefundGateway.refund(order, new BigDecimal("36.00"))) .thenThrow(new IllegalStateException("not configured")); autoRefundService.refundIfStillUnaccepted(9L); assertThat(order.getRefundStatus()).isEqualTo(RefundStatus.REFUND_FAILED.getCode()); verify(orderMapper).updateById(order); } private TourOrder paidCancelledOrder() { TourOrder order = new TourOrder(); order.setId(9L); order.setOrderNo("MJ202607290009"); order.setStatus(OrderStatus.CANCELLED.getCode()); order.setPaymentMethod("WECHAT"); order.setPaymentOrderNo("LOCALMJ202607290009"); order.setAmount(new BigDecimal("40.00")); order.setPaymentAmount(new BigDecimal("36.00")); return order; } }