Skip to content

Commit

Permalink
PI-2889 new endpoint for pni calculation (#4743)
Browse files Browse the repository at this point in the history
  • Loading branch information
anthony-britton-moj authored Mar 3, 2025
1 parent 53d6352 commit 0addf14
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"source": "OASys",
"inputs": {
"crnSource": "pris",
"crn": "P467262",
"additionalParameter": "Y",
"laoPrivilege": "ALLOW"
},
"probNumber": "P467262",
"prisNumber": "A8747PN",
"limitedAccessOffender": false,
"pniCalc": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"source": "OASys",
"inputs": {
"crnSource": "pris",
"crn": "P467261",
"additionalParameter": "N",
"laoPrivilege": "ALLOW"
},
"probNumber": "P467261",
"prisNumber": "A8746PN",
"limitedAccessOffender": false,
"pniCalc": [
{
"offenderPk": 869584726,
"riskLevel": "L",
"missingFields": null,
"sexDomainLevel": "L",
"sexDomainScore": 0,
"thinkingDomainLevel": "M",
"thinkingDomainScore": 1,
"relationshipDomainLevel": "M",
"relationshipDomainScore": 1,
"selfManagementDomainLevel": "H",
"selfManagementDomainScore": 2,
"totalDomainScore": 4,
"overallNeedLevel": "M",
"pniCalculation": "A",
"saraRiskLevelToPartner": 1,
"saraRiskLevelToOther": 2
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,56 @@
"Content-Type": "application/json"
}
}
},
{
"request": {
"method": "GET",
"url": "/eor/oasys/ass/pnildc/pris/A8746PN:N/ALLOW",
"headers": {
"Authorization": {
"matches": "^Bearer oasys.token$"
}
}
},
"response": {
"status": 200,
"bodyFileName": "pni-calculation-success.json",
"headers": {
"Content-Type": "application/json"
}
}
},
{
"request": {
"method": "GET",
"url": "/eor/oasys/ass/pnildc/pris/A8747PN:Y/ALLOW",
"headers": {
"Authorization": {
"matches": "^Bearer oasys.token$"
}
}
},
"response": {
"status": 200,
"bodyFileName": "pni-calculation-no-calculation.json",
"headers": {
"Content-Type": "application/json"
}
}
},
{
"request": {
"method": "GET",
"url": "/eor/oasys/ass/pnildc/pris/A1741PN:N/ALLOW",
"headers": {
"Authorization": {
"matches": "^Bearer oasys.token$"
}
}
},
"response": {
"status": 404
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import uk.gov.justice.digital.hmpps.controller.*
import uk.gov.justice.digital.hmpps.integrations.oasys.Level
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken
import java.math.BigDecimal
import java.time.LocalDateTime
import uk.gov.justice.digital.hmpps.integrations.oasys.PniCalculation.Type as PniType

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = RANDOM_PORT)
Expand Down Expand Up @@ -109,4 +111,44 @@ internal class IntegrationTest {
)
)
}

@Test
fun `get pni success`() {
val res = mockMvc
.perform(get("/assessments/pni/A8746PN?community=false").withToken())
.andExpect(status().isOk)
.andReturn().response.contentAsJson<PniCalculation>()

assertThat(
res,
equalTo(
PniCalculation(
LevelScore(Level.L, 0),
LevelScore(Level.M, 1),
LevelScore(Level.M, 1),
LevelScore(Level.H, 2),
Level.L,
Level.M,
4,
PniType.A,
SaraRiskLevel(1, 2),
listOf(),
)
)
)
}

@Test
fun `get pni no calculation`() {
mockMvc
.perform(get("/assessments/pni/A8747PN?community=true").withToken())
.andExpect(status().isNoContent)
}

