fix(analytics): count summary achievements by activity period

Signed-off-by: Marcus Fihlon <marcus@fihlon.swiss>
This commit is contained in:
Marcus Fihlon 2026-04-29 09:54:31 +02:00
parent 6af484bcf7
commit 10037de043
Signed by: McPringle
GPG key ID: C6B7F469EE363E1F
3 changed files with 113 additions and 1 deletions

View file

@ -60,6 +60,23 @@ public interface AchievementRepository extends JpaRepository<Achievement, UUID>
@Param("endDate") LocalDateTime endDate
);
/**
* Count achievements whose triggering activity started within a date range.
*/
@Query(value = """
SELECT COUNT(*)
FROM achievements ach
JOIN activities act ON act.id = ach.activity_id
WHERE ach.user_id = :userId
AND act.started_at >= :startDate
AND act.started_at < :endDate
""", nativeQuery = true)
long countByUserIdAndActivityStartedDateRange(
@Param("userId") UUID userId,
@Param("startDate") LocalDateTime startDate,
@Param("endDate") LocalDateTime endDate
);
/**
* Find recent achievements for a user.
*/

View file

@ -172,7 +172,7 @@ public class ActivitySummaryService {
startDateTime,
endDateTime
);
long achievementsEarned = achievementRepository.countByUserIdAndDateRange(
long achievementsEarned = achievementRepository.countByUserIdAndActivityStartedDateRange(
userId,
startDateTime,
endDateTime

View file

@ -0,0 +1,95 @@
package net.javahippie.fitpub.service;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.ActivitySummary;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.ActivitySummaryRepository;
import net.javahippie.fitpub.repository.AchievementRepository;
import net.javahippie.fitpub.repository.PersonalRecordRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ActivitySummaryServiceTest {
@Mock
private ActivitySummaryRepository activitySummaryRepository;
@Mock
private ActivityRepository activityRepository;
@Mock
private PersonalRecordRepository personalRecordRepository;
@Mock
private AchievementRepository achievementRepository;
@InjectMocks
private ActivitySummaryService activitySummaryService;
private UUID userId;
@BeforeEach
void setUp() {
userId = UUID.randomUUID();
}
@Test
@DisplayName("Should count achievements in summaries by triggering activity start date")
void testUpdateWeeklySummary_CountsAchievementsByActivityStartDate() {
LocalDate weekDate = LocalDate.of(2025, 12, 3);
LocalDate weekStart = LocalDate.of(2025, 12, 1);
LocalDateTime startDateTime = weekStart.atStartOfDay();
LocalDateTime endDateTime = weekStart.plusDays(7).atStartOfDay();
Activity activity = Activity.builder()
.id(UUID.randomUUID())
.userId(userId)
.activityType(Activity.ActivityType.RUN)
.startedAt(LocalDateTime.of(2025, 12, 3, 23, 30))
.endedAt(LocalDateTime.of(2025, 12, 4, 0, 15))
.totalDistance(BigDecimal.valueOf(5000))
.totalDurationSeconds(2700L)
.elevationGain(BigDecimal.valueOf(120))
.build();
when(activitySummaryRepository.findByUserIdAndPeriodTypeAndPeriodStart(
userId,
ActivitySummary.PeriodType.WEEK,
weekStart
)).thenReturn(Optional.empty());
when(activityRepository.findByUserIdAndStartedAtBetweenOrderByStartedAtDesc(
userId,
startDateTime,
endDateTime
)).thenReturn(List.of(activity));
when(personalRecordRepository.countByUserIdAndDateRange(userId, startDateTime, endDateTime)).thenReturn(0L);
when(achievementRepository.countByUserIdAndActivityStartedDateRange(userId, startDateTime, endDateTime)).thenReturn(1L);
when(activitySummaryRepository.save(org.mockito.ArgumentMatchers.any(ActivitySummary.class)))
.thenAnswer(invocation -> invocation.getArgument(0));
activitySummaryService.updateWeeklySummary(userId, weekDate);
verify(achievementRepository).countByUserIdAndActivityStartedDateRange(userId, startDateTime, endDateTime);
verify(activitySummaryRepository).save(org.mockito.ArgumentMatchers.argThat(summary ->
summary.getAchievementsEarned() == 1 &&
summary.getActivityCount() == 1
));
}
}