Skip to content

Commit

Permalink
PI-317 Added risk assessment scores consumer (#210)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus-bcl authored Oct 3, 2022
1 parent e8b0883 commit a38e1d0
Show file tree
Hide file tree
Showing 20 changed files with 290 additions and 56 deletions.
1 change: 1 addition & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ on:
- '["pre-sentence-reports-to-delius"]'
- '["prison-case-notes-to-probation"]'
- '["prison-custody-status-to-delius"]'
- '["risk-assessment-scores-to-delius"]'
- '["workforce-allocations-to-delius"]'
# GitHub Actions doesn't support dynamic choices, we must add each project here to enable manual deployments
# See https://github.com/community/community/discussions/11795
Expand Down
12 changes: 12 additions & 0 deletions .idea/runConfigurations/risk_assessment_scores_to_delius.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ class ZonedDateTimeDeserializer : JsonDeserializer<ZonedDateTime>() {
.optionalEnd()
.optionalEnd()
.toFormatter()

fun deserialize(text: String): ZonedDateTime {
val datetime = formatter.parseBest(text, ZonedDateTime::from, LocalDateTime::from)
return if (datetime is ZonedDateTime) datetime.withZoneSameInstant(EuropeLondon)
else (datetime as LocalDateTime).atZone(EuropeLondon)
}
}

@Throws(IOException::class, JsonProcessingException::class)
override fun deserialize(parser: JsonParser, context: DeserializationContext?): ZonedDateTime {
val datetime = formatter.parseBest(parser.text, ZonedDateTime::from, LocalDateTime::from)
return if (datetime is ZonedDateTime) datetime.withZoneSameInstant(EuropeLondon)
else (datetime as LocalDateTime).atZone(EuropeLondon)
}
override fun deserialize(parser: JsonParser, context: DeserializationContext?) = deserialize(parser.text)
}
27 changes: 13 additions & 14 deletions projects/risk-assessment-scores-to-delius/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,27 @@ Sample message:

