Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PI-2248: Add sentence changed events to manage pom cases #3908

Merged
merged 3 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ generic-service:
SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_HMPPS-AUTH_TOKEN-URI: http://hmpps-auth.hmpps-auth-dev.svc.cluster.local/auth/oauth/token
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: http://hmpps-auth.hmpps-auth-dev.svc.cluster.local/auth/.well-known/jwks.json
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/issuer

SPRING_DATASOURCE_HIKARI_MAXIMUMPOOLSIZE: 5
SPRING_DATASOURCE_HIKARI_MINIMUMIDLE: 0

LOGGING_LEVEL_UK_GOV_DIGITAL_JUSTICE_HMPPS: DEBUG
MPC_ENDPOINT_URL: https://dev.moic.service.justice.gov.uk

generic-prometheus-alerts:
businessHoursOnly: true
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ generic-service:
SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_HMPPS-AUTH_TOKEN-URI: http://hmpps-auth.hmpps-auth-preprod.svc.cluster.local/auth/oauth/token
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: http://hmpps-auth.hmpps-auth-preprod.svc.cluster.local/auth/.well-known/jwks.json
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth/issuer
MPC_ENDPOINT_URL: https://preprod.moic.service.justice.gov.uk

generic-prometheus-alerts:
businessHoursOnly: true
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ generic-service:
SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_HMPPS-AUTH_TOKEN-URI: http://hmpps-auth.hmpps-auth-prod.svc.cluster.local/auth/oauth/token
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: http://hmpps-auth.hmpps-auth-prod.svc.cluster.local/auth/.well-known/jwks.json
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in.hmpps.service.justice.gov.uk/auth/issuer
MPC_ENDPOINT_URL: https://moic.service.justice.gov.uk
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.ApplicationListener
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.data.generator.CaseAllocationGenerator
import uk.gov.justice.digital.hmpps.data.generator.EventGenerator
import uk.gov.justice.digital.hmpps.data.generator.IdGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonManagerGenerator
import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator
import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator
import uk.gov.justice.digital.hmpps.data.generator.RegistrationGenerator
import uk.gov.justice.digital.hmpps.data.generator.UserGenerator
import uk.gov.justice.digital.hmpps.data.generator.*
import uk.gov.justice.digital.hmpps.integrations.delius.allocation.entity.CaseAllocationRepository
import uk.gov.justice.digital.hmpps.integrations.delius.allocation.entity.event.CustodyRepository
import uk.gov.justice.digital.hmpps.integrations.delius.allocation.entity.event.Disposal
Expand All @@ -26,12 +18,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonMana
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonRepository
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.registration.entity.RegisterType
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.registration.entity.RegistrationRepository
import uk.gov.justice.digital.hmpps.integrations.delius.provider.entity.District
import uk.gov.justice.digital.hmpps.integrations.delius.provider.entity.Institution
import uk.gov.justice.digital.hmpps.integrations.delius.provider.entity.ProbationAreaRepository
import uk.gov.justice.digital.hmpps.integrations.delius.provider.entity.StaffRepository
import uk.gov.justice.digital.hmpps.integrations.delius.provider.entity.StaffUser
import uk.gov.justice.digital.hmpps.integrations.delius.provider.entity.TeamRepository
import uk.gov.justice.digital.hmpps.integrations.delius.provider.entity.*
import uk.gov.justice.digital.hmpps.integrations.delius.reference.entity.ReferenceDataRepository
import uk.gov.justice.digital.hmpps.integrations.delius.reference.entity.ReferenceDataSet
import uk.gov.justice.digital.hmpps.user.AuditUserRepository
Expand Down Expand Up @@ -106,7 +93,8 @@ class DataLoader(
PersonGenerator.DEFAULT,
PersonGenerator.HANDOVER,
PersonGenerator.CREATE_HANDOVER_AND_START,
PersonGenerator.UPDATE_HANDOVER_AND_START
PersonGenerator.UPDATE_HANDOVER_AND_START,
PersonGenerator.CREATE_SENTENCE_CHANGED
)
)
personManagerRepository.saveAll(
Expand Down Expand Up @@ -152,6 +140,12 @@ class DataLoader(
)
)

