From 8ad75d5872872b79abada58589adad0df4614db6 Mon Sep 17 00:00:00 2001
From: xyc <jc_xiong@hotmail.com>
Date: 星期三, 07 十月 2026 11:59:44 +0800
Subject: [PATCH] fix(holiday): 走势图按年度配置截取假期天数

---
 traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayComparisonBaseTest.java |  136 ++++++++++++++++++++++++++++++++++++---------
 1 files changed, 109 insertions(+), 27 deletions(-)

diff --git a/traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayComparisonBaseTest.java b/traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayComparisonBaseTest.java
index 62c7366..8dc3531 100644
--- a/traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayComparisonBaseTest.java
+++ b/traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayComparisonBaseTest.java
@@ -4,8 +4,10 @@
 import com.trafficaudit.holiday.HolidayNumberUtils;
 import com.trafficaudit.holiday.entity.HolidayCalendar;
 import com.trafficaudit.holiday.entity.HolidayPassengerFlow;
+import com.trafficaudit.holiday.entity.HolidayVehicleAdjustment;
 import com.trafficaudit.holiday.entity.HolidayVehicleFlow;
 import com.trafficaudit.holiday.mapper.HolidayPassengerFlowMapper;
+import com.trafficaudit.holiday.mapper.HolidayVehicleAdjustmentMapper;
 import com.trafficaudit.holiday.mapper.HolidayVehicleFlowMapper;
 import org.junit.jupiter.api.Test;
 
