From 492018a57089989abaa1d91a13894ab74c39d79e Mon Sep 17 00:00:00 2001 From: Anthony Britton Date: Thu, 19 Oct 2023 15:04:52 +0100 Subject: [PATCH] PI-1573 --- .../justice/digital/hmpps/data/DataLoader.kt | 16 +++---- .../data/generator/NotificationGenerator.kt | 3 +- .../hmpps/data/generator/PersonGenerator.kt | 3 +- ...son => prisoner-released-ecsl-active.json} | 0 .../prisoner-released-ecsl-inactive.json | 17 +++++++ .../digital/hmpps/PcstdIntegrationTest.kt | 47 +++++++++++++++++-- .../digital/hmpps/messaging/Handler.kt | 12 +++-- .../hmpps/messaging/PrisonerMovement.kt | 7 ++- .../hmpps/messaging/PrisonerMovementConfig.kt | 3 +- .../hmpps/messaging/actions/ReleaseAction.kt | 2 +- .../application-prisoner-movement.yml | 1 + 11 files changed, 87 insertions(+), 24 deletions(-) rename projects/prison-custody-status-to-delius/src/dev/resources/messages/{prisoner-released-ecsl.json => prisoner-released-ecsl-active.json} (100%) create mode 100644 projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl-inactive.json diff --git a/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index e9cd76029d..17a612b41f 100644 --- a/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -83,7 +83,7 @@ class DataLoader( override fun onApplicationEvent(are: ApplicationReadyEvent) { createReferenceData() - createReleasablePerson() + createReleasablePerson(PersonGenerator.RELEASABLE) createRecallablePerson() createPersonToDie() createMatchablePerson() @@ -94,7 +94,8 @@ class DataLoader( createTemporaryAbsenceReturnFromRotl() createIrcReleased() createIrcInCustody() - createReleasableEcslPerson() + createReleasablePerson(PersonGenerator.RELEASABLE_ECSL_ACTIVE) + createReleasablePerson(PersonGenerator.RELEASABLE_ECSL_INACTIVE) } private fun createReferenceData() { @@ -149,14 +150,9 @@ class DataLoader( createEvent(EventGenerator.custodialEvent(PersonGenerator.DIED, InstitutionGenerator.DEFAULT)) } - private fun createReleasablePerson() { - createPerson(PersonGenerator.RELEASABLE) - createEvent(EventGenerator.custodialEvent(PersonGenerator.RELEASABLE, InstitutionGenerator.DEFAULT)) - } - - private fun createReleasableEcslPerson() { - createPerson(PersonGenerator.RELEASABLE_ECSL) - createEvent(EventGenerator.custodialEvent(PersonGenerator.RELEASABLE_ECSL, InstitutionGenerator.DEFAULT)) + private fun createReleasablePerson(person: Person) { + createPerson(person) + createEvent(EventGenerator.custodialEvent(person, InstitutionGenerator.DEFAULT)) } private fun createRecallablePerson() { diff --git a/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NotificationGenerator.kt b/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NotificationGenerator.kt index 18ee88e19c..d8a3534e37 100644 --- a/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NotificationGenerator.kt +++ b/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NotificationGenerator.kt @@ -15,5 +15,6 @@ object NotificationGenerator { val PRISONER_ROTL_RETURN = ResourceLoader.notification("prisoner-received-rotl") val PRISONER_IRC_RELEASED = ResourceLoader.notification("prisoner-received-irc-released") val PRISONER_IRC_IN_CUSTODY = ResourceLoader.notification("prisoner-received-irc-custody") - val PRISONER_RELEASED_ECSL = ResourceLoader.notification("prisoner-released-ecsl") + val PRISONER_RELEASED_ECSL_ACTIVE = ResourceLoader.notification("prisoner-released-ecsl-active") + val PRISONER_RELEASED_ECSL_INACTIVE = ResourceLoader.notification("prisoner-released-ecsl-inactive") } diff --git a/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt index 701751df66..514a4356d2 100644 --- a/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt +++ b/projects/prison-custody-status-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -15,7 +15,8 @@ object PersonGenerator { val ROTL = generate(NotificationGenerator.PRISONER_ROTL_RETURN.nomsId()) val IRC_RELEASED = generate(NotificationGenerator.PRISONER_IRC_RELEASED.nomsId()) val IRC_IN_CUSTODY = generate(NotificationGenerator.PRISONER_IRC_IN_CUSTODY.nomsId()) - val RELEASABLE_ECSL = generate(NotificationGenerator.PRISONER_RELEASED_ECSL.nomsId()) + val RELEASABLE_ECSL_ACTIVE = generate(NotificationGenerator.PRISONER_RELEASED_ECSL_ACTIVE.nomsId()) + val RELEASABLE_ECSL_INACTIVE = generate(NotificationGenerator.PRISONER_RELEASED_ECSL_INACTIVE.nomsId()) fun generate(nomsNumber: String, id: Long = IdGenerator.getAndIncrement()) = Person(id, nomsNumber) } diff --git a/projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl.json b/projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl-active.json similarity index 100% rename from projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl.json rename to projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl-active.json diff --git a/projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl-inactive.json b/projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl-inactive.json new file mode 100644 index 0000000000..26bbe7421a --- /dev/null +++ b/projects/prison-custody-status-to-delius/src/dev/resources/messages/prisoner-released-ecsl-inactive.json @@ -0,0 +1,17 @@ +{ + "Type": "Notification", + "MessageId": "682dd2a4-c193-461c-a8e9-cc976a961aa5", + "TopicArn": "", + "Message": "{\"eventType\":\"prison-offender-events.prisoner.released\",\"additionalInformation\":{\"nomsNumber\":\"A0015AA\",\"reason\":\"RELEASED\",\"details\":\"Movement reason code ECSL\",\"nomisMovementReasonCode\":\"ECSL\",\"currentLocation\":\"OUTSIDE_PRISON\",\"prisonId\":\"WSI\",\"currentPrisonStatus\":\"NOT_UNDER_PRISON_CARE\"},\"version\":1,\"occurredAt\":\"2022-05-04T07:03:50.912169+01:00\",\"publishedAt\":\"2022-05-04T08:00:33.477735848+01:00\",\"description\":\"A prisoner has been released from prison\",\"personReference\":{\"identifiers\":[{\"type\":\"NOMS\",\"value\":\"A0015AA\"}]}}", + "Timestamp": "2022-05-04T07:00:33.487Z", + "SignatureVersion": "1", + "Signature": "", + "SigningCertURL": "", + "UnsubscribeURL": "", + "MessageAttributes": { + "eventType": { + "Type": "String", + "Value": "prison-offender-events.prisoner.released" + } + } +} \ No newline at end of file diff --git a/projects/prison-custody-status-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PcstdIntegrationTest.kt b/projects/prison-custody-status-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PcstdIntegrationTest.kt index 9d3acaf0b1..85e822da85 100644 --- a/projects/prison-custody-status-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PcstdIntegrationTest.kt +++ b/projects/prison-custody-status-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PcstdIntegrationTest.kt @@ -23,6 +23,8 @@ import uk.gov.justice.digital.hmpps.test.CustomMatchers.isCloseTo import java.time.ZonedDateTime class PcstdIntegrationTest : PcstdIntegrationTestBase() { + private val releaseOnLicence = "Released on Licence" + @Test fun `release a prisoner`() { val notification = NotificationGenerator.PRISONER_RELEASED @@ -38,7 +40,7 @@ class PcstdIntegrationTest : PcstdIntegrationTestBase() { verifyCustodyHistory( custody, - CustodyEventTester(CustodyEventTypeCode.STATUS_CHANGE, "Released on Licence"), + CustodyEventTester(CustodyEventTypeCode.STATUS_CHANGE, releaseOnLicence), CustodyEventTester( CustodyEventTypeCode.LOCATION_CHANGE, InstitutionGenerator.STANDARD_INSTITUTIONS[InstitutionCode.IN_COMMUNITY]?.description @@ -443,9 +445,9 @@ class PcstdIntegrationTest : PcstdIntegrationTestBase() { } @Test - fun `release a ecsl prisoner`() { + fun `release a ecsl prisoner with feature active`() { whenever(featureFlags.enabled("messages_released_ecsl")).thenReturn(true) - val notification = NotificationGenerator.PRISONER_RELEASED_ECSL + val notification = NotificationGenerator.PRISONER_RELEASED_ECSL_ACTIVE val nomsNumber = notification.nomsId() assertTrue(getCustody(nomsNumber).isInCustody()) @@ -458,7 +460,7 @@ class PcstdIntegrationTest : PcstdIntegrationTestBase() { verifyCustodyHistory( custody, - CustodyEventTester(CustodyEventTypeCode.STATUS_CHANGE, "Released on Licence"), + CustodyEventTester(CustodyEventTypeCode.STATUS_CHANGE, releaseOnLicence), CustodyEventTester( CustodyEventTypeCode.LOCATION_CHANGE, InstitutionGenerator.STANDARD_INSTITUTIONS[InstitutionCode.IN_COMMUNITY]?.description @@ -478,4 +480,41 @@ class PcstdIntegrationTest : PcstdIntegrationTestBase() { ) } } + + @Test + fun `release a ecsl prisoner with feature inactive`() { + whenever(featureFlags.enabled("messages_released_ecsl")).thenReturn(false) + val notification = NotificationGenerator.PRISONER_RELEASED_ECSL_INACTIVE + val nomsNumber = notification.nomsId() + assertTrue(getCustody(nomsNumber).isInCustody()) + + channelManager.getChannel(queueName).publishAndWait(notification) + + val custody = getCustody(nomsNumber) + assertFalse(custody.isInCustody()) + + verifyRelease(custody, notification.message.occurredAt, ReleaseTypeCode.ADULT_LICENCE) + + verifyCustodyHistory( + custody, + CustodyEventTester(CustodyEventTypeCode.STATUS_CHANGE, releaseOnLicence), + CustodyEventTester( + CustodyEventTypeCode.LOCATION_CHANGE, + InstitutionGenerator.STANDARD_INSTITUTIONS[InstitutionCode.IN_COMMUNITY]?.description + ) + ) + + verifyContact(custody, ContactType.Code.RELEASE_FROM_CUSTODY) + + verifyTelemetry("Released", "LocationUpdated", "StatusUpdated") { + mapOf( + "occurredAt" to notification.message.occurredAt.toString(), + "nomsNumber" to "A0015AA", + "institution" to "WSI", + "reason" to "RELEASED", + "movementReason" to "ECSL", + "movementType" to "Released" + ) + } + } } diff --git a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 68f0b49af2..20c39886a7 100644 --- a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -55,10 +55,14 @@ class Handler( ) if (config.featureFlag != null && !featureFlags.enabled(config.featureFlag)) { - return telemetryService.trackEvent( - "FeatureFlagNotActive", - movement.telemetryProperties() + ("featureFlag" to config.featureFlag) - ) + if (config.reasonOverride == null) { + return telemetryService.trackEvent( + "FeatureFlagNotActive", + movement.telemetryProperties() + ("featureFlag" to config.featureFlag) + ) + } else { + movement.reasonOverride = config.reasonOverride + } } val results = actionProcessor.processActions(movement, config.actionNames) diff --git a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovement.kt b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovement.kt index 3ba91f8128..8b67682ab6 100644 --- a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovement.kt +++ b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovement.kt @@ -8,13 +8,15 @@ sealed interface PrisonerMovement { val type: Type val reason: String val occurredAt: ZonedDateTime + var reasonOverride: String? data class Received( override val nomsId: String, override val prisonId: String, override val type: Type, override val reason: String, - override val occurredAt: ZonedDateTime + override val occurredAt: ZonedDateTime, + override var reasonOverride: String? = null ) : PrisonerMovement data class Released( @@ -22,7 +24,8 @@ sealed interface PrisonerMovement { override val prisonId: String?, override val type: Type, override val reason: String, - override val occurredAt: ZonedDateTime + override val occurredAt: ZonedDateTime, + override var reasonOverride: String? = null ) : PrisonerMovement enum class Type { diff --git a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovementConfig.kt b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovementConfig.kt index 465789259f..701aa9a5d9 100644 --- a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovementConfig.kt +++ b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/PrisonerMovementConfig.kt @@ -12,7 +12,8 @@ data class PrisonerMovementConfig( val types: List, val reasons: List = listOf(), val actionNames: List = listOf(), - val featureFlag: String? = null + val featureFlag: String? = null, + val reasonOverride: String? = null ) { fun validFor(type: PrisonerMovement.Type, reason: String): Boolean = type in types && (reasons.isEmpty() || reason in reasons) diff --git a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/actions/ReleaseAction.kt b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/actions/ReleaseAction.kt index b625f58cd2..85d3de0b5e 100644 --- a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/actions/ReleaseAction.kt +++ b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/actions/ReleaseAction.kt @@ -104,7 +104,7 @@ private fun PrisonerMovement.releaseType(): ReleaseTypeCode { if (type != PrisonerMovement.Type.RELEASED) { throw IgnorableMessageException("UnsupportedReleaseType") } - return when (reason) { + return when (reasonOverride ?: reason) { "ECSL" -> ReleaseTypeCode.END_CUSTODY_SUPERVISED_LICENCE else -> ReleaseTypeCode.ADULT_LICENCE } diff --git a/projects/prison-custody-status-to-delius/src/main/resources/application-prisoner-movement.yml b/projects/prison-custody-status-to-delius/src/main/resources/application-prisoner-movement.yml index d719b0a0ff..38e5e216b5 100644 --- a/projects/prison-custody-status-to-delius/src/main/resources/application-prisoner-movement.yml +++ b/projects/prison-custody-status-to-delius/src/main/resources/application-prisoner-movement.yml @@ -44,6 +44,7 @@ prisoner.movement.configs: - RELEASED reasons: - ECSL + reasonOverride: RO actionNames: - Release - UpdateStatus