diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListener.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListener.kt index 02ef16b9..942fdb79 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListener.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListener.kt @@ -33,18 +33,18 @@ class DomainEventsListener( } "probation-case.merge.completed" -> { - calculateTier(message.crn) + calculateTier(message.crn, message.eventType) message.sourceCrn?.also { calculator.deleteCalculationsForCrn(it, message.eventType) } } - else -> calculateTier(message.crn) + else -> calculateTier(message.crn, message.eventType) } } - private fun calculateTier(crn: String?) = crn?.also { - calculator.calculateTierForCrn(it, RecalculationSource.DomainEventRecalculation, true) + private fun calculateTier(crn: String?, eventType: String) = crn?.also { + calculator.calculateTierForCrn(it, RecalculationSource.EventSource.DomainEventRecalculation(eventType), true) } } diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/TierCalculationRequiredEventListener.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/TierCalculationRequiredEventListener.kt index afaf437a..86e62826 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/TierCalculationRequiredEventListener.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/TierCalculationRequiredEventListener.kt @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory import org.springframework.messaging.handler.annotation.MessageExceptionHandler import org.springframework.stereotype.Service import uk.gov.justice.digital.hmpps.hmppstier.service.RecalculationSource +import uk.gov.justice.digital.hmpps.hmppstier.service.RecalculationSource.EventSource.OffenderEventRecalculation import uk.gov.justice.digital.hmpps.hmppstier.service.TierCalculationService @Service @@ -28,14 +29,17 @@ class TierCalculationRequiredEventListener( val recalculation = getRecalculation(msg) calculator.calculateTierForCrn( recalculation.crn, - recalculation.recalculationSource ?: RecalculationSource.OffenderEventRecalculation, + RecalculationSource.of( + recalculation.recalculationSource ?: OffenderEventRecalculation::class.simpleName!!, + recalculation.eventType + ), !recalculation.dryRun ) } private fun getRecalculation(msg: String): TierCalculationMessage { - val (message) = objectMapper.readValue(msg) - return objectMapper.readValue(message) + val (message, attributes) = objectMapper.readValue(msg) + return objectMapper.readValue(message).forEventType(attributes.eventType) } companion object { @@ -45,9 +49,17 @@ class TierCalculationRequiredEventListener( data class TierCalculationMessage( val crn: String, - val recalculationSource: RecalculationSource? = null, + val recalculationSource: String? = null, val dryRun: Boolean = false -) +) { + var eventType: String? = null + private set + + fun forEventType(eventType: String?): TierCalculationMessage { + this.eventType = eventType + return this + } +} data class SQSMessage( @JsonProperty("Message") val message: String, diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/RecalculationSource.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/RecalculationSource.kt index 89ed7fa0..cab847a6 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/RecalculationSource.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/RecalculationSource.kt @@ -1,5 +1,26 @@ package uk.gov.justice.digital.hmpps.hmppstier.service -enum class RecalculationSource { - FullRecalculation, LimitedRecalculation, DomainEventRecalculation, OffenderEventRecalculation +sealed interface RecalculationSource { + data object FullRecalculation : RecalculationSource + + data object LimitedRecalculation : RecalculationSource + + data class Other(val type: String?) : RecalculationSource + + sealed interface EventSource : RecalculationSource { + val type: String + + data class DomainEventRecalculation(override val type: String) : EventSource + data class OffenderEventRecalculation(override val type: String) : EventSource + } + + companion object { + fun of(value: String, eventType: String?): RecalculationSource = when (value) { + FullRecalculation::class.simpleName -> FullRecalculation + LimitedRecalculation::class.simpleName -> LimitedRecalculation + EventSource.OffenderEventRecalculation::class.simpleName -> EventSource.OffenderEventRecalculation(eventType!!) + EventSource.DomainEventRecalculation::class.simpleName -> EventSource.DomainEventRecalculation(eventType!!) + else -> Other(eventType) + } + } } diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryService.kt index f78b374f..60476d73 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryService.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryService.kt @@ -21,16 +21,22 @@ class TelemetryService(@Autowired private val telemetryClient: TelemetryClient) } else { TIER_UNCHANGED }, - mapOf( + listOfNotNull( "crn" to calculation.crn, "protect" to calculation.data.protect.tier.value, "change" to calculation.data.change.tier.value.toString(), "version" to calculation.data.calculationVersion, - "recalculationReason" to recalculationSource.name, - ), + "recalculationSource" to recalculationSource::class.simpleName, + recalculationSource.reason()?.let { "recalculationReason" to it }, + ).toMap(), ) } + private fun RecalculationSource.reason() = when (this) { + is RecalculationSource.EventSource -> type + else -> null + } + fun trackEvent(eventType: TelemetryEventType, customDimensions: Map) { telemetryClient.trackEvent(eventType.eventName, customDimensions, null) } diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierCalculationService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierCalculationService.kt index 5c4be602..1fb86ba7 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierCalculationService.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierCalculationService.kt @@ -1,6 +1,7 @@ package uk.gov.justice.digital.hmpps.hmppstier.service import org.slf4j.LoggerFactory +import org.springframework.dao.DataIntegrityViolationException import org.springframework.stereotype.Service import uk.gov.justice.digital.hmpps.hmppstier.client.AssessmentForTier import uk.gov.justice.digital.hmpps.hmppstier.client.NeedSection @@ -33,11 +34,11 @@ class TierCalculationService( mapOf("crn" to crn, "reason" to reason), ) } catch (e: Exception) { - log.error("Unable to remove tier calculations for $crn") telemetryService.trackEvent( TIER_CALCULATION_REMOVAL_FAILED, mapOf("crn" to crn, "reasonToDelete" to reason, "failureReason" to e.message), ) + throw e } fun calculateTierForCrn(crn: String, recalculationSource: RecalculationSource, allowUpdates: Boolean) { @@ -61,7 +62,13 @@ class TierCalculationService( val eventType = if (allowUpdates) TIER_CALCULATION_FAILED else TIER_RECALCULATION_DRY_RUN_FAILURE telemetryService.trackEvent( eventType, - mapOf("crn" to crn, "exception" to e.message, "recalculationReason" to recalculationSource.name), + mapOf( + "crn" to crn, + "exception" to e.message, + "recalculationSource" to recalculationSource::class.simpleName, + "recalculationReason" to if (recalculationSource is RecalculationSource.EventSource) recalculationSource.type else "", + "duplicateAttempt" to (e is DataIntegrityViolationException).toString() + ), ) if (allowUpdates) { checkForCrnNotFound(crn, e) @@ -70,10 +77,10 @@ class TierCalculationService( } private fun checkForCrnNotFound(crn: String, e: Exception) { - if (e is CrnNotFoundException) { - deleteCalculationsForCrn(crn, "Not Found in Delius") - } else { - throw e + when (e) { + is DataIntegrityViolationException -> return + is CrnNotFoundException -> deleteCalculationsForCrn(crn, "Not Found in Delius") + else -> throw e } } @@ -128,8 +135,4 @@ class TierCalculationService( ).toMap() private fun NeedSection.mapSeverity(): Pair? = severity?.let { section to it } - - companion object { - private val log = LoggerFactory.getLogger(this::class.java) - } } diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierReader.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierReader.kt index 22ef05d9..1e339b89 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierReader.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierReader.kt @@ -20,27 +20,19 @@ class TierReader( fun getLatestTierByCrn(crn: String): TierDto? = tierSummaryRepository.findByIdOrNull(crn)?.let { - log.info("Found latest tier calculation for $crn") TierDto.from(it) } fun getLatestTierDetailsByCrn(crn: String): TierDetailsDto? = getLatestTierCalculation(crn)?.let { - log.info("Found latest tier calculation for $crn") TierDetailsDto.from(it) } fun getTierByCalculationId(crn: String, calculationId: UUID): TierDto? = tierCalculationRepository.findByCrnAndUuid(crn, calculationId)?.let { - log.info("Found tier for $crn and $calculationId") TierDto.from(it) } private fun getLatestTierCalculation(crn: String): TierCalculationEntity? = tierCalculationRepository.findFirstByCrnOrderByCreatedDesc(crn) - - companion object { - private val log = - LoggerFactory.getLogger(this::class.java) - } } diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierUpdater.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierUpdater.kt index e02388c0..87ab2782 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierUpdater.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TierUpdater.kt @@ -2,6 +2,7 @@ package uk.gov.justice.digital.hmpps.hmppstier.service import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Propagation import org.springframework.transaction.annotation.Transactional import uk.gov.justice.digital.hmpps.hmppstier.jpa.entity.TierCalculationEntity import uk.gov.justice.digital.hmpps.hmppstier.jpa.entity.TierSummary @@ -14,6 +15,7 @@ class TierUpdater( private val tierSummaryRepository: TierSummaryRepository, ) { + @Transactional(propagation = Propagation.REQUIRES_NEW) fun removeTierCalculationsFor(crn: String) { tierCalculationRepository.deleteAllByCrn(crn) tierSummaryRepository.deleteById(crn) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TriggerCalculationService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TriggerCalculationService.kt index f09fa9a6..5ad0b83f 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TriggerCalculationService.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TriggerCalculationService.kt @@ -57,7 +57,7 @@ class TriggerCalculationService( dryRun: Boolean ): SQSMessage = SQSMessage( objectMapper.writeValueAsString( - TierCalculationMessage(crn, recalculationSource, dryRun), + TierCalculationMessage(crn, recalculationSource::class.simpleName, dryRun), ), ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListenerTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListenerTest.kt index 0173ea18..5700ff12 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListenerTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/controller/DomainEventsListenerTest.kt @@ -9,7 +9,7 @@ import uk.gov.justice.digital.hmpps.hmppstier.integration.mockserver.tierToDeliu import uk.gov.justice.digital.hmpps.hmppstier.integration.mockserver.tierToDeliusApi.response.domain.Registration import uk.gov.justice.digital.hmpps.hmppstier.integration.mockserver.tierToDeliusApi.response.domain.TierDetails import uk.gov.justice.digital.hmpps.hmppstier.integration.setup.IntegrationTestBase -import uk.gov.justice.digital.hmpps.hmppstier.service.RecalculationSource.DomainEventRecalculation +import uk.gov.justice.digital.hmpps.hmppstier.service.RecalculationSource class DomainEventsListenerTest : IntegrationTestBase() { @Test @@ -61,7 +61,11 @@ class DomainEventsListenerTest : IntegrationTestBase() { mapOf("sourceCRN" to source), ) ) - verify(tierCalculationService, timeout(5000)).calculateTierForCrn(target, DomainEventRecalculation, true) + verify(tierCalculationService, timeout(5000)).calculateTierForCrn( + target, + RecalculationSource.EventSource.DomainEventRecalculation(eventType), + true + ) verify(tierCalculationService, timeout(5000)).deleteCalculationsForCrn(source, eventType) } @@ -76,6 +80,10 @@ class DomainEventsListenerTest : IntegrationTestBase() { ) ) verify(tierCalculationService, timeout(5000)).deleteCalculationsForCrn(crn, eventType) - verify(tierCalculationService, never()).calculateTierForCrn(crn, DomainEventRecalculation, true) + verify(tierCalculationService, never()).calculateTierForCrn( + crn, + RecalculationSource.EventSource.DomainEventRecalculation(eventType), + true + ) } } diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/CannotCalculateTierTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/CannotCalculateTierTest.kt index 20eb510b..025d93f2 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/CannotCalculateTierTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/CannotCalculateTierTest.kt @@ -19,7 +19,9 @@ class CannotCalculateTierTest : IntegrationTestBase() { mapOf( "crn" to "X123456", "exception" to "404 Not Found from GET http://localhost:8093/tier-details/X123456", - "recalculationReason" to "OffenderEventRecalculation", + "recalculationSource" to "OffenderEventRecalculation", + "recalculationReason" to "OFFENDER_MANAGEMENT_TIER_CALCULATION_REQUIRED", + "duplicateAttempt" to "false" ), null, ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/TriggerRecalculationsTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/TriggerRecalculationsTest.kt index 8b44164a..af187ecb 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/TriggerRecalculationsTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/integration/TriggerRecalculationsTest.kt @@ -46,7 +46,7 @@ class TriggerRecalculationsTest : IntegrationTestBase() { "protect" to "A", "change" to "1", "version" to "2", - "recalculationReason" to "LimitedRecalculation", + "recalculationSource" to "LimitedRecalculation", ), null, ) @@ -88,7 +88,7 @@ class TriggerRecalculationsTest : IntegrationTestBase() { "protect" to "A", "change" to "1", "version" to "2", - "recalculationReason" to "FullRecalculation", + "recalculationSource" to "FullRecalculation", ), null, ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryServiceTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryServiceTest.kt index a054b1a0..4ab23242 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryServiceTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppstier/service/TelemetryServiceTest.kt @@ -16,7 +16,7 @@ import uk.gov.justice.digital.hmpps.hmppstier.domain.enums.ProtectLevel import uk.gov.justice.digital.hmpps.hmppstier.jpa.entity.TierCalculationEntity import uk.gov.justice.digital.hmpps.hmppstier.jpa.entity.TierCalculationResultEntity import java.time.LocalDateTime -import java.util.UUID +import java.util.* @ExtendWith(MockKExtension::class) @DisplayName("Telemetry Service tests") @@ -60,7 +60,12 @@ internal class TelemetryServiceTest { @Test fun `Should emit TierChanged event when tier HAS changed`() { - service.trackTierCalculated(tierCalculation, true, RecalculationSource.DomainEventRecalculation) + val eventType = "some.event.type" + service.trackTierCalculated( + tierCalculation, + true, + RecalculationSource.EventSource.DomainEventRecalculation(eventType) + ) verify { client.trackEvent( @@ -70,7 +75,8 @@ internal class TelemetryServiceTest { "protect" to tierCalculation.data.protect.tier.value, "change" to tierCalculation.data.change.tier.value.toString(), "version" to tierCalculation.data.calculationVersion, - "recalculationReason" to "DomainEventRecalculation", + "recalculationSource" to "DomainEventRecalculation", + "recalculationReason" to eventType ), null, ) @@ -79,7 +85,12 @@ internal class TelemetryServiceTest { @Test fun `Should emit TierUnchanged event when tier HAS NOT changed`() { - service.trackTierCalculated(tierCalculation, false, RecalculationSource.DomainEventRecalculation) + val eventType = "some.event.type" + service.trackTierCalculated( + tierCalculation, + false, + RecalculationSource.EventSource.DomainEventRecalculation(eventType) + ) verify { client.trackEvent( @@ -89,7 +100,8 @@ internal class TelemetryServiceTest { "protect" to tierCalculation.data.protect.tier.value, "change" to tierCalculation.data.change.tier.value.toString(), "version" to tierCalculation.data.calculationVersion, - "recalculationReason" to "DomainEventRecalculation", + "recalculationSource" to "DomainEventRecalculation", + "recalculationReason" to eventType ), null, )