```json
{
"eventType": "risk-assessment.scores.determined",
"eventType": "risk-assessment.scores.rsr.determined",
"version": 1,
"description": "Risk assessment scores have been determined",
"detailUrl": "https://some-url-where-we-can-get-more-info",
"occurredAt": "2022-12-04T10:42:43+00:00",
"detailUrl": "https://some-url-where-we-can-get-more-info-this-might-not-exist",
"occurredAt": "2022-09-22T12:16:04+01:00",
"additionalInformation": {
"RSRScore": 0,
"RSRBand": 0,
"OSPIndecentScore": 0,
"OSPIndecentBand": 0,
"OSPContactScore": 0,
"OSPContactBand": 0,
"EventNumber": 0,
"OGRS3Yr1": 0,
"OGRS3Yr2": 0,
"AssessmentDate": "2022-12-04T10:42:43+00:00"
"RSRScore": 45.33,
"RSRBand": "H",
"RSRStaticOrDynamic": "STATIC",
"OSPIndecentScore": 5.79,
"OSPIndecentBand": "H",
"OSPContactScore": 38.70,
"OSPContactBand": "V",
"EventNumber": 1,
"AssessmentDate": "2022-09-22T12:16:04+01:00"
},
"personReference": {
"identifiers": [
{
"type": "CRN",
"value": "X08769"
"value": "X552020"
}
]
}
Expand Down
3 changes: 1 addition & 2 deletions projects/risk-assessment-scores-to-delius/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ dependencies {

implementation("org.springframework:spring-jms")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
environment_name: delius-test

enabled: false # TODO set this to true when you're ready to deploy your service

env:
SENTRY_ENVIRONMENT: dev
LOGGING_LEVEL_UK_GOV_DIGITAL_JUSTICE_HMPPS: DEBUG
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
environment_name: delius-pre-prod

enabled: false # TODO set this to true when you're ready to deploy your service

env:
SENTRY_ENVIRONMENT: preprod
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
environment_name: delius-prod

enabled: false # TODO set this to true when you're ready to deploy your service

env:
SENTRY_ENVIRONMENT: prod
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ secrets:
SPRING_DATASOURCE_URL: /delius-database/jdbc-url
SPRING_DATASOURCE_USERNAME: /risk-assessment-scores-to-delius/db-username
SPRING_DATASOURCE_PASSWORD: /risk-assessment-scores-to-delius/db-password
SPRING_JMS_TEMPLATE_DEFAULT-DESTINATION: /risk-assessment-scores-to-delius/queue-name
SPRING_JMS_TEMPLATE_DEFAULT-DESTINATION: /risk-assessment-scores-to-delius/sqs-queue-name
SENTRY_DSN: /risk-assessment-scores-to-delius/sentry-dsn
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package uk.gov.justice.digital.hmpps

import uk.gov.justice.digital.hmpps.message.HmppsEvent
import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader

object MessageGenerator {
val RSR_SCORES_DETERMINED = ResourceLoader.message<HmppsEvent>("rsr-scores-determined")
val OGRS_SCORES_DETERMINED = ResourceLoader.message<HmppsEvent>("ogrs-scores-determined")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
drop schema if exists pkg_triggersupport cascade;

create schema pkg_triggersupport;
create alias pkg_triggersupport.procRsrUpdateCas as 'void stub() {}';
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-- As of 30/09/2022, the procedure is not yet available in the Delius OracleDB so I've left this SQL here to help with local testing.

create or replace package pkg_triggersupport as
procedure procRsrUpdateCas(
p_crn in varchar2,
p_event_number in int,
p_rsr_assessor_date in timestamp,
p_rsr_score in float,
p_rsr_band in varchar2,
p_osp_indecent_score in float,
p_osp_indecent_band in varchar2,
p_osp_contact_score in float,
p_osp_contact_band in varchar2,
p_error out varchar2
);
end pkg_triggersupport;
grant execute on pkg_triggersupport to delius_app_schema;

create or replace package body pkg_triggersupport as
procedure procRsrUpdateCas(
p_crn in varchar2,
p_event_number in int,
p_rsr_assessor_date in timestamp,
p_rsr_score in float,
p_rsr_band in varchar2,
p_osp_indecent_score in float,
p_osp_indecent_band in varchar2,
p_osp_contact_score in float,
p_osp_contact_band in varchar2,
p_error out varchar2
) is
begin
-- For testing:
if length(p_crn) != 7 then p_error := 'Invalid CRN'; end if;
-- ...
end procRsrUpdateCas;
end pkg_triggersupport;
/
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"Type": "Notification",
"MessageId": "",
"TopicArn": "",
"Message": "{\"eventType\":\"risk-assessment.scores.ogrs.determined\",\"version\":1,\"description\":\"Risk assessment scores have been determined\",\"detailUrl\":\"https://some-url-where-we-can-get-more-info-this-might-not-exist\",\"occurredAt\":\"2022-09-15T15:34:48+01:00\",\"additionalInformation\":{\"OGRS3Yr1\":4,\"OGRS3Yr2\":8,\"EventNumber\":1,\"AssessmentDate\":\"2022-09-15T15:34:48+01:00\"},\"personReference\":{\"identifiers\":[{\"type\":\"CRN\",\"value\":\"X552020\"}]}}",
"Timestamp": "2022-09-15T14:34:48.123Z",
"SignatureVersion": "1",
"Signature": "",
"SigningCertURL": "",
"UnsubscribeURL": "",
"MessageAttributes": {
"eventType": {
"Type": "String",
"Value": "risk-assessment.scores.ogrs.determined"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"Type": "Notification",
"MessageId": "",
"TopicArn": "",
"Message": "{\"eventType\":\"risk-assessment.scores.rsr.determined\",\"version\":1,\"description\":\"Risk assessment scores have been determined\",\"detailUrl\":\"https://some-url-where-we-can-get-more-info-this-might-not-exist\",\"occurredAt\":\"2022-09-22T12:16:04+01:00\",\"additionalInformation\":{\"RSRScore\":45.33,\"RSRBand\":\"H\",\"RSRStaticOrDynamic\":\"STATIC\",\"OSPIndecentScore\":5.79,\"OSPIndecentBand\":\"H\",\"OSPContactScore\":38.7,\"OSPContactBand\":\"V\",\"EventNumber\":1,\"AssessmentDate\":\"2022-09-22T12:16:04+01:00\"},\"personReference\":{\"identifiers\":[{\"type\":\"CRN\",\"value\":\"X552020\"}]}}",
"Timestamp": "2022-05-04T08:06:46.704Z",
"SignatureVersion": "1",
"Signature": "",
"SigningCertURL": "",
"UnsubscribeURL": "",
"MessageAttributes": {
"eventType": {
"Type": "String",
"Value": "risk-assessment.scores.rsr.determined"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
package uk.gov.justice.digital.hmpps

import org.junit.jupiter.api.Test
import org.mockito.kotlin.verify
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 org.springframework.jms.core.JmsTemplate
import org.springframework.test.context.ActiveProfiles
import uk.gov.justice.digital.hmpps.jms.convertSendAndWait
import uk.gov.justice.digital.hmpps.listener.telemetryProperties
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService

@SpringBootTest
@ActiveProfiles("integration-test")
internal class IntegrationTest {
@Value("\${spring.jms.template.default-destination}")
private lateinit var queueName: String

@Autowired
private lateinit var jmsTemplate: JmsTemplate

@MockBean
private lateinit var telemetryService: TelemetryService

@Test
fun `the context loads`() {}
fun `successfully update RSR scores`() {
val message = MessageGenerator.RSR_SCORES_DETERMINED
jmsTemplate.convertSendAndWait(queueName, message)
verify(telemetryService).trackEvent("RsrScoresUpdated", message.telemetryProperties())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package uk.gov.justice.digital.hmpps.exception

class FailureToUpdateRiskScores(override val message: String) : RuntimeException(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package uk.gov.justice.digital.hmpps.integrations.delius

import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource
import org.springframework.jdbc.core.simple.SimpleJdbcCall
import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.exception.FailureToUpdateRiskScores
import java.time.ZonedDateTime

@Service
class RiskScoreService(jdbcTemplate: JdbcTemplate) {
private val updateRsrScoresProcedure = SimpleJdbcCall(jdbcTemplate)
.withCatalogName("pkg_triggersupport")
.withProcedureName("procRsrUpdateCas")

fun updateRsrScores(
crn: String,
eventNumber: Int,
assessmentDate: ZonedDateTime,
rsrScore: Double,
rsrBand: String,
ospIndecentScore: Double,
ospIndecentBand: String,
ospContactScore: Double,
ospContactBand: String,
) {
val result = updateRsrScoresProcedure.execute(
MapSqlParameterSource()
.addValue("p_crn", crn)
.addValue("p_event_number", eventNumber)
.addValue("p_rsr_assessor_date", assessmentDate)
.addValue("p_rsr_score", rsrScore)
.addValue("p_rsr_band", rsrBand)
.addValue("p_osp_indecent_score", ospIndecentScore)
.addValue("p_osp_indecent_band", ospIndecentBand)
.addValue("p_osp_contact_score", ospContactScore)
.addValue("p_osp_contact_band", ospContactBand)
)
result["P_ERROR"]?.let { throw FailureToUpdateRiskScores(it as String) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import org.slf4j.LoggerFactory
import org.springframework.jms.annotation.EnableJms
import org.springframework.jms.annotation.JmsListener
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.datetime.ZonedDateTimeDeserializer
import uk.gov.justice.digital.hmpps.integrations.delius.RiskScoreService
import uk.gov.justice.digital.hmpps.message.HmppsEvent
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService

@Component
@EnableJms
class MessageListener(private val telemetryService: TelemetryService) {

class MessageListener(
private val telemetryService: TelemetryService,
private val riskScoreService: RiskScoreService,
) {
companion object {
val log: Logger = LoggerFactory.getLogger(this::class.java)
}
Expand All @@ -20,6 +24,32 @@ class MessageListener(private val telemetryService: TelemetryService) {
fun receive(hmppsEvent: HmppsEvent) {
log.debug("received $hmppsEvent")
telemetryService.hmppsEventReceived(hmppsEvent)
TODO("Not yet implemented")
when (hmppsEvent.eventType) {
"risk-assessment.scores.rsr.determined" -> {
riskScoreService.updateRsrScores(
hmppsEvent.personReference.findCrn() ?: throw IllegalArgumentException("Missing CRN in ${hmppsEvent.personReference}"),
hmppsEvent.additionalInformation["EventNumber"] as Int,
(hmppsEvent.additionalInformation["AssessmentDate"] as String).toDate(),
hmppsEvent.additionalInformation["RSRScore"] as Double,
hmppsEvent.additionalInformation["RSRBand"] as String,
hmppsEvent.additionalInformation["OSPIndecentScore"] as Double,
hmppsEvent.additionalInformation["OSPIndecentBand"] as String,
hmppsEvent.additionalInformation["OSPContactScore"] as Double,
hmppsEvent.additionalInformation["OSPContactBand"] as String,
)
telemetryService.trackEvent("RsrScoresUpdated", hmppsEvent.telemetryProperties())
}
"risk-assessment.scores.ogrs.determined" ->
telemetryService.trackEvent("UnsupportedEventType", hmppsEvent.telemetryProperties())
else -> throw IllegalArgumentException("Unexpected event type ${hmppsEvent.eventType}")
}
}
}

fun HmppsEvent.telemetryProperties() = mapOf(
"occurredAt" to occurredAt.toString(),
"personReference" to personReference.toString(),
"additionalInformation" to additionalInformation.toString(),
)

fun String.toDate() = ZonedDateTimeDeserializer.deserialize(this)
Loading

0 comments on commit a38e1d0

Please sign in to comment.