Skip to content

Commit 8901851

Browse files
Added endpoint to return NOMS number.
1 parent 8659cf3 commit 8901851

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/HmppsIdController.kt

+34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.controllers.v1
22

3+
import io.swagger.v3.oas.annotations.Operation
4+
import io.swagger.v3.oas.annotations.responses.ApiResponse
35
import io.swagger.v3.oas.annotations.tags.Tag
6+
import jakarta.validation.ValidationException
47
import org.springframework.beans.factory.annotation.Autowired
58
import org.springframework.web.bind.annotation.GetMapping
69
import org.springframework.web.bind.annotation.PathVariable
@@ -10,6 +13,7 @@ import uk.gov.justice.digital.hmpps.hmppsintegrationapi.exception.EntityNotFound
1013
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.decodeUrlCharacters
1114
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.DataResponse
1215
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.HmppsId
16+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.NomisNumber
1317
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
1418
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetHmppsIdService
1519
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService
@@ -37,4 +41,34 @@ class HmppsIdController(
3741

3842
return DataResponse(response.data)
3943
}
44+
45+
@GetMapping("{encodedNomisNumber}/nomis-number")
46+
@Operation(
47+
summary = "Return NOMS number for a given hmpps Id",
48+
description = """Accepts a HMPPS Id (hmppsId) and looks up the corresponding NOMS number.
49+
""",
50+
responses = [
51+
ApiResponse(responseCode = "200", useReturnTypeSchema = true),
52+
ApiResponse(responseCode = "404", description = "NOMS number could not be found."),
53+
ApiResponse(responseCode = "400", description = "Invalid hmppsId."),
54+
],
55+
)
56+
fun getNomisNumberByHMPPSID(
57+
@PathVariable encodedNomisNumber: String,
58+
): DataResponse<NomisNumber?> {
59+
val hmppsId = encodedNomisNumber.decodeUrlCharacters()
60+
61+
val response = getHmppsIdService.getNomisNumber(hmppsId)
62+
63+
if (response.hasError(UpstreamApiError.Type.ENTITY_NOT_FOUND)) {
64+
throw EntityNotFoundException("Could not find nomis number for HMPPS ID: $hmppsId")
65+
}
66+
if (response.hasError(UpstreamApiError.Type.BAD_REQUEST)) {
67+
throw ValidationException("Invalid HMPPS ID: $hmppsId")
68+
}
69+
70+
auditService.createEvent("GET_NOMIS_NUMBER_BY_HMPPS_ID", mapOf("hmppsId" to hmppsId))
71+
72+
return DataResponse(response.data)
73+
}
4074
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps
2+
3+
data class NomisNumber(
4+
val nomisNumber: String? = null,
5+
)

src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetHmppsIdService.kt

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package uk.gov.justice.digital.hmpps.hmppsintegrationapi.services
33
import org.springframework.beans.factory.annotation.Autowired
44
import org.springframework.stereotype.Service
55
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.HmppsId
6+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.NomisNumber
67
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
78

89
@Service
@@ -17,4 +18,13 @@ class GetHmppsIdService(
1718
errors = personResponse.errors,
1819
)
1920
}
21+
22+
fun getNomisNumber(hmppsId: String): Response<NomisNumber?> {
23+
val nomisResponse = getPersonService.getNomisNumber(hmppsId = hmppsId)
24+
25+
return Response(
26+
data = NomisNumber(nomisNumber = nomisResponse.data?.nomisNumber),
27+
errors = nomisResponse.errors,
28+
)
29+
}
2030
}

src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPersonService.kt

+65
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import org.springframework.beans.factory.annotation.Autowired
44
import org.springframework.stereotype.Service
55
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.PrisonerOffenderSearchGateway
66
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ProbationOffenderSearchGateway
7+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.NomisNumber
78
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.OffenderSearchResponse
89
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Person
910
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
11+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi
12+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
1013

1114
@Service
1215
class GetPersonService(
@@ -19,6 +22,68 @@ class GetPersonService(
1922
return Response(data = personFromProbationOffenderSearch.data, errors = personFromProbationOffenderSearch.errors)
2023
}
2124

25+
enum class IdentifierType {
26+
NOMS,
27+
CRN,
28+
UNKNOWN,
29+
}
30+
31+
fun identifyHmppsId(input: String): IdentifierType {
32+
val nomsPattern = Regex("^[A-Z]\\d{4}[A-Z]{2}$")
33+
val crnPattern = Regex("^[A-Z]{2}\\d{6}$")
34+
35+
return when {
36+
nomsPattern.matches(input) -> IdentifierType.NOMS
37+
crnPattern.matches(input) -> IdentifierType.CRN
38+
else -> IdentifierType.UNKNOWN
39+
}
40+
}
41+
42+
/**
43+
* Identify whether the hmppsId is a noms number or a crn
44+
* When it is a noms number then return it.
45+
* When it is a CRN look up the prisoner in probation offender search and then return it
46+
*/
47+
fun getNomisNumber(hmppsId: String): Response<NomisNumber?> {
48+
return when (identifyHmppsId(hmppsId)) {
49+
IdentifierType.NOMS -> Response(data = NomisNumber(hmppsId))
50+
51+
IdentifierType.CRN -> {
52+
val personFromProbationOffenderSearch = probationOffenderSearchGateway.getPerson(id = hmppsId)
53+
val nomisNumber = personFromProbationOffenderSearch.data?.identifiers?.nomisNumber
54+
val errors = personFromProbationOffenderSearch.errors.toMutableList()
55+
56+
if (nomisNumber == null) {
57+
errors.add(
58+
UpstreamApiError(
59+
description = "NOMIS number not found",
60+
type = UpstreamApiError.Type.ENTITY_NOT_FOUND,
61+
causedBy = UpstreamApi.PROBATION_OFFENDER_SEARCH,
62+
),
63+
)
64+
}
65+
66+
Response(
67+
data = nomisNumber?.let { NomisNumber(it) },
68+
errors = errors,
69+
)
70+
}
71+
72+
IdentifierType.UNKNOWN ->
73+
Response(
74+
data = null,
75+
errors =
76+
listOf(
77+
UpstreamApiError(
78+
description = "Invalid HMPPS ID: $hmppsId",
79+
type = UpstreamApiError.Type.BAD_REQUEST,
80+
causedBy = UpstreamApi.NOMIS,
81+
),
82+
),
83+
)
84+
}
85+
}
86+
2287
fun getCombinedDataForPerson(hmppsId: String): Response<OffenderSearchResponse> {
2388
val probationResponse = probationOffenderSearchGateway.getPerson(id = hmppsId)
2489

0 commit comments

Comments
 (0)