fix: calculate jt808 daily mileage from metric endpoints

This commit is contained in:
lingniu
2026-07-01 09:52:24 +08:00
parent bb051391c2
commit 0236884f81
7 changed files with 53 additions and 15 deletions

View File

@@ -60,7 +60,7 @@ public final class JdbcVehicleStatMetricRepository implements VehicleStatReposit
DailyMileageState existingState = findDailyMileageState(normalizedVin, date).orElse(null);
double firstTotalMileage = existingState == null || !Double.isFinite(existingState.firstTotalMileageKm())
? totalMileageKm
: existingState.firstTotalMileageKm();
: Math.min(existingState.firstTotalMileageKm(), totalMileageKm);
double latestTotalMileage = existingState == null || !Double.isFinite(existingState.latestTotalMileageKm())
? totalMileageKm
: Math.max(existingState.latestTotalMileageKm(), totalMileageKm);

View File

@@ -116,6 +116,37 @@ class JdbcVehicleStatMetricRepositoryTest {
""", Double.class)).isEqualTo(9.5);
}
@Test
void recalculatesJt808MileageWhenEarlierLowerMileageArrivesAfterRestart() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(new DriverManagerDataSource(
"jdbc:h2:mem:vehicle_stat_metric_jt808_replay_lower;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1",
"sa",
""));
JdbcVehicleStatMetricRepository repository = new JdbcVehicleStatMetricRepository(jdbcTemplate);
repository.recordDailyMileageSample("VIN001", LocalDate.of(2026, 7, 1), 1010.0).orElseThrow();
JdbcVehicleStatMetricRepository restartedRepository = new JdbcVehicleStatMetricRepository(jdbcTemplate);
VehicleDailyStatResult replayedEarlierSample = restartedRepository.recordDailyMileageSample(
"VIN001", LocalDate.of(2026, 7, 1), 1000.5).orElseThrow();
assertThat(replayedEarlierSample.dailyMileageKm()).hasValue(9.5);
assertThat(jdbcTemplate.queryForObject("""
SELECT first_total_mileage_km
FROM vehicle_stat_metric
WHERE vin = 'VIN001' AND metric_key = 'daily_mileage_km'
""", Double.class)).isEqualTo(1000.5);
assertThat(jdbcTemplate.queryForObject("""
SELECT latest_total_mileage_km
FROM vehicle_stat_metric
WHERE vin = 'VIN001' AND metric_key = 'daily_mileage_km'
""", Double.class)).isEqualTo(1010.0);
assertThat(jdbcTemplate.queryForObject("""
SELECT COUNT(*)
FROM vehicle_stat_metric
WHERE vin = 'VIN001' AND stat_date = DATE '2026-07-01'
""", Integer.class)).isOne();
}
@Test
void ignoresLegacySplitMileageStateMetricsWhenRecordingNewGpsTotalMileage() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(new DriverManagerDataSource(
@@ -145,6 +176,11 @@ class JdbcVehicleStatMetricRepositoryTest {
FROM vehicle_stat_metric
WHERE vin = 'VIN001' AND metric_key = 'daily_mileage_km'
""", Double.class)).isEqualTo(110.0);
assertThat(jdbcTemplate.queryForObject("""
SELECT COUNT(*)
FROM vehicle_stat_metric
WHERE vin = 'VIN001' AND stat_date = DATE '2026-07-01'
""", Integer.class)).isOne();
}
@Test

View File

@@ -26,7 +26,7 @@ class VehicleStatRepositoryContractTest {
assertThat(plan)
.contains("Runtime state: none outside `vehicle_stat_metric`")
.contains("daily_mileage_km = last_total_mileage_km - first_total_mileage_km")
.contains("daily_mileage_km = max_total_mileage_km - min_total_mileage_km")
.contains("Do not create or write a protocol-specific JT808 daily-mileage table.")
.doesNotContain("Redis `Jt808MileageStateStore`")
.doesNotContain("REDIS_HOST")