@Test
fun `get pni returns 404 if oasys returns 404`() {
mockMvc
.perform(get("/assessments/pni/A1741PN?community=false").withToken())
.andExpect(status().isNotFound)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.*
import org.springframework.web.client.HttpClientErrorException
import uk.gov.justice.digital.hmpps.advice.ErrorResponse
import uk.gov.justice.digital.hmpps.integrations.oasys.OrdsClient
import uk.gov.justice.digital.hmpps.integrations.oasys.asIntegrationModel
import uk.gov.justice.digital.hmpps.integrations.oasys.getRiskPredictors

@RestController
Expand All @@ -26,6 +27,16 @@ class AssessmentController(private val ordsClient: OrdsClient) {
@GetMapping("/{id}/risk-predictors")
fun getRiskPredictors(@PathVariable id: Long): RiskPrediction = ordsClient.getRiskPredictors(id)

@PreAuthorize("hasRole('PROBATION_API__ACCREDITED_PROGRAMMES__ASSESSMENT')")
@GetMapping("/pni/{nomsId}")
fun getPniCalculation(
@PathVariable nomsId: String,
@RequestParam community: Boolean
): ResponseEntity<PniCalculation> =
ordsClient.getPni(nomsId, if (community) "Y" else "N").asIntegrationModel()?.let {
ResponseEntity.ok(it)
} ?: ResponseEntity.noContent().build()

@ExceptionHandler
fun handleNotFound(e: HttpClientErrorException) = ResponseEntity
.status(e.statusCode)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package uk.gov.justice.digital.hmpps.controller

import uk.gov.justice.digital.hmpps.integrations.oasys.Level
import uk.gov.justice.digital.hmpps.integrations.oasys.PniCalculation.Type

data class PniCalculation(
val sexDomain: LevelScore,
val thinkingDomain: LevelScore,
val relationshipDomain: LevelScore,
val selfManagementDomain: LevelScore,
val riskLevel: Level,
val needLevel: Level,
val totalDomainScore: Int,
val pni: Type,
val saraRiskLevel: SaraRiskLevel,
val missingFields: List<String> = listOf(),
)

data class LevelScore(val level: Level, val score: Int)
data class SaraRiskLevel(val toPartner: Int, val toOther: Int)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ interface OrdsClient {

@GetExchange("/ass/riskscrass/ALLOW/{id}")
fun getAssessmentPredictors(@PathVariable id: Long): OasysRiskPredictors

@GetExchange("/ass/pnildc/pris/{nomsId}:{communityFlag}/ALLOW")
fun getPni(
@PathVariable nomsId: String,
@PathVariable communityFlag: String
): PniResult
}

fun OrdsClient.getRiskPredictors(assessmentId: Long): RiskPrediction =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package uk.gov.justice.digital.hmpps.integrations.oasys

import uk.gov.justice.digital.hmpps.controller.LevelScore
import uk.gov.justice.digital.hmpps.controller.SaraRiskLevel
import uk.gov.justice.digital.hmpps.controller.PniCalculation as IntegrationModel

data class PniResult(val pniCalc: List<PniCalculation>?)
data class PniCalculation(
val missingFields: List<String>?,
val riskLevel: Level,
val sexDomainLevel: Level,
val sexDomainScore: Int,
val thinkingDomainLevel: Level,
val thinkingDomainScore: Int,
val relationshipDomainLevel: Level,
val relationshipDomainScore: Int,
val selfManagementDomainLevel: Level,
val selfManagementDomainScore: Int,
val overallNeedLevel: Level,
val totalDomainScore: Int,
val pniCalculation: Type,
val saraRiskLevelToPartner: Int,
val saraRiskLevelToOther: Int,
) {
enum class Type {
H, M, A, O
}
}

enum class Level {
H, M, L
}

fun PniResult.asIntegrationModel(): IntegrationModel? = with(pniCalc?.firstOrNull()) {
if (this == null) null
else IntegrationModel(
sexDomain = LevelScore(sexDomainLevel, sexDomainScore),
thinkingDomain = LevelScore(thinkingDomainLevel, thinkingDomainScore),
relationshipDomain = LevelScore(relationshipDomainLevel, relationshipDomainScore),
selfManagementDomain = LevelScore(selfManagementDomainLevel, selfManagementDomainScore),
riskLevel = riskLevel,
needLevel = overallNeedLevel,
totalDomainScore = totalDomainScore,
pni = pniCalculation,
saraRiskLevel = SaraRiskLevel(saraRiskLevelToPartner, saraRiskLevelToOther),
missingFields = missingFields ?: listOf(),
)
}

0 comments on commit 0addf14

Please sign in to comment.