Skip to content

Commit 96d9a42

Browse files
authored
HMAI-308-person-responsible-filter (#749)
* Person responsible officer endpoint filter support * Added missing status code schema decorator * fixed service test
1 parent 919883e commit 96d9a42

File tree

8 files changed

+70
-34
lines changed

8 files changed

+70
-34
lines changed

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

+13-6
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import io.swagger.v3.oas.annotations.media.Content
66
import io.swagger.v3.oas.annotations.media.Schema
77
import io.swagger.v3.oas.annotations.responses.ApiResponse
88
import io.swagger.v3.oas.annotations.tags.Tag
9+
import jakarta.validation.ValidationException
910
import org.springframework.beans.factory.annotation.Autowired
1011
import org.springframework.web.bind.annotation.GetMapping
1112
import org.springframework.web.bind.annotation.PathVariable
13+
import org.springframework.web.bind.annotation.RequestAttribute
1214
import org.springframework.web.bind.annotation.RequestMapping
1315
import org.springframework.web.bind.annotation.RestController
1416
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.exception.EntityNotFoundException
15-
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.decodeUrlCharacters
1617
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.DataResponse
1718
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficer
1819
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
20+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.roleconfig.ConsumerFilters
1921
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetCommunityOffenderManagerForPersonService
2022
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetPrisonOffenderManagerForPersonService
2123
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService
@@ -28,21 +30,26 @@ class PersonResponsibleOfficerController(
2830
@Autowired val getPrisonOffenderManagerForPersonService: GetPrisonOffenderManagerForPersonService,
2931
@Autowired val getCommunityOffenderManagerForPersonService: GetCommunityOffenderManagerForPersonService,
3032
) {
31-
@GetMapping("{encodedHmppsId}/person-responsible-officer")
33+
@GetMapping("{hmppsId}/person-responsible-officer")
3234
@Operation(
3335
summary = "Returns the person responsible officer associated with a person.",
3436
responses = [
3537
ApiResponse(responseCode = "200", useReturnTypeSchema = true, description = "Successfully found the person responsible officer for a person with the provided HMPPS ID."),
3638
ApiResponse(responseCode = "404", content = [Content(schema = Schema(ref = "#/components/schemas/PersonNotFound"))]),
39+
ApiResponse(responseCode = "400", content = [Content(schema = Schema(ref = "#/components/schemas/BadRequest"))]),
3740
ApiResponse(responseCode = "500", content = [Content(schema = Schema(ref = "#/components/schemas/InternalServerError"))]),
3841
],
3942
)
4043
fun getPersonResponsibleOfficer(
41-
@Parameter(description = "A URL-encoded HMPPS identifier", example = "2008%2F0545166T") @PathVariable encodedHmppsId: String,
44+
@Parameter(description = "A HMPPS identifier") @PathVariable hmppsId: String,
45+
@RequestAttribute filters: ConsumerFilters?,
4246
): DataResponse<PersonResponsibleOfficer> {
43-
val hmppsId = encodedHmppsId.decodeUrlCharacters()
44-
val prisonOffenderManager = getPrisonOffenderManagerForPersonService.execute(hmppsId)
45-
val communityOffenderManager = getCommunityOffenderManagerForPersonService.execute(hmppsId)
47+
val prisonOffenderManager = getPrisonOffenderManagerForPersonService.execute(hmppsId, filters)
48+
val communityOffenderManager = getCommunityOffenderManagerForPersonService.execute(hmppsId, filters)
49+
50+
if (prisonOffenderManager.hasError(UpstreamApiError.Type.BAD_REQUEST) || communityOffenderManager.hasError(UpstreamApiError.Type.BAD_REQUEST)) {
51+
throw ValidationException("Invalid HMPPS ID: $hmppsId")
52+
}
4653

4754
if (prisonOffenderManager.hasError(UpstreamApiError.Type.ENTITY_NOT_FOUND)) {
4855
throw EntityNotFoundException("Could not find prison offender manager related to id: $hmppsId")

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ import org.springframework.stereotype.Service
55
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.NDeliusGateway
66
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.CommunityOffenderManager
77
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
8+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.roleconfig.ConsumerFilters
89

910
@Service
1011
class GetCommunityOffenderManagerForPersonService(
1112
@Autowired val getPersonService: GetPersonService,
1213
@Autowired val nDeliusGateway: NDeliusGateway,
1314
) {
14-
fun execute(hmppsId: String): Response<CommunityOffenderManager> {
15-
val personResponse = getPersonService.execute(hmppsId = hmppsId)
15+
fun execute(
16+
hmppsId: String,
17+
filters: ConsumerFilters?,
18+
): Response<CommunityOffenderManager> {
19+
val personResponse = getPersonService.getPersonWithPrisonFilter(hmppsId, filters)
1620

1721
val deliusCrn = personResponse.data?.identifiers?.deliusCrn
1822
var nDeliusMappaDetailResponse: Response<CommunityOffenderManager> = Response(data = CommunityOffenderManager())

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

+8-3
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@ import org.springframework.stereotype.Service
55
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ManagePOMCaseGateway
66
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonOffenderManager
77
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
8+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.roleconfig.ConsumerFilters
89

910
@Service
1011
class GetPrisonOffenderManagerForPersonService(
1112
@Autowired val getPersonService: GetPersonService,
1213
@Autowired val managePOMCaseGateway: ManagePOMCaseGateway,
1314
) {
14-
fun execute(hmppsId: String): Response<PrisonOffenderManager> {
15-
val personResponse = getPersonService.execute(hmppsId = hmppsId)
16-
val nomisNumber = personResponse.data?.identifiers?.nomisNumber
15+
fun execute(
16+
hmppsId: String,
17+
filters: ConsumerFilters?,
18+
): Response<PrisonOffenderManager> {
19+
val personResponse = getPersonService.getNomisNumberWithPrisonFilter(hmppsId, filters)
20+
21+
val nomisNumber = personResponse.data?.nomisNumber
1722
var prisonOffenderManager: Response<PrisonOffenderManager> = Response(data = PrisonOffenderManager())
1823

1924
if (nomisNumber != null) {

src/main/resources/globals.yml

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ globals:
1919
- "/v1/persons/.*/cell-location"
2020
- "/v1/persons/.*/risks/categories"
2121
- "/v1/persons/.*/sentences"
22+
- "/v1/persons/.*/person-responsible-officer"
2223
- "/v1/persons/.*/protected-characteristics"
2324
- "/v1/persons/.*/reported-adjudications"
2425
- "/v1/prison/prisoners"

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/PersonResponsibleOfficerControllerTest.kt

+6-8
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
2424
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetCommunityOffenderManagerForPersonService
2525
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetPrisonOffenderManagerForPersonService
2626
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService
27-
import java.net.URLEncoder
28-
import java.nio.charset.StandardCharsets
2927

3028
@WebMvcTest(controllers = [PersonResponsibleOfficerController::class])
3129
@ActiveProfiles("test")
@@ -36,16 +34,16 @@ internal class PersonResponsibleOfficerControllerTest(
3634
@MockitoBean val getPrisonOffenderManagerForPersonService: GetPrisonOffenderManagerForPersonService,
3735
) : DescribeSpec() {
3836
init {
39-
val hmppsId = "9999/11111A"
40-
val encodedHmppsId = URLEncoder.encode(hmppsId, StandardCharsets.UTF_8)
41-
val path = "/v1/persons/$encodedHmppsId/person-responsible-officer"
37+
val hmppsId = "11111A"
38+
val path = "/v1/persons/$hmppsId/person-responsible-officer"
4239
val mockMvc = IntegrationAPIMockMvc(springMockMvc)
40+
val filters = null
4341

4442
describe("GET $path") {
4543
beforeTest {
4644
Mockito.reset(getPrisonOffenderManagerForPersonService)
4745
Mockito.reset(getCommunityOffenderManagerForPersonService)
48-
whenever(getPrisonOffenderManagerForPersonService.execute(hmppsId)).thenReturn(
46+
whenever(getPrisonOffenderManagerForPersonService.execute(hmppsId, filters)).thenReturn(
4947
Response(
5048
PrisonOffenderManager(
5149
forename = "Paul",
@@ -55,7 +53,7 @@ internal class PersonResponsibleOfficerControllerTest(
5553
),
5654
)
5755

58-
whenever(getCommunityOffenderManagerForPersonService.execute(hmppsId)).thenReturn(
56+
whenever(getCommunityOffenderManagerForPersonService.execute(hmppsId, filters)).thenReturn(
5957
Response(
6058
CommunityOffenderManager(
6159
name = PersonResponsibleOfficerName("Helen", surname = "Miller"),
@@ -82,7 +80,7 @@ internal class PersonResponsibleOfficerControllerTest(
8280

8381
it("gets the person responsible officer for a person with the matching ID") {
8482
mockMvc.performAuthorised(path)
85-
verify(getCommunityOffenderManagerForPersonService, VerificationModeFactory.times(1)).execute(hmppsId)
83+
verify(getCommunityOffenderManagerForPersonService, VerificationModeFactory.times(1)).execute(hmppsId, filters)
8684
}
8785

8886
it("logs audit") {

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/integration/person/PersonResponsibleOfficerIntegrationTest.kt

+19-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,26 @@ import uk.gov.justice.digital.hmpps.hmppsintegrationapi.integration.IntegrationT
88
class PersonResponsibleOfficerIntegrationTest : IntegrationTestBase() {
99
@Test
1010
fun `returns needs for a person`() {
11-
callApi("$basePath/$pnc/person-responsible-officer")
11+
callApi("$basePath/$nomsId/person-responsible-officer")
1212
.andExpect(status().isOk)
1313
.andExpect(content().json(getExpectedResponse("person-responsible-officer")))
1414
}
15+
16+
@Test
17+
fun `adjudications returns a 400 if the hmppsId is invalid`() {
18+
callApi("$basePath/$invalidNomsId/person-responsible-officer")
19+
.andExpect(status().isBadRequest)
20+
}
21+
22+
@Test
23+
fun `return a 404 for person in wrong prison`() {
24+
callApiWithCN("$basePath/$nomsId/person-responsible-officer", limitedPrisonsCn)
25+
.andExpect(status().isNotFound)
26+
}
27+
28+
@Test
29+
fun `return a 404 when no prisons in filter`() {
30+
callApiWithCN("$basePath/$nomsId/person-responsible-officer", noPrisonsCn)
31+
.andExpect(status().isNotFound)
32+
}
1533
}

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetCommunityOffenderManagerForPersonServiceTest.kt

+8-7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class GetCommunityOffenderManagerForPersonServiceTest(
3131
{
3232
val hmppsId = "1234/56789B"
3333
val deliusCrn = "X224466"
34+
val filter = null
3435

3536
val person = Person(firstName = "Sam", lastName = "Smith", identifiers = Identifiers(deliusCrn = deliusCrn))
3637

@@ -40,27 +41,27 @@ class GetCommunityOffenderManagerForPersonServiceTest(
4041
Mockito.reset(getPersonService)
4142
Mockito.reset(nDeliusGateway)
4243

43-
whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn(Response(person))
44+
whenever(getPersonService.getPersonWithPrisonFilter(hmppsId = hmppsId, filter)).thenReturn(Response(person))
4445
whenever(nDeliusGateway.getCommunityOffenderManagerForPerson(id = deliusCrn)).thenReturn(Response(communityOffenderManager))
4546
}
4647

4748
it("performs a search according to hmpps Id") {
48-
getCommunityOffenderManagerForPersonService.execute(hmppsId)
49-
verify(getPersonService, VerificationModeFactory.times(1)).execute(hmppsId = hmppsId)
49+
getCommunityOffenderManagerForPersonService.execute(hmppsId, filter)
50+
verify(getPersonService, VerificationModeFactory.times(1)).getPersonWithPrisonFilter(hmppsId = hmppsId, filter)
5051
}
5152

5253
it("Returns a community offender manager for person given a hmppsId") {
53-
whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn(
54+
whenever(getPersonService.getPersonWithPrisonFilter(hmppsId, filter)).thenReturn(
5455
Response(
5556
data = person,
5657
),
5758
)
58-
val result = getCommunityOffenderManagerForPersonService.execute(hmppsId)
59+
val result = getCommunityOffenderManagerForPersonService.execute(hmppsId, filter)
5960
result.shouldBe(Response(data = communityOffenderManager))
6061
}
6162

6263
it("should return a list of errors if person not found") {
63-
whenever(getPersonService.execute(hmppsId = "NOT_FOUND")).thenReturn(
64+
whenever(getPersonService.getPersonWithPrisonFilter(hmppsId = "NOT_FOUND", filter)).thenReturn(
6465
Response(
6566
data = null,
6667
errors =
@@ -72,7 +73,7 @@ class GetCommunityOffenderManagerForPersonServiceTest(
7273
),
7374
),
7475
)
75-
val result = getCommunityOffenderManagerForPersonService.execute("NOT_FOUND")
76+
val result = getCommunityOffenderManagerForPersonService.execute("NOT_FOUND", filter)
7677
result.data.shouldBe(CommunityOffenderManager())
7778
result.errors
7879
.first()

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPrisonOffenderManagerForPersonServiceTest.kt

+9-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.springframework.test.context.ContextConfiguration
1111
import org.springframework.test.context.bean.override.mockito.MockitoBean
1212
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ManagePOMCaseGateway
1313
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Identifiers
14+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.NomisNumber
1415
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Person
1516
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Prison
1617
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonOffenderManager
@@ -28,23 +29,24 @@ class GetPrisonOffenderManagerForPersonServiceTest(
2829
private val getPrisonOffenderManagerForPersonService: GetPrisonOffenderManagerForPersonService,
2930
) : DescribeSpec(
3031
{
31-
val hmppsId = "1234/56789B"
32+
val hmppsId = "56789B"
3233
val nomisNumber = "Z99999ZZ"
3334
val person = Person(firstName = "Julianna", lastName = "Blake", identifiers = Identifiers(nomisNumber = nomisNumber))
35+
val filters = null
3436

3537
val prisonOffenderManager = PrisonOffenderManager(forename = "Paul", surname = "Smith", prison = Prison(code = "RED"))
3638

3739
beforeEach {
3840
Mockito.reset(getPersonService)
3941
Mockito.reset(managePOMCaseGateway)
4042

41-
whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn(Response(person))
43+
whenever(getPersonService.getNomisNumberWithPrisonFilter(hmppsId = hmppsId, filters)).thenReturn(Response(NomisNumber(nomisNumber)))
4244
whenever(managePOMCaseGateway.getPrimaryPOMForNomisNumber(id = nomisNumber)).thenReturn(Response(prisonOffenderManager))
4345
}
4446

4547
it("performs a search according to hmpps Id") {
46-
getPrisonOffenderManagerForPersonService.execute(hmppsId)
47-
verify(getPersonService, VerificationModeFactory.times(1)).execute(hmppsId = hmppsId)
48+
getPrisonOffenderManagerForPersonService.execute(hmppsId, filters)
49+
verify(getPersonService, VerificationModeFactory.times(1)).getNomisNumberWithPrisonFilter(hmppsId = hmppsId, filters)
4850
}
4951

5052
it("Returns a prison offender manager for person given a hmppsId") {
@@ -53,12 +55,12 @@ class GetPrisonOffenderManagerForPersonServiceTest(
5355
data = person,
5456
),
5557
)
56-
val result = getPrisonOffenderManagerForPersonService.execute(hmppsId)
58+
val result = getPrisonOffenderManagerForPersonService.execute(hmppsId, filters)
5759
result.shouldBe(Response(data = prisonOffenderManager))
5860
}
5961

6062
it("should return a list of errors if person not found") {
61-
whenever(getPersonService.execute(hmppsId = "NOT_FOUND")).thenReturn(
63+
whenever(getPersonService.getNomisNumberWithPrisonFilter(hmppsId = "NOT_FOUND", filters)).thenReturn(
6264
Response(
6365
data = null,
6466
errors =
@@ -70,7 +72,7 @@ class GetPrisonOffenderManagerForPersonServiceTest(
7072
),
7173
),
7274
)
73-
val result = getPrisonOffenderManagerForPersonService.execute("NOT_FOUND")
75+
val result = getPrisonOffenderManagerForPersonService.execute("NOT_FOUND", filters)
7476
result.data.shouldBe(PrisonOffenderManager())
7577
result.errors
7678
.first()

0 commit comments

Comments
 (0)