diff --git a/Dockerfile.setup-manage-pom-case-api b/Dockerfile.setup-manage-pom-case-api new file mode 100644 index 000000000..96e5ee543 --- /dev/null +++ b/Dockerfile.setup-manage-pom-case-api @@ -0,0 +1,8 @@ +FROM node:current-alpine3.17 + +RUN apk update && apk add bash curl + +RUN curl https://allocation-manager-staging.apps.live.cloud-platform.service.justice.gov.uk/v3/api-docs.json > manage-pom-case-api.json && \ + npm install -g @stoplight/prism-cli + +CMD prism mock -p 4010 -h 0.0.0.0 /manage-pom-case-api.json diff --git a/docker-compose.yml b/docker-compose.yml index a067aec51..9a288d7f6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,8 @@ services: condition: service_healthy probation-integration-epf-api: condition: service_healthy + manage-pom-case-api: + condition: service_healthy environment: - SERVER_PORT=8080 - SPRING_PROFILES_ACTIVE=local-docker @@ -124,6 +126,16 @@ services: ports: - '4080:4010' + manage-pom-case-api: + build: + context: . + dockerfile: Dockerfile.setup-manage-pom-case-api + container_name: manage-pom-case-api + healthcheck: + test: 'wget --header="Authorization: Bearer abc" http://127.0.0.1:4010/api/allocation/X1234YZ/primary_pom -O /dev/null' + ports: + - '4090:4010' + local-stack-aws: image: localstack/localstack:3.0 container_name: local-stack-aws diff --git a/openapi.yml b/openapi.yml index 4b9626117..a9ccb6fb3 100644 --- a/openapi.yml +++ b/openapi.yml @@ -722,6 +722,40 @@ paths: NoQueryParametersBadRequestError: $ref: "#/components/examples/InternalServerError" + /v1/persons/{HmppsId}/person-responsible-officer: + get: + summary: Returns the person responsible officer associated with a person. + parameters: + - $ref: "#/components/parameters/HmppsId" + responses: + "200": + description: Successfully found the person responsible officer for a person with the provided HMPPS ID. + content: + application/json: + schema: + type: object + properties: + data: + $ref: "#/components/schemas/PersonResponsibleOfficer" + "404": + description: Failed to find licenses for a person with the provided HMPPS ID. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + PersonNotFoundError: + $ref: "#/components/examples/PersonNotFoundError" + "500": + description: An upstream service was not responding, so we cannot verify the accuracy of any data we did get. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + NoQueryParametersBadRequestError: + $ref: "#/components/examples/InternalServerError" + /v1/persons/{HmppsId}/licences/conditions: get: summary: Returns license conditions associated with a person. @@ -1269,6 +1303,19 @@ components: releaseDate: type: string format: date + CommunityOffenderManager: + type: object + properties: + name: + $ref: "#/components/schemas/PersonResponsibleOfficerName" + email: + type: string + nullable: true + telephoneNumber: + type: string + nullable: true + team: + $ref: "#/components/schemas/PersonResponsibleOfficerTeam" ContactDetails: properties: phoneNumbers: @@ -1755,6 +1802,30 @@ components: description: Currently a hmppsId is a CRN identifier however this will change in the future to be a new unique Hmpps identifier contactDetails: $ref: "#/components/schemas/ContactDetails" + PersonResponsibleOfficerName: + type: object + properties: + forename: + type: string + nullable: true + surname: + type: string + nullable: true + PersonResponsibleOfficerTeam: + type: object + properties: + code: + type: string + nullable: true + description: + type: string + nullable: true + email: + type: string + nullable: true + telephoneNumber: + type: string + nullable: true PhoneNumbers: type: array items: @@ -1768,6 +1839,13 @@ components: type: string example: "TELEPHONE" description: "The type of number" + PersonResponsibleOfficer: + type: object + properties: + prisonOffenderOfficer: + $ref: "#/components/schemas/PrisonOffenderOfficer" + communityOffenderManager: + $ref: "#/components/schemas/CommunityOffenderManager" PersonLicencesData: type: object properties: @@ -1839,7 +1917,23 @@ components: minItems: 0 items: $ref: "#/components/schemas/ReasonableAdjustment" - + Prison: + type: object + properties: + code: + type: string + nullable: true + PrisonOffenderOfficer: + type: object + properties: + forename: + type: string + nullable: true + surname: + type: string + nullable: true + prison: + $ref: "#/components/schemas/Prison" Punishment: type: object diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/PersonResponsibleOfficerController.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/PersonResponsibleOfficerController.kt new file mode 100644 index 000000000..63481e357 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/PersonResponsibleOfficerController.kt @@ -0,0 +1,48 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.controllers.v1.person + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.exception.EntityNotFoundException +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.decodeUrlCharacters +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficer +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetCommunityOffenderManagerForPersonService +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetPrisonOffenderManagerForPersonService +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService + +@RestController +@RequestMapping("/v1/persons") +class PersonResponsibleOfficerController( + @Autowired val auditService: AuditService, + @Autowired val getPrisonOffenderManagerForPersonService: GetPrisonOffenderManagerForPersonService, + @Autowired val getCommunityOffenderManagerForPersonService: GetCommunityOffenderManagerForPersonService, +) { + @GetMapping("{encodedHmppsId}/person-responsible-officer") + fun getPersonResponsibleOfficer( + @PathVariable encodedHmppsId: String, + ): Map { + val hmppsId = encodedHmppsId.decodeUrlCharacters() + val prisonOffenderManager = getPrisonOffenderManagerForPersonService.execute(hmppsId) + val communityOffenderManager = getCommunityOffenderManagerForPersonService.execute(hmppsId) + + if (prisonOffenderManager.hasError(UpstreamApiError.Type.ENTITY_NOT_FOUND)) { + throw EntityNotFoundException("Could not find prison offender manager related to id: $hmppsId") + } + + if (communityOffenderManager.hasError(UpstreamApiError.Type.ENTITY_NOT_FOUND)) { + throw EntityNotFoundException("Could not find community offender manager related to id: $hmppsId") + } + + val mergedData = + PersonResponsibleOfficer( + prisonOffenderManager = prisonOffenderManager.data, + communityOffenderManager = communityOffenderManager.data, + ) + + auditService.createEvent("GET_PERSON_RESPONSIBLE_OFFICER", mapOf("hmppsId" to hmppsId)) + return mapOf("data" to mergedData) + } +} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ManagePOMCaseGateway.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ManagePOMCaseGateway.kt new file mode 100644 index 000000000..bba085a76 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ManagePOMCaseGateway.kt @@ -0,0 +1,52 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.HttpMethod +import org.springframework.stereotype.Component +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.WebClientWrapper +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.managePOMCase.AllocationPrimaryPOM + +@Component +class ManagePOMCaseGateway( + @Value("\${services.manage-pom-case-api.base-url}") baseUrl: String, +) { + private val webClient = WebClientWrapper(baseUrl) + + @Autowired + lateinit var hmppsAuthGateway: HmppsAuthGateway + + fun getPrimaryPOMForNomisNumber(id: String): Response { + val result = + webClient.request( + HttpMethod.GET, + "/api/allocation/$id/primary_pom", + authenticationHeader(), + UpstreamApi.MANAGE_POM_CASE, + ) + + return when (result) { + is WebClientWrapper.WebClientWrapperResponse.Success -> { + Response(data = result.data.toPrisonOffenderManager()) + } + + is WebClientWrapper.WebClientWrapperResponse.Error -> { + Response( + data = PrisonOffenderManager(), + errors = result.errors, + ) + } + } + } + + private fun authenticationHeader(): Map { + val token = hmppsAuthGateway.getClientToken("ManagePOMCase") + + return mapOf( + "Authorization" to "Bearer $token", + ) + } +} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/NDeliusGateway.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/NDeliusGateway.kt index 879eeb711..a4e33d00c 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/NDeliusGateway.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/NDeliusGateway.kt @@ -6,6 +6,7 @@ import org.springframework.http.HttpMethod import org.springframework.stereotype.Component import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.WebClientWrapper import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.WebClientWrapper.WebClientWrapperResponse +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.CommunityOffenderManager import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.MappaDetail import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Offence import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response @@ -91,6 +92,28 @@ class NDeliusGateway( } } + fun getCommunityOffenderManagerForPerson(id: String): Response { + val result = + webClient.request( + HttpMethod.GET, + "/case/$id/supervisions", + authenticationHeader(), + UpstreamApi.NDELIUS, + ) + return when (result) { + is WebClientWrapperResponse.Success -> { + Response(data = result.data.communityManager.toCommunityOffenderManager()) + } + + is WebClientWrapperResponse.Error -> { + Response( + data = CommunityOffenderManager(), + errors = result.errors, + ) + } + } + } + private fun authenticationHeader(): Map { val token = hmppsAuthGateway.getClientToken("nDelius") diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/CommunityOffenderManager.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/CommunityOffenderManager.kt new file mode 100644 index 000000000..6e99c3287 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/CommunityOffenderManager.kt @@ -0,0 +1,8 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps + +data class CommunityOffenderManager( + val name: PersonResponsibleOfficerName = PersonResponsibleOfficerName(), + val email: String? = null, + val telephoneNumber: String? = null, + val team: PersonResponsibleOfficerTeam = PersonResponsibleOfficerTeam(), +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficer.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficer.kt new file mode 100644 index 000000000..a0431645e --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficer.kt @@ -0,0 +1,6 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps + +data class PersonResponsibleOfficer( + val prisonOffenderManager: PrisonOffenderManager = PrisonOffenderManager(), + val communityOffenderManager: CommunityOffenderManager = CommunityOffenderManager(), +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficerName.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficerName.kt new file mode 100644 index 000000000..2b07d0552 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficerName.kt @@ -0,0 +1,6 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps + +data class PersonResponsibleOfficerName( + val forename: String? = null, + val surname: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficerTeam.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficerTeam.kt new file mode 100644 index 000000000..eb27202f4 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PersonResponsibleOfficerTeam.kt @@ -0,0 +1,8 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps + +data class PersonResponsibleOfficerTeam( + val code: String? = null, + val description: String? = null, + val email: String? = null, + val telephoneNumber: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/Prison.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/Prison.kt new file mode 100644 index 000000000..538bfd5f6 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/Prison.kt @@ -0,0 +1,5 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps + +data class Prison( + val code: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PrisonOffenderManager.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PrisonOffenderManager.kt new file mode 100644 index 000000000..222bd4e2c --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/PrisonOffenderManager.kt @@ -0,0 +1,7 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps + +data class PrisonOffenderManager( + val forename: String? = null, + val surname: String? = null, + val prison: Prison = Prison(), +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/UpstreamApi.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/UpstreamApi.kt index 34ee1c7df..00fc8c25b 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/UpstreamApi.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/hmpps/UpstreamApi.kt @@ -9,5 +9,6 @@ enum class UpstreamApi { ADJUDICATIONS, CVL, CASE_NOTES, + MANAGE_POM_CASE, TEST, } diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationManager.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationManager.kt new file mode 100644 index 000000000..9b8b7f942 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationManager.kt @@ -0,0 +1,7 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.managePOMCase + +data class AllocationManager( + val code: Int? = null, + val forename: String? = null, + val surname: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationPrimaryPOM.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationPrimaryPOM.kt new file mode 100644 index 000000000..c6b80a1d0 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationPrimaryPOM.kt @@ -0,0 +1,19 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.managePOMCase + +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Prison +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonOffenderManager + +data class AllocationPrimaryPOM( + val manager: AllocationManager = AllocationManager(), + val prison: AllocationPrison = AllocationPrison(), +) { + fun toPrisonOffenderManager(): PrisonOffenderManager = + PrisonOffenderManager( + forename = this.manager.forename, + surname = this.manager.surname, + prison = + Prison( + code = this.prison.code, + ), + ) +} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationPrison.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationPrison.kt new file mode 100644 index 000000000..2ccecdf0b --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/managePOMCase/AllocationPrison.kt @@ -0,0 +1,5 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.managePOMCase + +data class AllocationPrison( + val code: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusCommunityManager.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusCommunityManager.kt new file mode 100644 index 000000000..698905a48 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusCommunityManager.kt @@ -0,0 +1,25 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.ndelius + +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.CommunityOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerName +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerTeam + +data class NDeliusCommunityManager( + val code: String? = null, + val name: NDeliusName = NDeliusName(), + val username: String? = null, + val email: String? = null, + val telephoneNumber: String? = null, + val team: NDeliusTeam = NDeliusTeam(), + val allocated: Boolean? = null, +) { + fun toCommunityOffenderManager(): CommunityOffenderManager = + ( + CommunityOffenderManager( + name = PersonResponsibleOfficerName(forename = this.name.forename, surname = this.name.surname), + email = this.email, + telephoneNumber = this.telephoneNumber, + team = PersonResponsibleOfficerTeam(code = this.team.code, description = this.team.description, email = this.team.email, telephoneNumber = this.team.telephoneNumber), + ) + ) +} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusName.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusName.kt new file mode 100644 index 000000000..5b889f70c --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusName.kt @@ -0,0 +1,6 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.ndelius + +data class NDeliusName( + val forename: String? = null, + val surname: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusProvider.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusProvider.kt new file mode 100644 index 000000000..bece8787d --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusProvider.kt @@ -0,0 +1,6 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.ndelius + +data class NDeliusProvider( + val code: String? = null, + val description: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusSupervisions.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusSupervisions.kt index 1e9ca5496..daaddd4af 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusSupervisions.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusSupervisions.kt @@ -1,6 +1,7 @@ package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.ndelius data class NDeliusSupervisions( + val communityManager: NDeliusCommunityManager, val mappaDetail: NDeliusMappaDetail? = null, val supervisions: List, ) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusTeam.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusTeam.kt new file mode 100644 index 000000000..208301217 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/NDeliusTeam.kt @@ -0,0 +1,8 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.ndelius + +data class NDeliusTeam( + val code: String? = null, + val description: String? = null, + val email: String? = null, + val telephoneNumber: String? = null, +) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetCommunityOffenderManagerForPersonService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetCommunityOffenderManagerForPersonService.kt new file mode 100644 index 000000000..50021aeb2 --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetCommunityOffenderManagerForPersonService.kt @@ -0,0 +1,29 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.services + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.NDeliusGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.CommunityOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response + +@Service +class GetCommunityOffenderManagerForPersonService( + @Autowired val getPersonService: GetPersonService, + @Autowired val nDeliusGateway: NDeliusGateway, +) { + fun execute(hmppsId: String): Response { + val personResponse = getPersonService.execute(hmppsId = hmppsId) + + val deliusCrn = personResponse.data?.identifiers?.deliusCrn + var nDeliusMappaDetailResponse: Response = Response(data = CommunityOffenderManager()) + + if (deliusCrn != null) { + nDeliusMappaDetailResponse = nDeliusGateway.getCommunityOffenderManagerForPerson(id = deliusCrn) + } + + return Response( + data = nDeliusMappaDetailResponse.data, + errors = personResponse.errors + nDeliusMappaDetailResponse.errors, + ) + } +} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPrisonOffenderManagerForPersonService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPrisonOffenderManagerForPersonService.kt new file mode 100644 index 000000000..3204b2beb --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPrisonOffenderManagerForPersonService.kt @@ -0,0 +1,28 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.services + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ManagePOMCaseGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response + +@Service +class GetPrisonOffenderManagerForPersonService( + @Autowired val getPersonService: GetPersonService, + @Autowired val managePOMCaseGateway: ManagePOMCaseGateway, +) { + fun execute(hmppsId: String): Response { + val personResponse = getPersonService.execute(hmppsId = hmppsId) + val nomisNumber = personResponse.data?.identifiers?.nomisNumber + var prisonOffenderManager: Response = Response(data = PrisonOffenderManager()) + + if (nomisNumber != null) { + prisonOffenderManager = managePOMCaseGateway.getPrimaryPOMForNomisNumber(nomisNumber) + } + + return Response( + data = prisonOffenderManager.data, + errors = personResponse.errors + prisonOffenderManager.errors, + ) + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index cb13e0e36..a46848f0c 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -17,6 +17,8 @@ services: base-url: https://create-and-vary-a-licence-api-dev.hmpps.service.justice.gov.uk case-notes: base-url: https://dev.offender-case-notes.service.justice.gov.uk + manage-pom-case-api: + base-url: https://dev.moic.service.justice.gov.uk hmpps-auth: base-url: https://sign-in-dev.hmpps.service.justice.gov.uk username: ${CLIENT_ID} @@ -60,3 +62,4 @@ authorisation: - "/v1/persons/.*/risks/scores" - "/v1/persons/.*/risks" - "/v1/persons/.*/licences/conditions" + - "/v1/persons/.*/person-responsible-officer" diff --git a/src/main/resources/application-local-docker.yml b/src/main/resources/application-local-docker.yml index 4678e37ba..bb3f2fd10 100644 --- a/src/main/resources/application-local-docker.yml +++ b/src/main/resources/application-local-docker.yml @@ -17,6 +17,8 @@ services: base-url: http://create-and-vary-licence-api:4010 case-notes: base-url: http://case-notes-api:4010 + manage-pom-case-api: + base-url: http://manage-pom-case-api:4010 hmpps-auth: base-url: http://hmpps-auth:8080 @@ -37,6 +39,7 @@ authorisation: - "/v1/persons/.*/risks" - "/v1/persons/.*/reported-adjudications" - "/v1/persons/.*/case-notes" + - "/v1/persons/.*/person-responsible-officer" - "/v1/epf/person-details/.*/.*" - "/health" - "/health/ping" diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 93f1b6343..3dec6146d 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -19,6 +19,8 @@ services: base-url: http://localhost:4070 case-notes: base-url: http://localhost:4080 + manage-pom-case-api: + base-url: http://localhost:4090 hmpps.sqs: provider: localstack @@ -44,6 +46,7 @@ authorisation: - "/v1/persons/.*/risks" - "/v1/persons/.*/reported-adjudications" - "/v1/persons/.*/case-notes" + - "/v1/persons/.*/person-responsible-officer" - "/v1/epf/person-details/.*/.*" - "/health" - "/health/ping" diff --git a/src/main/resources/application-preprod.yml b/src/main/resources/application-preprod.yml index b36e6eadd..44db9a64e 100644 --- a/src/main/resources/application-preprod.yml +++ b/src/main/resources/application-preprod.yml @@ -17,6 +17,8 @@ services: base-url: https://create-and-vary-a-licence-api-preprod.hmpps.service.justice.gov.uk case-notes: base-url: https://preprod.offender-case-notes.service.justice.gov.uk + manage-pom-case-api: + base-url: https://preprod.moic.service.justice.gov.uk hmpps-auth: base-url: https://sign-in-preprod.hmpps.service.justice.gov.uk username: ${CLIENT_ID} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index ec6ca7dff..5cad6f114 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -17,6 +17,8 @@ services: base-url: https://create-and-vary-a-licence-api-prod.hmpps.service.justice.gov.uk case-notes: base-url: https://prod.offender-case-notes.service.justice.gov.uk + manage-pom-case-api: + base-url: https://moic.service.justice.gov.uk hmpps-auth: base-url: https://sign-in.hmpps.service.justice.gov.uk username: ${CLIENT_ID} diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index b9c50a71f..7b8828032 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -28,6 +28,8 @@ services: base-url: http://localhost:4007 case-notes: base-url: http://localhost:4008 + manage-pom-case-api: + base-url: http://localhost:4009 hmpps.sqs: provider: localstack @@ -55,6 +57,7 @@ authorisation: - "/v1/persons/.*/adjudications" - "/v1/persons/.*/licences/conditions" - "/v1/persons/.*/case-notes" + - "/v1/persons/.*/person-responsible-officer" - "/health" - "/health/ping" - "/health/readiness" diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1765d3fb8..9c929cb2b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -73,6 +73,8 @@ services: base-url: http://localhost:4070 case-notes: base-url: http://localhost:4080 + manage-pom-case-api: + base-url: http://localhost:4090 sentry: traces-sample-rate: "0.05" diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/PersonResponsibleOfficerControllerTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/PersonResponsibleOfficerControllerTest.kt new file mode 100644 index 000000000..e4f666948 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/PersonResponsibleOfficerControllerTest.kt @@ -0,0 +1,130 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.controllers.v1.person + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import org.mockito.Mockito +import org.mockito.internal.verification.VerificationModeFactory +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.http.HttpStatus +import org.springframework.test.context.ActiveProfiles +import org.springframework.test.web.servlet.MockMvc +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.removeWhitespaceAndNewlines +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.helpers.IntegrationAPIMockMvc +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.CommunityOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerName +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerTeam +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Prison +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetCommunityOffenderManagerForPersonService +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetPrisonOffenderManagerForPersonService +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService +import java.net.URLEncoder +import java.nio.charset.StandardCharsets + +@WebMvcTest(controllers = [PersonResponsibleOfficerController::class]) +@ActiveProfiles("test") +internal class PersonResponsibleOfficerControllerTest( + @Autowired var springMockMvc: MockMvc, + @MockBean val auditService: AuditService, + @MockBean val getCommunityOffenderManagerForPersonService: GetCommunityOffenderManagerForPersonService, + @MockBean val getPrisonOffenderManagerForPersonService: GetPrisonOffenderManagerForPersonService, +) : DescribeSpec() { + init { + val hmppsId = "9999/11111A" + val encodedHmppsId = URLEncoder.encode(hmppsId, StandardCharsets.UTF_8) + val path = "/v1/persons/$encodedHmppsId/person-responsible-officer" + val mockMvc = IntegrationAPIMockMvc(springMockMvc) + + describe("GET $path") { + beforeTest { + Mockito.reset(getPrisonOffenderManagerForPersonService) + Mockito.reset(getCommunityOffenderManagerForPersonService) + whenever(getPrisonOffenderManagerForPersonService.execute(hmppsId)).thenReturn( + Response( + PrisonOffenderManager( + forename = "Paul", + surname = "Reds", + prison = Prison(code = "PrisonCode1"), + ), + ), + ) + + whenever(getCommunityOffenderManagerForPersonService.execute(hmppsId)).thenReturn( + Response( + CommunityOffenderManager( + name = PersonResponsibleOfficerName("Helen", surname = "Miller"), + email = "helenemail@email.com", + telephoneNumber = "0987654321", + team = + PersonResponsibleOfficerTeam( + code = "PrisonCode2", + description = "Description", + email = "email_again@email.com", + telephoneNumber = "01234567890", + ), + ), + ), + ) + Mockito.reset(auditService) + } + + it("returns a 200 OK status code") { + val result = mockMvc.performAuthorised(path) + + result.response.status.shouldBe(HttpStatus.OK.value()) + } + + it("gets the person responsible officer for a person with the matching ID") { + mockMvc.performAuthorised(path) + verify(getCommunityOffenderManagerForPersonService, VerificationModeFactory.times(1)).execute(hmppsId) + } + + it("logs audit") { + mockMvc.performAuthorised(path) + + verify( + auditService, + VerificationModeFactory.times(1), + ).createEvent("GET_PERSON_RESPONSIBLE_OFFICER", mapOf("hmppsId" to hmppsId)) + } + + it("returns the person responsible officer for a person with the matching ID") { + val result = mockMvc.performAuthorised(path) + + result.response.contentAsString.shouldContain( + """ + "data": { + "prisonOffenderManager": { + "forename": "Paul", + "surname": "Reds", + "prison": { + "code": "PrisonCode1" + } + }, + "communityOffenderManager": { + "name": { + "forename": "Helen", + "surname": "Miller" + }, + "email": "helenemail@email.com", + "telephoneNumber": "0987654321", + "team": { + "code": "PrisonCode2", + "description": "Description", + "email": "email_again@email.com", + "telephoneNumber": "01234567890" + } + } + } + """.removeWhitespaceAndNewlines(), + ) + } + } + } +} diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/managePOMcase/ManagePOMCaseGatewayTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/managePOMcase/ManagePOMCaseGatewayTest.kt new file mode 100644 index 000000000..cb96f4680 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/managePOMcase/ManagePOMCaseGatewayTest.kt @@ -0,0 +1,82 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.managePOMcase + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import org.mockito.Mockito +import org.mockito.internal.verification.VerificationModeFactory +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.http.HttpStatus +import org.springframework.test.context.ActiveProfiles +import org.springframework.test.context.ContextConfiguration +import org.springframework.web.reactive.function.client.WebClientResponseException +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.HmppsAuthGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ManagePOMCaseGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.mockservers.HmppsAuthMockServer +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.mockservers.ManagePOMCaseApiMockServer + +@ActiveProfiles("test") +@ContextConfiguration( + initializers = [ConfigDataApplicationContextInitializer::class], + classes = [ManagePOMCaseGateway::class], +) +class ManagePOMCaseGatewayTest( + @MockBean val hmppsAuthGateway: HmppsAuthGateway, + val managePOMCaseGateway: ManagePOMCaseGateway, +) : DescribeSpec( + { + val managePOMCaseApiMockServer = ManagePOMCaseApiMockServer() + beforeEach { + managePOMCaseApiMockServer.start() + + Mockito.reset(hmppsAuthGateway) + whenever(hmppsAuthGateway.getClientToken("ManagePOMCase")).thenReturn( + HmppsAuthMockServer.TOKEN, + ) + } + afterTest { + managePOMCaseApiMockServer.stop() + } + + it("authenticates using HMPPS Auth with credentials") { + managePOMCaseGateway.getPrimaryPOMForNomisNumber(id = "X1234YZ") + + verify(hmppsAuthGateway, VerificationModeFactory.times(1)).getClientToken("ManagePOMCase") + } + + it("upstream API returns an error, throw exception") { + managePOMCaseApiMockServer.stubGetPrimaryPOMForNomisNumber("X1234YZ", "", HttpStatus.BAD_REQUEST) + val response = + shouldThrow { + managePOMCaseGateway.getPrimaryPOMForNomisNumber(id = "X1234YZ") + } + response.statusCode.shouldBe(HttpStatus.BAD_REQUEST) + } + + it("returns primary offender officer") { + managePOMCaseApiMockServer.stubGetPrimaryPOMForNomisNumber( + "X1234YZ", + """ + { + "manager": { + "code": 0, + "forename": "string", + "surname": "string" + }, + "prison": { + "code": "string" + } + } + """, + HttpStatus.OK, + ) + + val response = managePOMCaseGateway.getPrimaryPOMForNomisNumber(id = "X1234YZ") + response.data.forename.shouldBe("string") + response.data.surname.shouldBe("string") + } + }, + ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetCommunityOffenderManagerForPersonTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetCommunityOffenderManagerForPersonTest.kt new file mode 100644 index 000000000..7ea68c6c4 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetCommunityOffenderManagerForPersonTest.kt @@ -0,0 +1,109 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ndelius + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.shouldBe +import org.mockito.Mockito +import org.mockito.internal.verification.VerificationModeFactory +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.http.HttpStatus +import org.springframework.test.context.ActiveProfiles +import org.springframework.test.context.ContextConfiguration +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.HmppsAuthGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.NDeliusGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.mockservers.HmppsAuthMockServer +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.mockservers.NDeliusApiMockServer +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.CommunityOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerName +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerTeam +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError +import java.io.File + +@ActiveProfiles("test") +@ContextConfiguration( + initializers = [ConfigDataApplicationContextInitializer::class], + classes = [NDeliusGateway::class], +) +class GetCommunityOffenderManagerForPersonTest( + @MockBean + val hmppsAuthGateway: HmppsAuthGateway, + val nDeliusGateway: NDeliusGateway, +) : DescribeSpec( + { + val nDeliusApiMockServer = NDeliusApiMockServer() + val deliusCrn = "X777776" + + beforeEach { + nDeliusApiMockServer.start() + nDeliusApiMockServer.stubGetSupervisionsForPerson( + deliusCrn, + File( + "src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/fixtures/GetSupervisionsResponse.json", + ).readText(), + ) + + Mockito.reset(hmppsAuthGateway) + whenever(hmppsAuthGateway.getClientToken("nDelius")).thenReturn(HmppsAuthMockServer.TOKEN) + } + + afterTest { + nDeliusApiMockServer.stop() + } + + it("authenticates using HMPPS Auth with credentials") { + nDeliusGateway.getCommunityOffenderManagerForPerson(deliusCrn) + + verify(hmppsAuthGateway, VerificationModeFactory.times(1)).getClientToken("nDelius") + } + + it("returns community offender manager related to the matching CRN") { + val response = nDeliusGateway.getCommunityOffenderManagerForPerson(deliusCrn) + + response.data.shouldBe( + CommunityOffenderManager( + name = PersonResponsibleOfficerName(forename = "John", surname = "Smith"), + email = "johnsmith@email.com", + telephoneNumber = "077777777", + team = + PersonResponsibleOfficerTeam( + code = "Code1", + description = "Description", + email = "team@email.com", + telephoneNumber = "07888888", + ), + ), + ) + } + + it("returns an empty object if no community offender manager is found") { + nDeliusApiMockServer.stubGetSupervisionsForPerson( + deliusCrn, + """ + { + "communityManager": {}, + "mappaDetail": {}, + "supervisions": [] + } + """, + ) + + val response = nDeliusGateway.getCommunityOffenderManagerForPerson(deliusCrn) + + response.data.shouldBe(CommunityOffenderManager()) + } + + it("returns an error when 404 Not Found is returned because no person is found") { + nDeliusApiMockServer.stubGetSupervisionsForPerson(deliusCrn, "", HttpStatus.NOT_FOUND) + + val response = nDeliusGateway.getCommunityOffenderManagerForPerson(deliusCrn) + + response.errors.shouldHaveSize(1) + response.errors.first().causedBy.shouldBe(UpstreamApi.NDELIUS) + response.errors.first().type.shouldBe(UpstreamApiError.Type.ENTITY_NOT_FOUND) + } + }, + ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetMappaDetailForPersonTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetMappaDetailForPersonTest.kt index c2c1b20a5..38018e7a8 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetMappaDetailForPersonTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetMappaDetailForPersonTest.kt @@ -79,6 +79,7 @@ class GetMappaDetailForPersonTest( deliusCrn, """ { + "communityManager": {}, "mappaDetail": {}, "supervisions": [] } diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetOffencesForPersonTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetOffencesForPersonTest.kt index 3ab0b8be2..02ddcb1bf 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetOffencesForPersonTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetOffencesForPersonTest.kt @@ -139,6 +139,7 @@ class GetOffencesForPersonTest( deliusCrn, """ { + "communityManager": {}, "mappaDetail": null, "supervisions": [] } """, diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetSentencesForPersonTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetSentencesForPersonTest.kt index e7e4733e2..c8736792e 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetSentencesForPersonTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/GetSentencesForPersonTest.kt @@ -104,6 +104,7 @@ class GetSentencesForPersonTest( deliusCrn, """ { + "communityManager": {}, "mappaDetail": {}, "supervisions": [] } """, diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/fixtures/GetSupervisionsResponse.json b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/fixtures/GetSupervisionsResponse.json index 121848853..9c6c5c1dc 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/fixtures/GetSupervisionsResponse.json +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/ndelius/fixtures/GetSupervisionsResponse.json @@ -1,4 +1,21 @@ { + "communityManager": { + "code": "Code1", + "name": { + "forename": "John", + "surname": "Smith" + }, + "username": "JohnSmithUsername", + "email": "johnsmith@email.com", + "telephoneNumber": "077777777", + "team": { + "code": "Code1", + "description": "Description", + "email": "team@email.com", + "telephoneNumber": "07888888" + }, + "allocated": true + }, "mappaDetail": { "level": 1, "levelDescription": "string", diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/mockservers/ManagePOMCaseApiMockServer.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/mockservers/ManagePOMCaseApiMockServer.kt new file mode 100644 index 000000000..d51c5383e --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/mockservers/ManagePOMCaseApiMockServer.kt @@ -0,0 +1,30 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.mockservers + +import com.github.tomakehurst.wiremock.WireMockServer +import com.github.tomakehurst.wiremock.client.WireMock +import org.springframework.http.HttpStatus + +class ManagePOMCaseApiMockServer : WireMockServer(WIREMOCK_PORT) { + companion object { + private const val WIREMOCK_PORT = 4009 + } + + fun stubGetPrimaryPOMForNomisNumber( + id: String, + body: String, + status: HttpStatus = HttpStatus.OK, + ) { + stubFor( + WireMock.get("/api/allocation/$id/primary_pom") + .withHeader( + "Authorization", + WireMock.matching("Bearer ${HmppsAuthMockServer.TOKEN}"), + ).willReturn( + WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withStatus(status.value()) + .withBody(body.trimIndent()), + ), + ) + } +} diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/SupervisionsTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/SupervisionsTest.kt index db553fa19..a49c21ca0 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/SupervisionsTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/ndelius/SupervisionsTest.kt @@ -17,6 +17,7 @@ class SupervisionsTest : DescribeSpec( it("maps one-to-one attributes to integration API attributes") { val supervisions = NDeliusSupervisions( + communityManager = NDeliusCommunityManager(), mappaDetail = NDeliusMappaDetail(), supervisions = listOf( @@ -83,6 +84,7 @@ class SupervisionsTest : DescribeSpec( it("does not local date parse additional offence date if no date is provided") { val supervisions = NDeliusSupervisions( + communityManager = NDeliusCommunityManager(), mappaDetail = NDeliusMappaDetail(), supervisions = listOf( @@ -122,6 +124,7 @@ class SupervisionsTest : DescribeSpec( it("does local date parse additional offence date if a date is provided") { val supervisions = NDeliusSupervisions( + communityManager = NDeliusCommunityManager(), mappaDetail = NDeliusMappaDetail(), supervisions = listOf( @@ -166,6 +169,7 @@ class SupervisionsTest : DescribeSpec( it("maps one-to-one attributes to integration API attributes") { val supervisions = NDeliusSupervisions( + communityManager = NDeliusCommunityManager(), mappaDetail = NDeliusMappaDetail(), supervisions = listOf( @@ -213,6 +217,7 @@ class SupervisionsTest : DescribeSpec( it("maps one-to-one attributes to integration API sentence attributes") { val supervisions = NDeliusSupervisions( + communityManager = NDeliusCommunityManager(), mappaDetail = NDeliusMappaDetail(), listOf( NDeliusSupervision( @@ -276,6 +281,7 @@ class SupervisionsTest : DescribeSpec( it("can be constructed with NULL values") { val supervisions = NDeliusSupervisions( + communityManager = NDeliusCommunityManager(), mappaDetail = NDeliusMappaDetail(), listOf( NDeliusSupervision(custodial = true), diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetCommunityOffenderManagerForPersonServiceTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetCommunityOffenderManagerForPersonServiceTest.kt new file mode 100644 index 000000000..5a5da37a1 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetCommunityOffenderManagerForPersonServiceTest.kt @@ -0,0 +1,80 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.services + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import org.mockito.Mockito +import org.mockito.internal.verification.VerificationModeFactory +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.context.ContextConfiguration +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.NDeliusGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.CommunityOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Identifiers +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Person +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerName +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PersonResponsibleOfficerTeam +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError + +@ContextConfiguration( + initializers = [ConfigDataApplicationContextInitializer::class], + classes = [GetCommunityOffenderManagerForPersonService::class], +) +class GetCommunityOffenderManagerForPersonServiceTest( + @MockBean val nDeliusGateway: NDeliusGateway, + @MockBean val getPersonService: GetPersonService, + private val getCommunityOffenderManagerForPersonService: GetCommunityOffenderManagerForPersonService, +) : DescribeSpec( + { + val hmppsId = "1234/56789B" + val deliusCrn = "X224466" + + val person = Person(firstName = "Sam", lastName = "Smith", identifiers = Identifiers(deliusCrn = deliusCrn)) + + val communityOffenderManager = CommunityOffenderManager(name = PersonResponsibleOfficerName(forename = "Michael", surname = "Green"), email = "email@email.com", telephoneNumber = "07471234567", team = PersonResponsibleOfficerTeam(code = "Code2", description = "Service description", email = "email2@email2.com", telephoneNumber = "07170987654")) + + beforeEach { + Mockito.reset(getPersonService) + Mockito.reset(nDeliusGateway) + + whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn(Response(person)) + whenever(nDeliusGateway.getCommunityOffenderManagerForPerson(id = deliusCrn)).thenReturn(Response(communityOffenderManager)) + } + + it("performs a search according to hmpps Id") { + getCommunityOffenderManagerForPersonService.execute(hmppsId) + verify(getPersonService, VerificationModeFactory.times(1)).execute(hmppsId = hmppsId) + } + + it("Returns a community offender manager for person given a hmppsId") { + whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn( + Response( + data = person, + ), + ) + val result = getCommunityOffenderManagerForPersonService.execute(hmppsId) + result.shouldBe(Response(data = communityOffenderManager)) + } + + it("should return a list of errors if person not found") { + whenever(getPersonService.execute(hmppsId = "NOT_FOUND")).thenReturn( + Response( + data = null, + errors = + listOf( + UpstreamApiError( + causedBy = UpstreamApi.NDELIUS, + type = UpstreamApiError.Type.ENTITY_NOT_FOUND, + ), + ), + ), + ) + val result = getCommunityOffenderManagerForPersonService.execute("NOT_FOUND") + result.data.shouldBe(CommunityOffenderManager()) + result.errors.first().type.shouldBe(UpstreamApiError.Type.ENTITY_NOT_FOUND) + } + }, + ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPrisonOffenderManagerForPersonServiceTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPrisonOffenderManagerForPersonServiceTest.kt new file mode 100644 index 000000000..81fc46348 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetPrisonOffenderManagerForPersonServiceTest.kt @@ -0,0 +1,78 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.services + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import org.mockito.Mockito +import org.mockito.internal.verification.VerificationModeFactory +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.context.ContextConfiguration +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ManagePOMCaseGateway +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Identifiers +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Person +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Prison +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonOffenderManager +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError + +@ContextConfiguration( + initializers = [ConfigDataApplicationContextInitializer::class], + classes = [GetPrisonOffenderManagerForPersonService::class], +) +class GetPrisonOffenderManagerForPersonServiceTest( + @MockBean val managePOMCaseGateway: ManagePOMCaseGateway, + @MockBean val getPersonService: GetPersonService, + private val getPrisonOffenderManagerForPersonService: GetPrisonOffenderManagerForPersonService, +) : DescribeSpec( + { + val hmppsId = "1234/56789B" + val nomisNumber = "Z99999ZZ" + val person = Person(firstName = "Julianna", lastName = "Blake", identifiers = Identifiers(nomisNumber = nomisNumber)) + + val prisonOffenderManager = PrisonOffenderManager(forename = "Paul", surname = "Smith", prison = Prison(code = "RED")) + + beforeEach { + Mockito.reset(getPersonService) + Mockito.reset(managePOMCaseGateway) + + whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn(Response(person)) + whenever(managePOMCaseGateway.getPrimaryPOMForNomisNumber(id = nomisNumber)).thenReturn(Response(prisonOffenderManager)) + } + + it("performs a search according to hmpps Id") { + getPrisonOffenderManagerForPersonService.execute(hmppsId) + verify(getPersonService, VerificationModeFactory.times(1)).execute(hmppsId = hmppsId) + } + + it("Returns a prison offender manager for person given a hmppsId") { + whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn( + Response( + data = person, + ), + ) + val result = getPrisonOffenderManagerForPersonService.execute(hmppsId) + result.shouldBe(Response(data = prisonOffenderManager)) + } + + it("should return a list of errors if person not found") { + whenever(getPersonService.execute(hmppsId = "NOT_FOUND")).thenReturn( + Response( + data = null, + errors = + listOf( + UpstreamApiError( + causedBy = UpstreamApi.MANAGE_POM_CASE, + type = UpstreamApiError.Type.ENTITY_NOT_FOUND, + ), + ), + ), + ) + val result = getPrisonOffenderManagerForPersonService.execute("NOT_FOUND") + result.data.shouldBe(PrisonOffenderManager()) + result.errors.first().type.shouldBe(UpstreamApiError.Type.ENTITY_NOT_FOUND) + } + }, + ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/smoke/EPFPersonDetailSmokeTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/smoke/EPFPersonDetailSmokeTest.kt index b2cf06e16..5aaf2a95f 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/smoke/EPFPersonDetailSmokeTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/smoke/EPFPersonDetailSmokeTest.kt @@ -32,7 +32,7 @@ class EPFPersonDetailSmokeTest : DescribeSpec( "dateOfBirth":"2019-08-24", "gender": "string", "sentence": { - "date": "2019-08-24", + "date": null, "sentencingCourt": { "name": "string" }, diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/smoke/person/PersonResponsibleOfficerSmokeTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/smoke/person/PersonResponsibleOfficerSmokeTest.kt new file mode 100644 index 000000000..2bf7eefb7 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/smoke/person/PersonResponsibleOfficerSmokeTest.kt @@ -0,0 +1,53 @@ +package uk.gov.justice.digital.hmpps.hmppsintegrationapi.smoke.person + +import io.kotest.assertions.json.shouldEqualJson +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import org.springframework.http.HttpStatus +import uk.gov.justice.digital.hmpps.hmppsintegrationapi.helpers.IntegrationAPIHttpClient +import java.net.URLEncoder +import java.nio.charset.StandardCharsets + +class PersonResponsibleOfficerSmokeTest : DescribeSpec( + { + val hmppsId = "A1234AA" + val encodedHmppsId = URLEncoder.encode(hmppsId, StandardCharsets.UTF_8) + + val basePath = "v1/persons/$encodedHmppsId/person-responsible-officer" + val httpClient = IntegrationAPIHttpClient() + + it("returns the person responsible officer for a person") { + val response = httpClient.performAuthorised(basePath) + response.statusCode().shouldBe(HttpStatus.OK.value()) + response.body().shouldEqualJson( + """ + { + "data": { + "prisonOffenderManager": { + "forename": "string", + "surname": "string", + "prison": { + "code": "string" + } + }, + "communityOffenderManager": { + "name": { + "forename": "string", + "surname": "string" + }, + "email": "string", + "telephoneNumber": "string", + "team": { + "code": "string", + "description": "string", + "email": "string", + "telephoneNumber": "string" + } + } + } + } + """.trimIndent(), + ) + } + }, +)