Skip to content

Commit

Permalink
PI-2231 Add mapping from R&M withdrawal codes to NSI outcomes (#3885)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus-bcl authored Jun 11, 2024
1 parent d764932 commit 28e7d74
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ 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

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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
"authSource": "string",
"userId": "string"
}
}
},
"withdrawalCode": "NEE",
"withdrawalState": "PRE_ICA_WITHDRAWAL"
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 }
Expand All @@ -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",
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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())
Expand All @@ -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

Expand All @@ -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) =
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -109,6 +109,8 @@ internal class ReferralEndSubmittedTest {
ZonedDateTime.now().minusDays(1),
endRequestedAt,
null,
null,
null,
null
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ internal class RepositoryExtensionMethodTests {
ZonedDateTime.now().minusDays(1),
ZonedDateTime.now(),
ReferralEndType.CANCELLED,
"",
null,
"Notes",
ZonedDateTime.now(),
"End Of Service Report Submitted"
Expand All @@ -102,7 +102,7 @@ internal class RepositoryExtensionMethodTests {
ZonedDateTime.now().minusDays(1),
ZonedDateTime.now(),
ReferralEndType.COMPLETED,
"",
null,
"Notes",
ZonedDateTime.now(),
"End Of Service Report Submitted"
Expand All @@ -129,7 +129,7 @@ internal class RepositoryExtensionMethodTests {
ZonedDateTime.now().minusDays(1),
ZonedDateTime.now(),
ReferralEndType.COMPLETED,
"",
null,
"Notes",
ZonedDateTime.now(),
"End Of Service Report Submitted"
Expand Down

0 comments on commit 28e7d74

Please sign in to comment.