From 28e7d74d4f3f580032df9f66d27116c78176b16d Mon Sep 17 00:00:00 2001 From: Marcus Aspin Date: Tue, 11 Jun 2024 09:04:33 +0100 Subject: [PATCH] PI-2231 Add mapping from R&M withdrawal codes to NSI outcomes (#3885) --- .../hmpps/data/generator/NsiGenerator.kt | 4 +- .../messages/referral-withdrawn.json | 2 +- .../__files/referral-prematurely-ended.json | 4 +- .../hmpps/ReferAndMonitorIntegrationTest.kt | 5 +- .../hmpps/messaging/ReferralEndSubmitted.kt | 68 +++++++++++++++++-- .../digital/hmpps/service/NsiService.kt | 3 +- .../messaging/ReferralEndSubmittedTest.kt | 4 +- .../service/RepositoryExtensionMethodTests.kt | 6 +- 8 files changed, 81 insertions(+), 15 deletions(-) diff --git a/projects/refer-and-monitor-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiGenerator.kt b/projects/refer-and-monitor-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiGenerator.kt index 39b3f2d384..ba7a821504 100644 --- a/projects/refer-and-monitor-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiGenerator.kt +++ b/projects/refer-and-monitor-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiGenerator.kt @@ -9,6 +9,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.referral.entity.NsiManag import uk.gov.justice.digital.hmpps.integrations.delius.referral.entity.NsiStatus import uk.gov.justice.digital.hmpps.integrations.delius.referral.entity.NsiType import uk.gov.justice.digital.hmpps.messaging.ReferralEndType +import uk.gov.justice.digital.hmpps.messaging.ReferralWithdrawalNsiOutcome import uk.gov.justice.digital.hmpps.service.ContractTypeNsiType import java.time.LocalDate import java.time.ZonedDateTime @@ -16,7 +17,8 @@ import java.time.ZonedDateTime object NsiGenerator { val NSI_OUTCOME_DS = Dataset(Dataset.Code.NSI_OUTCOME.value, IdGenerator.getAndIncrement()) val OUTCOMES = ReferralEndType.entries.map { generateOutcome(it.outcome) }.associateBy { it.code } - val WITHDRAWN_OUTCOMES = (1..13).map { generateOutcome("NSI$it") }.associateBy { it.code } + val WITHDRAWN_OUTCOMES = + ReferralWithdrawalNsiOutcome.entries.map { generateOutcome(it.name, it.description) }.associateBy { it.code } val TYPES = ContractTypeNsiType.MAPPING.values.map { generateType(it) }.associateBy { it.code } val INPROG_STATUS = generateStatus( NsiStatus.Code.IN_PROGRESS.value, diff --git a/projects/refer-and-monitor-and-delius/src/dev/resources/messages/referral-withdrawn.json b/projects/refer-and-monitor-and-delius/src/dev/resources/messages/referral-withdrawn.json index 7afee4da2a..bfe109d03c 100644 --- a/projects/refer-and-monitor-and-delius/src/dev/resources/messages/referral-withdrawn.json +++ b/projects/refer-and-monitor-and-delius/src/dev/resources/messages/referral-withdrawn.json @@ -2,7 +2,7 @@ "Type": "Notification", "MessageId": "aa2c2828-167f-529b-8e19-78535a2fb85c", "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", - "Message": "{\"eventType\":\"intervention.referral.ended\",\"version\":1,\"description\":\"Referral Ended\",\"detailUrl\":\"http://localhost:{wiremock.port}/sent-referral/f56c5f7c-632f-4cad-a1b3-693541cb5f22\",\"occurredAt\":\"2023-02-23T15:55:21.1065440Z\",\"additionalInformation\":{\"deliveryState\": \"CANCELLED\",\"withdrawalCode\": \"NSI1\",\"referralId\":\"f56c5f7c-632f-4cad-a1b3-693541cb5f22\",\"referralURN\":\"urn:hmpps:interventions-referral:68df9f6c-3fcb-4ec6-8fcf-96551cd9b080\",\"referralProbationUserURL\":\"https://refer-monitor-intervention.service.justice.gov.uk/probation-practitioner/referrals/68df9f6c-3fcb-4ec6-8fcf-96551cd9b080/details\"},\"personReference\":{\"identifiers\":[{\"type\":\"CRN\",\"value\":\"T140223\"}]}}", + "Message": "{\"eventType\":\"intervention.referral.ended\",\"version\":1,\"description\":\"Referral Ended\",\"detailUrl\":\"http://localhost:{wiremock.port}/sent-referral/f56c5f7c-632f-4cad-a1b3-693541cb5f22\",\"occurredAt\":\"2023-02-23T15:55:21.1065440Z\",\"additionalInformation\":{\"deliveryState\": \"CANCELLED\",\"withdrawalCode\": \"NEE\",\"withdrawalState\": \"PRE_ICA_WITHDRAWAL\",\"referralId\":\"f56c5f7c-632f-4cad-a1b3-693541cb5f22\",\"referralURN\":\"urn:hmpps:interventions-referral:68df9f6c-3fcb-4ec6-8fcf-96551cd9b080\",\"referralProbationUserURL\":\"https://refer-monitor-intervention.service.justice.gov.uk/probation-practitioner/referrals/68df9f6c-3fcb-4ec6-8fcf-96551cd9b080/details\"},\"personReference\":{\"identifiers\":[{\"type\":\"CRN\",\"value\":\"T140223\"}]}}", "Timestamp": "2023-02-23T15:55:20.306Z", "SignatureVersion": "1", "MessageAttributes": { diff --git a/projects/refer-and-monitor-and-delius/src/dev/resources/simulations/__files/referral-prematurely-ended.json b/projects/refer-and-monitor-and-delius/src/dev/resources/simulations/__files/referral-prematurely-ended.json index c9f2d475bd..aa0efd8d03 100644 --- a/projects/refer-and-monitor-and-delius/src/dev/resources/simulations/__files/referral-prematurely-ended.json +++ b/projects/refer-and-monitor-and-delius/src/dev/resources/simulations/__files/referral-prematurely-ended.json @@ -36,5 +36,7 @@ "authSource": "string", "userId": "string" } - } + }, + "withdrawalCode": "NEE", + "withdrawalState": "PRE_ICA_WITHDRAWAL" } \ No newline at end of file diff --git a/projects/refer-and-monitor-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ReferAndMonitorIntegrationTest.kt b/projects/refer-and-monitor-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ReferAndMonitorIntegrationTest.kt index 09b53ab9d2..cac0f96210 100644 --- a/projects/refer-and-monitor-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ReferAndMonitorIntegrationTest.kt +++ b/projects/refer-and-monitor-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ReferAndMonitorIntegrationTest.kt @@ -27,6 +27,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.referral.NsiRepository import uk.gov.justice.digital.hmpps.integrations.delius.referral.NsiStatusHistoryRepository import uk.gov.justice.digital.hmpps.integrations.delius.referral.entity.NsiStatus import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager +import uk.gov.justice.digital.hmpps.messaging.ReferralWithdrawalNsiOutcome import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader.notification import uk.gov.justice.digital.hmpps.telemetry.TelemetryService import uk.gov.justice.digital.hmpps.test.CustomMatchers.isCloseTo @@ -292,7 +293,7 @@ internal class ReferAndMonitorIntegrationTest { saved.actualEndDate!!.withZoneSameInstant(EuropeLondon), isCloseTo(ZonedDateTime.parse("2023-02-23T15:29:54.197Z").withZoneSameInstant(EuropeLondon)) ) - assertThat(saved.outcome?.code, equalTo("NSI1")) + assertThat(saved.outcome?.code, equalTo(ReferralWithdrawalNsiOutcome.NSI7.name)) assertFalse(saved.active) val sh = statusHistoryRepo.findAll().firstOrNull { it.nsiId == nsi.id } @@ -316,7 +317,7 @@ internal class ReferAndMonitorIntegrationTest { "referralUrn" to "urn:hmpps:interventions-referral:68df9f6c-3fcb-4ec6-8fcf-96551cd9b080", "endDate" to "2023-02-23T15:29:54.197Z[Europe/London]", "endType" to "CANCELLED", - "withdrawalCode" to "NSI1", + "withdrawalOutcome" to "NSI7", ) ) } diff --git a/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmitted.kt b/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmitted.kt index 86882c7e51..97c136ec50 100644 --- a/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmitted.kt +++ b/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmitted.kt @@ -7,6 +7,8 @@ import uk.gov.justice.digital.hmpps.integrations.randm.ReferAndMonitorClient import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent import uk.gov.justice.digital.hmpps.messaging.DomainEventType.ReferralEnded import uk.gov.justice.digital.hmpps.messaging.EventProcessingResult.Success +import uk.gov.justice.digital.hmpps.messaging.ReferralWithdrawalNsiOutcome.* +import uk.gov.justice.digital.hmpps.messaging.ReferralWithdrawalState.PRE_ICA_WITHDRAWAL import uk.gov.justice.digital.hmpps.service.NsiService import java.net.URI import java.time.ZonedDateTime @@ -32,7 +34,7 @@ class ReferralEndSubmitted( sentReferral.endDate ?: throw IllegalStateException("No End Date for Termination: ${event.referralUrn()} => ${event.personReference.findCrn()}"), ReferralEndType.valueOf(event.deliveryState()), - event.withdrawalCode(), + sentReferral.withdrawalCode?.toOutcome(sentReferral.withdrawalState), sentReferral.notes(event.referralUiUrl()), sentReferral.endOfServiceReport?.submittedAt, sentReferral.notificationNotes(event.referralUiUrl()) @@ -46,14 +48,13 @@ class ReferralEndSubmitted( "referralUrn" to event.referralUrn(), "endDate" to sentReferral.endDate.toString(), "endType" to termination.endType.toString(), - termination.withdrawalCode?.let { "withdrawalCode" to it } + termination.withdrawalOutcome?.let { "withdrawalOutcome" to it.name }, ).toMap() ) } } fun HmppsDomainEvent.deliveryState() = additionalInformation["deliveryState"] as String -fun HmppsDomainEvent.withdrawalCode() = (additionalInformation["withdrawalCode"] as String?)?.takeIf { it.isNotEmpty() } fun HmppsDomainEvent.referralUrn() = additionalInformation["referralURN"] as String fun HmppsDomainEvent.referralUiUrl() = additionalInformation["referralProbationUserURL"] as String @@ -64,7 +65,9 @@ data class SentReferral( val sentAt: ZonedDateTime, val endRequestedAt: ZonedDateTime?, val concludedAt: ZonedDateTime?, - val endOfServiceReport: EndOfServiceReport? + val endOfServiceReport: EndOfServiceReport?, + val withdrawalState: ReferralWithdrawalState?, + val withdrawalCode: ReferralWithdrawalReason?, ) { val endDate = concludedAt ?: endRequestedAt fun notes(uiUrl: String) = @@ -98,6 +101,61 @@ enum class ReferralEndType(val outcome: String) { COMPLETED("CRS03") } +enum class ReferralWithdrawalState { + PRE_ICA_WITHDRAWAL, + POST_ICA_WITHDRAWAL, + POST_ICA_CLOSE_REFERRAL_EARLY, +} + +enum class ReferralWithdrawalReason( + val description: String, + private val preIcaOutcome: ReferralWithdrawalNsiOutcome, + private val postIcaOutcome: ReferralWithdrawalNsiOutcome = preIcaOutcome +) { + // Problem with referral + INE("Ineligible Referral", NSI1), + MIS("Mistaken or duplicate referral", NSI2), + + // User related + NOT("Not engaged", NSI11, NSI12), + NEE("Needs met through another route", NSI7, NSI8), + MOV("Moved out of service area", NSI5, NSI6), + WOR("Work or caring responsibilities", NSI3, NSi4), + USE("User died", NSI5, NSI6), + + // Sentence / custody related + ACQ("Acquitted on appeal", NSI5, NSI6), + RET("Returned to custody", NSI5, NSI6), + SER("Sentence revoked", NSI5, NSI6), + SEE("Sentence expired", NSI9, NSI10), + EAR("Intervention has been completed", NSI13), + + // Other + ANO("Another reason", CRS01); + + fun toOutcome(withdrawalState: ReferralWithdrawalState?): ReferralWithdrawalNsiOutcome { + val state = requireNotNull(withdrawalState) { "Withdrawal state not provided" } + return if (state == PRE_ICA_WITHDRAWAL) preIcaOutcome else postIcaOutcome + } +} + +enum class ReferralWithdrawalNsiOutcome(val description: String) { + NSI1("Ineligible referral"), + NSI2("Mistaken referral (inc Duplicate)"), + NSI3("Did not start (Work, Caring Commitments, Long-term Sickness)"), + NSi4("Started - Not finished (Work,Caring Commitments or Long-Term Sickness)"), // Note: intentional typo (NSI4 -> NSi4) to match Delius data + NSI5("Did not start – Changed Circumstances"), + NSI6("Started - Not finished (Changed Circumstances)"), + NSI7("Did not start - Needs met through another route"), + NSI8("Started - not finished (Needs met through another route)"), + NSI9("Did not start - Sentence Expired"), + NSI10("Started - Not finished (Sentence Expired)"), + NSI11("Did not start – Disengaged"), + NSI12("Started - Not finished (Disengaged)"), + NSI13("Completed"), + CRS01("Cancelled"), +} + data class EndOfServiceReport(val submittedAt: ZonedDateTime?) data class NsiTermination( @@ -107,7 +165,7 @@ data class NsiTermination( val startDate: ZonedDateTime, val endDate: ZonedDateTime, val endType: ReferralEndType, - val withdrawalCode: String?, + val withdrawalOutcome: ReferralWithdrawalNsiOutcome?, val notes: String, val notificationDateTime: ZonedDateTime?, val notificationNotes: String diff --git a/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/NsiService.kt b/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/NsiService.kt index d938c7e489..c2e8222517 100644 --- a/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/NsiService.kt +++ b/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/NsiService.kt @@ -77,7 +77,8 @@ class NsiService( fun terminateNsi(termination: NsiTermination) = audit(MANAGE_NSI) { audit -> val nsi = findNsi(termination) val status = nsiStatusRepository.getByCode(END.value) - val outcomeCode = termination.withdrawalCode.takeIf { featureFlags.enabled("referral-withdrawal-reason") } + val outcomeCode = termination.withdrawalOutcome?.name + ?.takeIf { featureFlags.enabled("referral-withdrawal-reason") } ?: termination.endType.outcome val outcome = nsiOutcomeRepository.nsiOutcome(outcomeCode) diff --git a/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmittedTest.kt b/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmittedTest.kt index bb1a509490..ee73126729 100644 --- a/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmittedTest.kt +++ b/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/ReferralEndSubmittedTest.kt @@ -22,7 +22,7 @@ import uk.gov.justice.digital.hmpps.message.PersonIdentifier import uk.gov.justice.digital.hmpps.message.PersonReference import uk.gov.justice.digital.hmpps.service.NsiService import java.time.ZonedDateTime -import java.util.UUID +import java.util.* @ExtendWith(MockitoExtension::class) internal class ReferralEndSubmittedTest { @@ -109,6 +109,8 @@ internal class ReferralEndSubmittedTest { ZonedDateTime.now().minusDays(1), endRequestedAt, null, + null, + null, null ) diff --git a/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/RepositoryExtensionMethodTests.kt b/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/RepositoryExtensionMethodTests.kt index d636dd7579..bdb1aa4ab3 100644 --- a/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/RepositoryExtensionMethodTests.kt +++ b/projects/refer-and-monitor-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/RepositoryExtensionMethodTests.kt @@ -79,7 +79,7 @@ internal class RepositoryExtensionMethodTests { ZonedDateTime.now().minusDays(1), ZonedDateTime.now(), ReferralEndType.CANCELLED, - "", + null, "Notes", ZonedDateTime.now(), "End Of Service Report Submitted" @@ -102,7 +102,7 @@ internal class RepositoryExtensionMethodTests { ZonedDateTime.now().minusDays(1), ZonedDateTime.now(), ReferralEndType.COMPLETED, - "", + null, "Notes", ZonedDateTime.now(), "End Of Service Report Submitted" @@ -129,7 +129,7 @@ internal class RepositoryExtensionMethodTests { ZonedDateTime.now().minusDays(1), ZonedDateTime.now(), ReferralEndType.COMPLETED, - "", + null, "Notes", ZonedDateTime.now(), "End Of Service Report Submitted"