@@ -13,79 +15,159 @@
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 /**
- * The Excel comparison base column (C) is an operator backup value only: it must never change the
- * national/provincial ring ratio. This locks in that behaviour.
+ * Ring-ratio denominators are built one day at a time. The Excel comparison base (column C) is
+ * consumed on the source day and inherited by the next day's denominator, while historical
+ * adjustment records change only that historical day's same-day value.
  */
 class HolidayComparisonBaseTest {
 
     @Test
-    void ringRatioUsesPreviousDayEvenWhenComparisonBaseIsStored() throws Exception {
+    void comparisonBaseChangesOnlyTheNextDayRingRatioDenominator() throws Exception {
+        HolidayStatService service = serviceWithData(
+                2026,
+                passengerRows(2026, "50", "10", "6", "3"),
+                vehicleRows(2026),
+                Collections.<HolidayVehicleAdjustment>emptyList());
+
+        List<Map<String, Object>> rows = service.buildOverviewRows(
+                2026, HolidayConstants.TYPE_NATIONAL_DAY, calendar(2026));
+
+        assertEquals(new BigDecimal("323.7837"), rows.get(2).get("nationalProvincial"));
+        assertEquals(new BigDecimal("320.2418"), rows.get(2).get("comparisonBase"));
+        assertEquals(new BigDecimal("322.7695"), rows.get(3).get("nationalProvincial"));
+
+        BigDecimal nationalRatio = (BigDecimal) rows.get(3).get("nationalProvincialRingRatio");
+        assertEquals(ratio(new BigDecimal("322.7695"), new BigDecimal("320.2418")), nationalRatio);
+        assertNotEquals(ratio(new BigDecimal("322.7695"), new BigDecimal("323.7837")), nationalRatio);
+
+        HolidayStatService.DailyMetrics base = service.ringRatioBaseMetrics(
+                2026, HolidayConstants.TYPE_NATIONAL_DAY, 4);
+        assertNotNull(base);
+        assertEquals(new BigDecimal("320.2418"), base.getNationalProvincial());
+        assertDecimalEquals("1008.58032", base.getNonBusinessPersonFlow());
+        assertDecimalEquals("1058.58032", base.getRoadPersonFlow());
+        assertDecimalEquals("1077.58032", base.getTotalPersonFlow());
+    }
+
+    @Test
+    void historicalAdjustmentChangesTheHistoricalSameDayValue() throws Exception {
+        HolidayVehicleAdjustment adjustment = new HolidayVehicleAdjustment();
+        adjustment.setYear(2025);
+        adjustment.setFlowDate(LocalDate.of(2025, 10, 4));
+        adjustment.setAdjustedValue(new BigDecimal("337.5009"));
+
+        HolidayStatService service = serviceWithData(
+                2025,
+                passengerRows(2025, "50", "10", "6", "3"),
+                Arrays.asList(
+                        vehicle("2025-10-03", HolidayConstants.ROAD_EXPRESSWAY, "100", null),
+                        vehicle("2025-10-03", HolidayConstants.ROAD_NATIONAL_PROVINCIAL, "362.0035", null),
+                        vehicle("2025-10-04", HolidayConstants.ROAD_EXPRESSWAY, "110", null),
+                        vehicle("2025-10-04", HolidayConstants.ROAD_NATIONAL_PROVINCIAL, "350.0000", null)),
+                Collections.singletonList(adjustment));
+
+        List<Map<String, Object>> rows = service.buildOverviewRows(
+                2025, HolidayConstants.TYPE_NATIONAL_DAY, calendar(2025));
+
+        assertEquals(new BigDecimal("337.5009"), rows.get(3).get("nationalProvincial"));
+    }
+
+    private static HolidayStatService serviceWithData(int year,
+                                                      List<HolidayPassengerFlow> passengerRows,
+                                                      List<HolidayVehicleFlow> vehicleRows,
+                                                      List<HolidayVehicleAdjustment> adjustments) throws Exception {
         HolidayConfigService configService = mock(HolidayConfigService.class);
         HolidayPassengerFlowMapper passengerMapper = mock(HolidayPassengerFlowMapper.class);
         HolidayVehicleFlowMapper vehicleMapper = mock(HolidayVehicleFlowMapper.class);
+        HolidayVehicleAdjustmentMapper adjustmentMapper = mock(HolidayVehicleAdjustmentMapper.class);
 
-        when(configService.coefficientOf(2026, HolidayConstants.CATEGORY_HOLIDAY)).thenReturn(new BigDecimal("2.4"));
-        when(passengerMapper.selectList(any())).thenReturn(new ArrayList<HolidayPassengerFlow>());
-        when(vehicleMapper.selectList(any())).thenReturn(vehicleRows());
+        when(configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY)).thenReturn(new BigDecimal("2.4"));
+        when(configService.findHolidayDays(year, HolidayConstants.TYPE_NATIONAL_DAY)).thenReturn(calendar(year));
+        when(passengerMapper.selectList(any())).thenReturn(passengerRows);
+        when(vehicleMapper.selectList(any())).thenReturn(vehicleRows);
+        when(adjustmentMapper.selectList(any())).thenReturn(adjustments);
 
         HolidayStatService service = new HolidayStatService();
         inject(service, "configService", configService);
         inject(service, "passengerFlowMapper", passengerMapper);
         inject(service, "vehicleFlowMapper", vehicleMapper);
-
-        List<Map<String, Object>> rows = service.buildOverviewRows(2026, HolidayConstants.TYPE_NATIONAL_DAY, calendar());
-
-        BigDecimal ringRatio = (BigDecimal) rows.get(3).get("nationalProvincialRingRatio");
-        assertEquals(ratio(new BigDecimal("322.7695"), new BigDecimal("323.7837")), ringRatio);
-        assertNotEquals(ratio(new BigDecimal("322.7695"), new BigDecimal("320.2418")), ringRatio);
-        assertEquals(new BigDecimal("320.2418"), rows.get(2).get("comparisonBase"));
-    }
-
-    @Test
-    void exportFormulaComparesPreviousRowInsteadOfComparisonBaseColumn() {
-        assertEquals("=(D6-D5)/D5", HolidayWorkbookService.ringRatioFormula(6, 5));
+        inject(service, "vehicleAdjustmentMapper", adjustmentMapper);
+        return service;
     }
 
     private static BigDecimal ratio(BigDecimal current, BigDecimal base) {
         return HolidayNumberUtils.normalize(HolidayNumberUtils.divide(current, base).subtract(BigDecimal.ONE));
     }
 
-    private static List<HolidayVehicleFlow> vehicleRows() {
+    private static void assertDecimalEquals(String expected, BigDecimal actual) {
+        assertNotNull(actual);
+        assertEquals(0, new BigDecimal(expected).compareTo(actual));
+    }
+
+    private static List<HolidayVehicleFlow> vehicleRows(int year) {
         List<HolidayVehicleFlow> rows = new ArrayList<>();
-        rows.add(vehicle("2026-10-03", "323.7837", "320.2418"));
-        rows.add(vehicle("2026-10-04", "322.7695", null));
+        rows.add(vehicle(year + "-10-03", HolidayConstants.ROAD_EXPRESSWAY, "100", null));
+        rows.add(vehicle(year + "-10-03", HolidayConstants.ROAD_NATIONAL_PROVINCIAL, "323.7837", "320.2418"));
+        rows.add(vehicle(year + "-10-04", HolidayConstants.ROAD_EXPRESSWAY, "110", null));
+        rows.add(vehicle(year + "-10-04", HolidayConstants.ROAD_NATIONAL_PROVINCIAL, "322.7695", null));
         return rows;
     }
 
-    private static HolidayVehicleFlow vehicle(String date, String value, String base) {
+    private static HolidayVehicleFlow vehicle(String date, String roadCategory, String value, String base) {
         HolidayVehicleFlow row = new HolidayVehicleFlow();
-        row.setYear(2026);
+        row.setYear(LocalDate.parse(date).getYear());
         row.setFlowDate(LocalDate.parse(date));
-        row.setRoadCategory(HolidayConstants.ROAD_NATIONAL_PROVINCIAL);
+        row.setRoadCategory(roadCategory);
         row.setVehicleType(HolidayConstants.VEHICLE_MEDIUM_SMALL_PASSENGER);
         row.setVehicleCount(new BigDecimal(value));
         row.setComparisonBase(base == null ? null : new BigDecimal(base));
         return row;
     }
 
-    private static List<HolidayCalendar> calendar() {
+    private static List<HolidayPassengerFlow> passengerRows(int year, String road, String rail,
+                                                            String civilAviation, String water) {
+        List<HolidayPassengerFlow> rows = new ArrayList<>();
+        rows.add(passenger(year + "-10-03", HolidayConstants.MODE_ROAD, road));
+        rows.add(passenger(year + "-10-03", HolidayConstants.MODE_RAIL, rail));
+        rows.add(passenger(year + "-10-03", HolidayConstants.MODE_CIVIL_AVIATION, civilAviation));
+        rows.add(passenger(year + "-10-03", HolidayConstants.MODE_WATER, water));
+        rows.add(passenger(year + "-10-04", HolidayConstants.MODE_ROAD, road));
+        rows.add(passenger(year + "-10-04", HolidayConstants.MODE_RAIL, rail));
+        rows.add(passenger(year + "-10-04", HolidayConstants.MODE_CIVIL_AVIATION, civilAviation));
+        rows.add(passenger(year + "-10-04", HolidayConstants.MODE_WATER, water));
+        return rows;
+    }
+
+    private static HolidayPassengerFlow passenger(String date, String mode, String value) {
+        HolidayPassengerFlow row = new HolidayPassengerFlow();
+        row.setYear(LocalDate.parse(date).getYear());
+        row.setFlowDate(LocalDate.parse(date));
+        row.setTransportMode(mode);
+        row.setPassengerCount(new BigDecimal(value));
+        return row;
+    }
+
+    private static List<HolidayCalendar> calendar(int year) {
         List<HolidayCalendar> days = new ArrayList<>();
         for (int i = 1; i <= 4; i++) {
             HolidayCalendar day = new HolidayCalendar();
-            day.setYear(2026);
+            day.setYear(year);
             day.setHolidayType(HolidayConstants.TYPE_NATIONAL_DAY);
             day.setDayIndex(i);
-            day.setHolidayDate(LocalDate.of(2026, 10, i));
+            day.setHolidayDate(LocalDate.of(year, 10, i));
             days.add(day);
         }
         return days;

--
Gitblit v1.9.1