Skip to content

Commit

Permalink
PI-2729 add subtype filtering in code (#4545)
Browse files Browse the repository at this point in the history
* PI-2729 add subtype filtering in code

---------

Co-authored-by: probation-integration-bot[bot] <177347787+probation-integration-bot[bot]@users.noreply.github.com>
  • Loading branch information
1 parent 159700f commit f138a2e
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ fun prepNotification(
"{wiremock.port}",
port.toString()
)
)
),
attributes = notification.attributes
)

fun ZonedDateTime.closeTo(dateTime: ZonedDateTime?, unit: ChronoUnit = ChronoUnit.SECONDS, number: Int = 1): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package uk.gov.justice.digital.hmpps.data.generator

import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.message.Notification
import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader

object CaseNoteMessageGenerator {
val EXISTS_IN_DELIUS: HmppsDomainEvent = ResourceLoader.message("case-note-exists-in-delius")
val NEW_TO_DELIUS: HmppsDomainEvent = ResourceLoader.message("case-note-new-to-delius")
val NOT_FOUND: HmppsDomainEvent = ResourceLoader.message("case-note-not-found")
val RESETTLEMENT_PASSPORT: HmppsDomainEvent = ResourceLoader.message("resettlement-passport-casenote")
val NOMS_NUMBER_ADDED: HmppsDomainEvent = ResourceLoader.message("noms-number-added")
val EXISTS_IN_DELIUS: Notification<HmppsDomainEvent> =
ResourceLoader.notification<HmppsDomainEvent>("case-note-exists-in-delius")
val NEW_TO_DELIUS: Notification<HmppsDomainEvent> =
ResourceLoader.notification<HmppsDomainEvent>("case-note-new-to-delius")
val NOT_FOUND: Notification<HmppsDomainEvent> = ResourceLoader.notification<HmppsDomainEvent>("case-note-not-found")
val RESETTLEMENT_PASSPORT: Notification<HmppsDomainEvent> =
ResourceLoader.notification<HmppsDomainEvent>("resettlement-passport-casenote")
val NOMS_NUMBER_ADDED: Notification<HmppsDomainEvent> =
ResourceLoader.notification<HmppsDomainEvent>("noms-number-added")
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"MessageId": "ae06c49e-1f41-4b9f-b2f2-dcca610d02cd",
"Type": "Notification",
"Timestamp": "2019-10-21T14:01:18.500Z",
"Message": "{\"eventType\":\"person.case-note.updated\",\"version\":1,\"description\":\"A prison case note has been amended\",\"occurredAt\":\"2022-10-18T08:19:19.451579+01:00\",\"detailUrl\":\"http://localhost:{wiremock.port}/case-notes/AA0001A/0ec15f8b-6b57-471f-b02a-c89169a6a3e5\",\"additionalInformation\":{\"id\":\"0ec15f8b-6b57-471f-b02a-c89169a6a3e5\",\"legacyId\":\"1111\",\"type\":\"NEG\",\"subType\":\"IEP_WARN\"},\"personReference\":{\"identifiers\":[{\"type\":\"NOMS\",\"value\":\"AA0001A\"}]}}",
"Message": "{\"eventType\":\"person.case-note.updated\",\"version\":1,\"description\":\"A prison case note has been amended\",\"occurredAt\":\"2022-10-18T08:19:19.451579+01:00\",\"detailUrl\":\"http://localhost:{wiremock.port}/case-notes/AA0001A/0ec15f8b-6b57-471f-b02a-c89169a6a3e5\",\"additionalInformation\":{\"id\":\"0ec15f8b-6b57-471f-b02a-c89169a6a3e5\",\"legacyId\":\"1111\",\"type\":\"GEN\",\"subType\":\"OSE\"},\"personReference\":{\"identifiers\":[{\"type\":\"NOMS\",\"value\":\"AA0001A\"}]}}",
"TopicArn": "arn:aws:sns:eu-west-1:000000000000:offender_events",
"MessageAttributes": {
"eventType": {
Expand All @@ -11,11 +11,11 @@
},
"type": {
"Type": "String",
"Value": "NEG"
"Value": "GEN"
},
"subType": {
"Type": "String",
"Value": "IEP_WARN"
"Value": "OSE"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"MessageId": "ae06c49e-1f41-4b9f-b2f2-dcca610d02cd",
"Type": "Notification",
"Timestamp": "2019-10-21T14:01:18.500Z",
"Message": "{\"eventType\":\"person.case-note.created\",\"version\":1,\"description\":\"A prison case note has been created\",\"occurredAt\":\"2022-10-18T08:19:19.451579+01:00\",\"detailUrl\":\"http://localhost:{wiremock.port}/case-notes/AA0001A/2cf4f9e1-df22-49a1-a2a7-5968a96529e3\",\"additionalInformation\":{\"id\":\"2cf4f9e1-df22-49a1-a2a7-5968a96529e3\",\"legacyId\":\"2222\",\"type\":\"NEG\",\"subType\":\"IEP_WARN\"},\"personReference\":{\"identifiers\":[{\"type\":\"NOMS\",\"value\":\"AA0001A\"}]}}",
"Message": "{\"eventType\":\"person.case-note.created\",\"version\":1,\"description\":\"A prison case note has been created\",\"occurredAt\":\"2022-10-18T08:19:19.451579+01:00\",\"detailUrl\":\"http://localhost:{wiremock.port}/case-notes/AA0001A/2cf4f9e1-df22-49a1-a2a7-5968a96529e3\",\"additionalInformation\":{\"id\":\"2cf4f9e1-df22-49a1-a2a7-5968a96529e3\",\"legacyId\":\"2222\",\"type\":\"KA\",\"subType\":\"KS\"},\"personReference\":{\"identifiers\":[{\"type\":\"NOMS\",\"value\":\"AA0001A\"}]}}",
"TopicArn": "arn:aws:sns:eu-west-1:000000000000:offender_events",
"MessageAttributes": {
"eventType": {
Expand All @@ -11,11 +11,11 @@
},
"type": {
"Type": "String",
"Value": "NEG"
"Value": "KA"
},
"subType": {
"Type": "String",
"Value": "IEP_WARN"
"Value": "KS"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"MessageId": "ae06c49e-1f41-4b9f-b2f2-dcca610d02cd",
"Type": "Notification",
"Timestamp": "2019-10-21T14:01:18.500Z",
"Message": "{\"eventType\":\"person.case-note.created\",\"version\":1,\"description\":\"A prison case note has been created\",\"occurredAt\":\"2022-10-18T08:19:19.451579+01:00\",\"detailUrl\":\"http://localhost:{wiremock.port}/case-notes/AA0001A/da82e1df-1a74-486e-842c-6ce961575211\",\"additionalInformation\":{\"id\":\"da82e1df-1a74-486e-842c-6ce961575211\",\"legacyId\":\"432109\",\"type\":\"NEG\",\"subType\":\"IEP_WARN\"},\"personReference\":{\"identifiers\":[{\"type\":\"NOMS\",\"value\":\"AA0001A\"}]}}",
"Message": "{\"eventType\":\"person.case-note.created\",\"version\":1,\"description\":\"A prison case note has been created\",\"occurredAt\":\"2022-10-18T08:19:19.451579+01:00\",\"detailUrl\":\"http://localhost:{wiremock.port}/case-notes/AA0001A/da82e1df-1a74-486e-842c-6ce961575211\",\"additionalInformation\":{\"id\":\"da82e1df-1a74-486e-842c-6ce961575211\",\"legacyId\":\"432109\",\"type\":\"OMIC\",\"subType\":\"GEN\"},\"personReference\":{\"identifiers\":[{\"type\":\"NOMS\",\"value\":\"AA0001A\"}]}}",
"TopicArn": "arn:aws:sns:eu-west-1:000000000000:offender_events",
"MessageAttributes": {
"eventType": {
Expand All @@ -11,11 +11,11 @@
},
"type": {
"Type": "String",
"Value": "NEG"
"Value": "OMIC"
},
"subType": {
"Type": "String",
"Value": "IEP_WARN"
"Value": "GEN"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ import org.springframework.test.context.bean.override.mockito.MockitoSpyBean
import uk.gov.justice.digital.hmpps.audit.repository.AuditedInteractionRepository
import uk.gov.justice.digital.hmpps.data.generator.*
import uk.gov.justice.digital.hmpps.datetime.DeliusDateTimeFormatter
import uk.gov.justice.digital.hmpps.integrations.delius.model.DeliusCaseNote
import uk.gov.justice.digital.hmpps.integrations.delius.repository.CaseNoteRepository
import uk.gov.justice.digital.hmpps.integrations.delius.repository.OffenderRepository
import uk.gov.justice.digital.hmpps.integrations.delius.repository.StaffRepository
import uk.gov.justice.digital.hmpps.message.MessageAttribute
import uk.gov.justice.digital.hmpps.message.MessageAttributes
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
import uk.gov.justice.digital.hmpps.test.CustomMatchers.isCloseTo
import java.time.Duration
import java.time.ZonedDateTime

const val CASE_NOTE_MERGED = "CaseNoteMerged"
Expand Down Expand Up @@ -62,10 +66,10 @@ class CaseNotesIntegrationTest {
val nomisCaseNote = PrisonCaseNoteGenerator.EXISTING_IN_BOTH

channelManager.getChannel(queueName).publishAndWait(
prepMessage(CaseNoteMessageGenerator.EXISTS_IN_DELIUS, wireMockserver.port())
prepNotification(CaseNoteMessageGenerator.EXISTS_IN_DELIUS, wireMockserver.port())
)

val saved = caseNoteRepository.findByNomisId(nomisCaseNote.eventId)
val saved = caseNoteRepository.findByExternalReference("${DeliusCaseNote.URN_PREFIX}${nomisCaseNote.id}")

assertThat(
saved?.notes,
Expand Down Expand Up @@ -93,11 +97,11 @@ class CaseNotesIntegrationTest {
assertNull(original)

channelManager.getChannel(queueName).publishAndWait(
prepMessage(CaseNoteMessageGenerator.NEW_TO_DELIUS, wireMockserver.port())
prepNotification(CaseNoteMessageGenerator.NEW_TO_DELIUS, wireMockserver.port())
)

verify(telemetryService).trackEvent(eq(CASE_NOTE_MERGED), anyMap(), anyMap())
val saved = caseNoteRepository.findByNomisId(nomisCaseNote.eventId)
val saved = caseNoteRepository.findByExternalReference("${DeliusCaseNote.URN_PREFIX}${nomisCaseNote.id}")
assertNotNull(saved)

assertThat(
Expand Down Expand Up @@ -135,7 +139,7 @@ class CaseNotesIntegrationTest {
@Test
fun `case note not found - noop`() {
channelManager.getChannel(queueName).publishAndWait(
prepMessage(CaseNoteMessageGenerator.NOT_FOUND, wireMockserver.port())
prepNotification(CaseNoteMessageGenerator.NOT_FOUND, wireMockserver.port())
)

verify(telemetryService, never()).trackEvent(eq(CASE_NOTE_MERGED), anyMap(), anyMap())
Expand All @@ -146,11 +150,11 @@ class CaseNotesIntegrationTest {
val nomisCaseNote = PrisonCaseNoteGenerator.RESETTLEMENT_PASSPORT

channelManager.getChannel(queueName).publishAndWait(
prepMessage(CaseNoteMessageGenerator.RESETTLEMENT_PASSPORT, wireMockserver.port())
prepNotification(CaseNoteMessageGenerator.RESETTLEMENT_PASSPORT, wireMockserver.port())
)

verify(telemetryService).trackEvent(eq(CASE_NOTE_MERGED), anyMap(), anyMap())
val saved = caseNoteRepository.findByNomisId(nomisCaseNote.eventId)
val saved = caseNoteRepository.findByExternalReference("${DeliusCaseNote.URN_PREFIX}${nomisCaseNote.id}")
assertNotNull(saved)

assertThat(
Expand Down Expand Up @@ -179,7 +183,7 @@ class CaseNotesIntegrationTest {
assert(originals.isEmpty())

channelManager.getChannel(queueName).publishAndWait(
prepMessage(CaseNoteMessageGenerator.NOMS_NUMBER_ADDED, wireMockserver.port())
prepNotification(CaseNoteMessageGenerator.NOMS_NUMBER_ADDED, wireMockserver.port())
)

verify(telemetryService).trackEvent(
Expand All @@ -190,4 +194,20 @@ class CaseNotesIntegrationTest {
val saved = caseNoteRepository.findAll().filter { it.offenderId == offender.id }
assertThat(saved.size, equalTo(4))
}

@Test
fun `case note not of interest - noop`() {
val existing = CaseNoteMessageGenerator.EXISTS_IN_DELIUS
channelManager.getChannel(queueName).publishAndWait(
prepNotification(
existing.copy(
attributes = MessageAttributes(existing.eventType!!).apply {
this["type"] = MessageAttribute("String", "NOTOF")
this["subType"] = MessageAttribute("String", "INTEREST")
}
), wireMockserver.port())
)

verify(telemetryService, never()).trackEvent(eq(CASE_NOTE_MERGED), anyMap(), anyMap())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import java.time.ZonedDateTime
import java.util.*

data class DeliusCaseNote(val header: CaseNoteHeader, val body: CaseNoteBody) {
val urn = header.uuid?.let { "urn:uk:gov:hmpps:prison-case-note:${it}" }
val urn = header.uuid?.let { "$URN_PREFIX${it}" }

companion object {
const val URN_PREFIX = "urn:uk:gov:hmpps:prison-case-note:"
}
}

data class CaseNoteHeader(val nomisId: String, val legacyId: Long, val uuid: UUID?)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package uk.gov.justice.digital.hmpps.integrations.prison

object CaseNoteTypesOfInterest {
private val typeSubTypeMap = mapOf(
"PRISON" to setOf("RELEASE"),
"TRANSFER" to setOf("FROMTOL"),
"GEN" to setOf("OSE"),
"RESET" to setOf("BCST"),
"ALERT" to setOf(),
"OMIC" to setOf(),
"OMIC_OPD" to setOf(),
"KA" to setOf()
)

fun forSearchRequest(): Set<TypeSubTypeRequest> =
typeSubTypeMap.map { TypeSubTypeRequest(it.key, it.value) }.toSet()

fun verifyOfInterest(type: String, subType: String): Boolean {
val subTypes = typeSubTypeMap[type] ?: return false
return subTypes.isEmpty() || subTypes.contains(subType)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,7 @@ data class SearchCaseNotes(
val page: Int = 1,
val size: Int = Int.MAX_VALUE,
val sort: String = "occurredAt,desc",
) {
companion object {
val TYPES_OF_INTEREST = setOf(
TypeSubTypeRequest("PRISON", setOf("RELEASE")),
TypeSubTypeRequest("TRANSFER", setOf("FROMTOL")),
TypeSubTypeRequest("GEN", setOf("OSE")),
TypeSubTypeRequest("ALERT"),
TypeSubTypeRequest("OMIC"),
TypeSubTypeRequest("OMIC_OPD"),
TypeSubTypeRequest("KA"),
)
}
}
)

data class TypeSubTypeRequest(val type: String, val subTypes: Set<String> = setOf())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import org.openfolder.kotlinasyncapi.annotation.channel.Message
import org.openfolder.kotlinasyncapi.annotation.channel.Publish
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.converter.NotificationConverter
import uk.gov.justice.digital.hmpps.integrations.prison.CaseNoteTypesOfInterest
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.message.Notification
import uk.gov.justice.digital.hmpps.messaging.Handler.Companion.CASE_NOTE_PUBLISHED
import uk.gov.justice.digital.hmpps.messaging.Handler.Companion.PERSON_CASE_NOTE_CREATED
import uk.gov.justice.digital.hmpps.messaging.Handler.Companion.PERSON_CASE_NOTE_UPDATED

@Component
@Channel("prison-case-notes-to-probation-queue")
Expand All @@ -34,10 +38,21 @@ class Handler(
]
)
override fun handle(notification: Notification<HmppsDomainEvent>) {
when (notification.eventType) {
CASE_NOTE_PUBLISHED -> caseNotePublished.handle(notification.message)
PRISON_IDENTIFIER_ADDED -> prisonIdentifierAdded.handle(notification.message)
PERSON_CASE_NOTE_CREATED, PERSON_CASE_NOTE_UPDATED -> personCaseNote.handle(notification.message)
when {
notification.eventType == PRISON_IDENTIFIER_ADDED -> prisonIdentifierAdded.handle(notification.message)
notification.isCaseNoteOfInterest() -> personCaseNote.handle(notification.message)
notification.publishedOfInterest() -> caseNotePublished.handle(notification.message)
}
}
}

private fun Notification<*>.publishedOfInterest(): Boolean =
eventType == CASE_NOTE_PUBLISHED && typeIsOfInterest()

private fun Notification<*>.isCaseNoteOfInterest(): Boolean =
(eventType == PERSON_CASE_NOTE_CREATED || eventType == PERSON_CASE_NOTE_UPDATED) && typeIsOfInterest()

val Notification<*>.type get() = attributes["type"]?.value
val Notification<*>.subType get() = attributes["subType"]?.value

private fun Notification<*>.typeIsOfInterest() = CaseNoteTypesOfInterest.verifyOfInterest(type!!, subType!!)
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import uk.gov.justice.digital.hmpps.integrations.delius.service.DeliusService
import uk.gov.justice.digital.hmpps.integrations.prison.PrisonCaseNoteFilters
import uk.gov.justice.digital.hmpps.integrations.prison.PrisonCaseNotesClient
import uk.gov.justice.digital.hmpps.integrations.prison.SearchCaseNotes
import uk.gov.justice.digital.hmpps.integrations.prison.SearchCaseNotes.Companion.TYPES_OF_INTEREST
import uk.gov.justice.digital.hmpps.integrations.prison.toDeliusCaseNote
import uk.gov.justice.digital.hmpps.integrations.prison.*
import uk.gov.justice.digital.hmpps.integrations.prison.CaseNoteTypesOfInterest.forSearchRequest
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
import java.net.URI
Expand All @@ -27,7 +24,7 @@ class PrisonIdentifierAdded(
"NomsNumber not found for ${event.eventType}"
}
val uri = URI.create("$caseNotesBaseUrl/search/case-notes/$nomsId")
val caseNotes = caseNotesApi.searchCaseNotes(uri, SearchCaseNotes(TYPES_OF_INTEREST)).content
val caseNotes = caseNotesApi.searchCaseNotes(uri, SearchCaseNotes(forSearchRequest())).content
.filter { cn -> PrisonCaseNoteFilters.filters.none { it.predicate.invoke(cn) } }

caseNotes.forEach { deliusService.mergeCaseNote(it.toDeliusCaseNote()) }
Expand Down
Loading

0 comments on commit f138a2e

Please sign in to comment.