package com.tcm.training.admin.statistics.service; import com.tcm.training.admin.statistics.mapper.RevenueStatisticsMapper; import com.tcm.training.admin.statistics.row.RevenueStatisticsDailyRow; import com.tcm.training.admin.statistics.vo.RevenueStatisticsVO; import com.tcm.training.admin.trade.service.PaymentFlowAppService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class RevenueStatisticsAppServiceTest { @Mock private RevenueStatisticsMapper revenueStatisticsMapper; @Mock private PaymentFlowAppService paymentFlowAppService; @InjectMocks private RevenueStatisticsAppService revenueStatisticsAppService; @Test void statisticsShouldBuildOverviewAndFillMissingDates() { RevenueStatisticsDailyRow row = new RevenueStatisticsDailyRow(); row.setStatDate(LocalDate.of(2026, 3, 1)); row.setHealthIncome(new BigDecimal("100.00")); row.setMemberIncome(new BigDecimal("50.00")); row.setHealthRefundAmount(new BigDecimal("12.00")); row.setMemberRefundAmount(new BigDecimal("8.00")); when(revenueStatisticsMapper.selectDailyStatistics( eq(null), eq(LocalDateTime.of(2026, 3, 1, 0, 0, 0)), eq(LocalDateTime.of(2026, 3, 3, LocalTime.MAX.getHour(), LocalTime.MAX.getMinute(), LocalTime.MAX.getSecond(), LocalTime.MAX.getNano())) )).thenReturn(Collections.singletonList(row)); RevenueStatisticsVO result = revenueStatisticsAppService.statistics( "ALL", LocalDate.of(2026, 3, 1), LocalDate.of(2026, 3, 3) ); verify(paymentFlowAppService).syncFlows(); assertEquals(3, result.getTrend().size()); assertEquals(new BigDecimal("150.00"), result.getOverview().getTotalIncome()); assertEquals(new BigDecimal("100.00"), result.getOverview().getHealthIncome()); assertEquals(new BigDecimal("50.00"), result.getOverview().getMemberIncome()); assertEquals(new BigDecimal("20.00"), result.getOverview().getRefundAmount()); assertEquals(new BigDecimal("130.00"), result.getOverview().getProfit()); assertEquals(new BigDecimal("0"), result.getTrend().get(1).getTotalIncome()); assertEquals(new BigDecimal("12.00"), result.getTrend().get(0).getHealthRefundAmount()); assertEquals(new BigDecimal("8.00"), result.getTrend().get(0).getMemberRefundAmount()); } @Test void statisticsShouldUseHealthTypeFilter() { RevenueStatisticsDailyRow row = new RevenueStatisticsDailyRow(); row.setStatDate(LocalDate.of(2026, 3, 5)); row.setHealthIncome(new BigDecimal("88.00")); row.setMemberIncome(BigDecimal.ZERO); row.setHealthRefundAmount(new BigDecimal("8.00")); row.setMemberRefundAmount(BigDecimal.ZERO); when(revenueStatisticsMapper.selectDailyStatistics( eq("COURSE_PURCHASE"), eq(LocalDateTime.of(2026, 3, 5, 0, 0, 0)), eq(LocalDateTime.of(2026, 3, 5, LocalTime.MAX.getHour(), LocalTime.MAX.getMinute(), LocalTime.MAX.getSecond(), LocalTime.MAX.getNano())) )).thenReturn(Collections.singletonList(row)); RevenueStatisticsVO result = revenueStatisticsAppService.statistics( "HEALTH", LocalDate.of(2026, 3, 5), LocalDate.of(2026, 3, 5) ); assertEquals(new BigDecimal("88.00"), result.getOverview().getTotalIncome()); assertEquals(new BigDecimal("88.00"), result.getOverview().getHealthIncome()); assertEquals(new BigDecimal("0"), result.getOverview().getMemberIncome()); assertEquals(new BigDecimal("8.00"), result.getOverview().getRefundAmount()); assertEquals(new BigDecimal("80.00"), result.getOverview().getProfit()); } @Test void statisticsShouldRejectInvalidType() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> revenueStatisticsAppService.statistics("OTHER", LocalDate.of(2026, 3, 1), LocalDate.of(2026, 3, 1))); assertEquals("统计类型不合法", exception.getMessage()); } @Test void statisticsShouldRejectInvalidDateRange() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> revenueStatisticsAppService.statistics("ALL", LocalDate.of(2026, 3, 10), LocalDate.of(2026, 3, 1))); assertEquals("开始日期不能晚于结束日期", exception.getMessage()); } }