val sentenceChangedHandoverEvent =
eventRepository.save(EventGenerator.generateEvent(PersonGenerator.CREATE_SENTENCE_CHANGED.id))
val sentenceChangedHandoverDisposal =
disposalRepository.save(EventGenerator.generateDisposal(sentenceChangedHandoverEvent))
custodyRepository.save(EventGenerator.generateCustody(sentenceChangedHandoverDisposal))

val handoverEvent = eventRepository.save(EventGenerator.generateEvent(PersonGenerator.HANDOVER.id))
val handoverDisposal = disposalRepository.save(EventGenerator.generateDisposal(handoverEvent))
custodyRepository.save(EventGenerator.generateCustody(handoverDisposal))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package uk.gov.justice.digital.hmpps.data.generator

import uk.gov.justice.digital.hmpps.messaging.ProbationOffenderEvent
import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader

object MessageGenerator {
val SENTENCE_CHANGED = ResourceLoader.message<ProbationOffenderEvent>("sentence-changed")
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ object PersonGenerator {
val HANDOVER = generate("H123456", "A1024BY")
val UPDATE_HANDOVER_AND_START = generate("H123457", "A2048BY")
val CREATE_HANDOVER_AND_START = generate("H123458", "A4096BY")
val CREATE_SENTENCE_CHANGED = generate("H123459", "A4096CY")

fun generate(
crn: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"Type": "Notification",
"MessageId": "20e13002-d1be-56e7-be8c-66cdd7e23341",
"TopicArn": "arn:aws:sns:eu-west-2:754256621582:cloud-platform-Digital-Prison-Services-f221e27fcfcf78f6ab4f4c3cc165eee7",
"Message": "{\"eventType\":\"SENTENCE_CHANGED\",\"eventDatetime\":\"2020-02-25T11:24:32.935401\",\"offenderId\":1,\"crn\":\"H123459\",\"sourceId\":\"2500974056\"}",
"Timestamp": "2020-02-25T11:25:16.169Z",
"SignatureVersion": "1",
"Signature": "h5p3FnnbsSHxj53RFePh8HR40cbVvgEZa6XUVTlYs/yuqfDsi17MPA+bX4ijKmmTT2l6xG2xYhcmRAbJWQ4wrwncTBm2azgiwSO5keRNWYVdiC0rI484KLZboP1SDsE+Y7hOU/R0dz49q7+0yd+QIocPteKB/8xG7/6kjGStAZKf3cEdlxOwLhN+7RU1Yk2ENuwAJjVRtvlAa76yKB3xvL2hId7P7ZLmHGlzZDNZNYxbg9C8HGxteOzZ9ZeeQsWDf9jmZ+5+7dKXQoW9LeqwHxEAq2vuwSZ8uwM5JljXbtS5w1P0psXPYNoin2gU1F5MDK8RPzjUtIvjINx08rmEOA==",
"SigningCertURL": "https://sns.eu-west-2.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem",
"UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-2:754256621582:cloud-platform-Digital-Prison-Services-f221e27fcfcf78f6ab4f4c3cc165eee7:92545cfe-de5d-43e1-8339-c366bf0172aa",
"MessageAttributes": {
"eventType": {
"Type": "String",
"Value": "SENTENCE_CHANGED"
},
"id": {
"Type": "String",
"Value": "cb4645f2-d0c1-4677-806a-8036ed54bf69"
},
"contentType": {
"Type": "String",
"Value": "text/plain;charset=UTF-8"
},
"timestamp": {
"Type": "Number.java.lang.Long",
"Value": "1582629916147"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"nomsNumber": "A4096CY",
"handoverDate": "2023-06-11",
"handoverStartDate": "2023-06-07",
"responsibility": "COM"
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@
"bodyFileName": "create-handover-and-start-date.json"
}
},
{
"request": {
"method": "GET",
"url": "/api/handovers/A4096CY"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"bodyFileName": "sentence-changed-dates.json"
}
},
{
"request": {
"method": "GET",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.integrations.delius.allocation.entity.event.CustodyRepository
import uk.gov.justice.digital.hmpps.integrations.delius.allocation.entity.event.keydate.KeyDate
import uk.gov.justice.digital.hmpps.integrations.delius.allocation.entity.event.keydate.KeyDateRepository
import uk.gov.justice.digital.hmpps.integrations.delius.allocation.entity.event.keydate.findHandoverDates
import uk.gov.justice.digital.hmpps.message.MessageAttributes
import uk.gov.justice.digital.hmpps.message.Notification
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader.notification
import uk.gov.justice.digital.hmpps.services.KeyDateMergeResult
Expand Down Expand Up @@ -91,4 +94,30 @@ internal class HandoverMessagingIntegrationTest {
assertThat(handoverDates[KeyDate.TypeCode.HANDOVER_DATE.value]?.date, equalTo(LocalDate.of(2023, 5, 10)))
assertThat(handoverDates[KeyDate.TypeCode.HANDOVER_START_DATE.value]?.date, equalTo(LocalDate.of(2023, 5, 6)))
}

@Test
fun `processes a sentence changed event successfully`() {
val notification = Notification(
message = MessageGenerator.SENTENCE_CHANGED,
attributes = MessageAttributes(eventType = "SENTENCE_CHANGED")
)

channelManager.getChannel(queueName).publishAndWait(notification)

verify(telemetryService).trackEvent(
KeyDateMergeResult.KeyDateCreated.name,
mapOf(
"nomsId" to "A4096CY",
"handoverDate" to "2023-06-11",
"handoverStartDate" to "2023-06-07"
)
)

val custody =
custodyRepository.findAllByDisposalEventPersonId(PersonGenerator.CREATE_SENTENCE_CHANGED.id).first()
val handoverDates = keyDateRepository.findHandoverDates(custody.id).associateBy { it.type.code }
assertThat(handoverDates.size, equalTo(2))
assertThat(handoverDates[KeyDate.TypeCode.HANDOVER_DATE.value]?.date, equalTo(LocalDate.of(2023, 6, 11)))
assertThat(handoverDates[KeyDate.TypeCode.HANDOVER_START_DATE.value]?.date, equalTo(LocalDate.of(2023, 6, 7)))
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
package uk.gov.justice.digital.hmpps.integrations.delius.person.entity

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.LockModeType
import jakarta.persistence.ManyToOne
import jakarta.persistence.OneToMany
import jakarta.persistence.Table
import jakarta.persistence.*
import org.hibernate.annotations.Immutable
import org.hibernate.annotations.SQLRestriction
import org.springframework.data.jpa.repository.EntityGraph
Expand Down Expand Up @@ -98,6 +91,9 @@ interface PersonRepository : JpaRepository<Person, Long> {
@Lock(LockModeType.PESSIMISTIC_READ)
@Query("select p.id from Person p where p.id = :personId")
fun findForUpdate(personId: Long): Long

@Query("select p.nomsId from Person p where p.crn = :crn and p.softDeleted = false")
fun findNomsIdByCrn(crn: String): String?
}

fun PersonRepository.getByNomsId(nomsId: String) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package uk.gov.justice.digital.hmpps.messaging

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
import org.openfolder.kotlinasyncapi.annotation.Schema
import org.openfolder.kotlinasyncapi.annotation.channel.Channel
import org.openfolder.kotlinasyncapi.annotation.channel.Message
import org.openfolder.kotlinasyncapi.annotation.channel.Publish
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Primary
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.converter.NotificationConverter
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonRepository
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.message.Notification
import uk.gov.justice.digital.hmpps.message.PersonIdentifier
import uk.gov.justice.digital.hmpps.message.PersonReference
import uk.gov.justice.digital.hmpps.services.HandoverDatesChanged
import uk.gov.justice.digital.hmpps.services.PomAllocated
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
Expand All @@ -15,23 +23,77 @@ import uk.gov.justice.digital.hmpps.telemetry.notificationReceived
@Component
@Channel("manage-pom-cases-and-delius-queue")
class PomCaseMessageHandler(
override val converter: NotificationConverter<HmppsDomainEvent>,
@Value("\${mpc.handover.url}") private val mpcHandoverUrl: String,
override val converter: PomCaseEventConverter,
private val handoverDatesChanged: HandoverDatesChanged,
private val pomAllocated: PomAllocated,
private val telemetryService: TelemetryService
) : NotificationHandler<HmppsDomainEvent> {
private val telemetryService: TelemetryService,
private val personRepository: PersonRepository
) : NotificationHandler<Any> {
@Publish(
messages = [
Message(name = "offender-management/handover-changed"),
Message(name = "offender-management/pom-allocated")
Message(name = "offender-management/pom-allocated"),
Message(messageId = "SENTENCE_CHANGED", payload = Schema(ProbationOffenderEvent::class)),
]
)
override fun handle(notification: Notification<HmppsDomainEvent>) {
override fun handle(notification: Notification<Any>) {
telemetryService.notificationReceived(notification)
when (notification.eventType) {
"offender-management.handover.changed" -> handoverDatesChanged.process(notification.message)
"offender-management.allocation.changed" -> pomAllocated.process(notification.message)
else -> throw NotImplementedError("Unhandled message type received: ${notification.eventType}")
when (val message = notification.message) {
is HmppsDomainEvent -> when (notification.eventType) {
"offender-management.handover.changed" -> handoverDatesChanged.process(
HandoverMessage(
message.personReference,
message.detailUrl
)
)

"offender-management.allocation.changed" -> pomAllocated.process(message)
else -> throw NotImplementedError("Unhandled message type received: ${notification.eventType}")
}

is ProbationOffenderEvent -> when (notification.eventType) {
"SENTENCE_CHANGED",
-> personRepository.findNomsIdByCrn(message.crn)?.let {
handoverDatesChanged.process(
HandoverMessage(
PersonReference(listOf(PersonIdentifier("NOMS", it))),
"$mpcHandoverUrl/api/handovers/$it"
)
)
}

else -> throw NotImplementedError("Unexpected offender event type: ${notification.eventType}")
}
}
}
}

data class HandoverMessage(
val personReference: PersonReference,
val detailUrl: String?
)

@Message
data class ProbationOffenderEvent(val crn: String)

@Primary
@Component
class PomCaseEventConverter(objectMapper: ObjectMapper) : NotificationConverter<Any>(objectMapper) {
override fun getMessageType() = Any::class

override fun fromMessage(message: String): Notification<Any> {
val stringMessage = objectMapper.readValue(message, jacksonTypeRef<Notification<String>>())
val json = objectMapper.readTree(stringMessage.message)
if (json.has("crn")) {
return Notification(
message = objectMapper.readValue(stringMessage.message, ProbationOffenderEvent::class.java),
attributes = stringMessage.attributes
)
}
return Notification(
message = objectMapper.readValue(stringMessage.message, HmppsDomainEvent::class.java),
attributes = stringMessage.attributes
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import uk.gov.justice.digital.hmpps.exception.IgnorableMessageException
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonRepository
import uk.gov.justice.digital.hmpps.integrations.managepomcases.Handover
import uk.gov.justice.digital.hmpps.integrations.managepomcases.ManagePomCasesClient
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.messaging.HandoverMessage
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
import java.net.URI

Expand All @@ -16,7 +16,7 @@ class HandoverDatesChanged(
private val keyDateService: KeyDateService,
private val telemetryService: TelemetryService
) {
fun process(event: HmppsDomainEvent) = try {
fun process(event: HandoverMessage) = try {
val handOver = event.detailUrl?.let { pomCasesClient.getDetails(URI.create(it)) }
?: throw IgnorableMessageException(
"No handover data available",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ context.initializer.classes: uk.gov.justice.digital.hmpps.wiremock.WireMockIniti

messaging.consumer.queue: message-queue

mpc.handover.url: http://localhost:${wiremock.port}

logging.level:
uk.gov.justice.digital.hmpps: DEBUG
org.hibernate.tool.schema: ERROR
Expand Down
Loading