diff --git a/src/main/kotlin/com/moa/repository/NotificationLogRepository.kt b/src/main/kotlin/com/moa/repository/NotificationLogRepository.kt index 05d32b9..07fc84b 100644 --- a/src/main/kotlin/com/moa/repository/NotificationLogRepository.kt +++ b/src/main/kotlin/com/moa/repository/NotificationLogRepository.kt @@ -4,6 +4,7 @@ import com.moa.entity.notification.NotificationLog import com.moa.entity.notification.NotificationStatus import com.moa.entity.notification.NotificationType import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query import java.time.LocalDate import java.time.LocalTime @@ -33,14 +34,16 @@ interface NotificationLogRepository : JpaRepository { notificationTypes: Collection, ): List - fun existsByMemberIdAndScheduledDateAndStatus( - memberId: Long, - scheduledDate: LocalDate, - status: NotificationStatus, - ): Boolean - - fun existsByScheduledDateAndNotificationType( + @Query( + "select distinct n.memberId " + + "from NotificationLog n " + + "where n.scheduledDate = :scheduledDate " + + "and n.notificationType = :notificationType " + + "and n.memberId in :memberIds" + ) + fun findMemberIdsByScheduledDateAndNotificationTypeAndMemberIdIn( scheduledDate: LocalDate, notificationType: NotificationType, - ): Boolean + memberIds: Collection, + ): List } diff --git a/src/main/kotlin/com/moa/service/notification/NotificationBatchService.kt b/src/main/kotlin/com/moa/service/notification/NotificationBatchService.kt index d6e314b..63a8d1c 100644 --- a/src/main/kotlin/com/moa/service/notification/NotificationBatchService.kt +++ b/src/main/kotlin/com/moa/service/notification/NotificationBatchService.kt @@ -1,7 +1,7 @@ package com.moa.service.notification -import com.moa.entity.Workday import com.moa.entity.WorkPolicyVersion +import com.moa.entity.Workday import com.moa.entity.notification.NotificationLog import com.moa.entity.notification.NotificationSettingType import com.moa.entity.notification.NotificationType @@ -30,8 +30,6 @@ class NotificationBatchService( @Transactional fun generateNotificationsForDate(date: LocalDate) { - if (isAlreadyGenerated(date)) return - if (publicHolidayService.isHoliday(date)) { generateHolidayNotifications(date) } else { @@ -43,13 +41,21 @@ class NotificationBatchService( val allPolicies = workPolicyVersionRepository.findLatestEffectivePoliciesPerMember(date) if (allPolicies.isEmpty()) return - val memberIds = allPolicies.map { it.memberId } + val allMemberIds = allPolicies.map { it.memberId } + val alreadyGeneratedMemberIds = notificationLogRepository + .findMemberIdsByScheduledDateAndNotificationTypeAndMemberIdIn(date, NotificationType.PUBLIC_HOLIDAY, allMemberIds) + .toSet() + + val targetPolicies = allPolicies.filter { it.memberId !in alreadyGeneratedMemberIds } + if (targetPolicies.isEmpty()) return + + val memberIds = targetPolicies.map { it.memberId } val requiredTermCodes = notificationEligibilityService.findRequiredTermCodes() val context = notificationEligibilityService.loadContext(memberIds, date) log.info("Generating public holiday notifications for {} members on {}", memberIds.size, date) - val notifications = allPolicies.mapNotNull { policy -> + val notifications = targetPolicies.mapNotNull { policy -> createHolidayNotificationIfEligible(policy.memberId, date, requiredTermCodes, context) } @@ -74,13 +80,21 @@ class NotificationBatchService( val workdayPolicies = findWorkdayPolicies(date) if (workdayPolicies.isEmpty()) return - val memberIds = workdayPolicies.map { it.memberId } + val workdayMemberIds = workdayPolicies.map { it.memberId } + val alreadyGeneratedMemberIds = notificationLogRepository + .findMemberIdsByScheduledDateAndNotificationTypeAndMemberIdIn(date, NotificationType.CLOCK_IN, workdayMemberIds) + .toSet() + + val targetPolicies = workdayPolicies.filter { it.memberId !in alreadyGeneratedMemberIds } + if (targetPolicies.isEmpty()) return + + val memberIds = targetPolicies.map { it.memberId } val requiredTermCodes = notificationEligibilityService.findRequiredTermCodes() val context = notificationEligibilityService.loadContext(memberIds, date) log.info("Generating notifications for {} members on {}", memberIds.size, date) - val notifications = workdayPolicies.mapNotNull { policy -> + val notifications = targetPolicies.mapNotNull { policy -> createNotificationsIfEligible(policy, date, requiredTermCodes, context) }.flatten() @@ -88,15 +102,6 @@ class NotificationBatchService( log.info("Created {} notification logs for {}", notifications.size, date) } - private fun isAlreadyGenerated(date: LocalDate): Boolean { - val exists = notificationLogRepository - .existsByScheduledDateAndNotificationType(date, NotificationType.CLOCK_IN) - || notificationLogRepository - .existsByScheduledDateAndNotificationType(date, NotificationType.PUBLIC_HOLIDAY) - if (exists) log.info("Notifications already generated for date: {}", date) - return exists - } - private fun findWorkdayPolicies(date: LocalDate): List { val todayWorkday = Workday.from(date) return workPolicyVersionRepository.findLatestEffectivePoliciesPerMember(date) diff --git a/src/main/kotlin/com/moa/service/notification/PaydayNotificationBatchService.kt b/src/main/kotlin/com/moa/service/notification/PaydayNotificationBatchService.kt index fba159d..20cde3c 100644 --- a/src/main/kotlin/com/moa/service/notification/PaydayNotificationBatchService.kt +++ b/src/main/kotlin/com/moa/service/notification/PaydayNotificationBatchService.kt @@ -23,18 +23,24 @@ class PaydayNotificationBatchService( @Transactional fun generateNotificationsForDate(date: LocalDate) { - if (isAlreadyGenerated(date)) return - val profiles = findPaydayProfiles(date) if (profiles.isEmpty()) return - val memberIds = profiles.map { it.memberId } + val profileMemberIds = profiles.map { it.memberId } + val alreadyGeneratedMemberIds = notificationLogRepository + .findMemberIdsByScheduledDateAndNotificationTypeAndMemberIdIn(date, NotificationType.PAYDAY, profileMemberIds) + .toSet() + + val targetProfiles = profiles.filter { it.memberId !in alreadyGeneratedMemberIds } + if (targetProfiles.isEmpty()) return + + val memberIds = targetProfiles.map { it.memberId } val requiredTermCodes = notificationEligibilityService.findRequiredTermCodes() val context = notificationEligibilityService.loadContext(memberIds) log.info("Generating payday notifications for {} members on {}", memberIds.size, date) - val notifications = profiles.mapNotNull { profile -> + val notifications = targetProfiles.mapNotNull { profile -> createNotificationIfEligible(profile.memberId, date, requiredTermCodes, context) } @@ -42,13 +48,6 @@ class PaydayNotificationBatchService( log.info("Created {} payday notification logs for {}", notifications.size, date) } - private fun isAlreadyGenerated(date: LocalDate): Boolean { - val exists = notificationLogRepository - .existsByScheduledDateAndNotificationType(date, NotificationType.PAYDAY) - if (exists) log.info("Payday notifications already generated for date: {}", date) - return exists - } - private fun findPaydayProfiles(date: LocalDate): List { val candidatePaydayDays = PaydayDay.resolvingTo(date) .map { it.value }