Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PI-2107: Added documents grouped endpoint #4152

Merged
merged 1 commit into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package uk.gov.justice.digital.hmpps.data.entity
import jakarta.persistence.*
import org.hibernate.type.YesNoConverter
import java.time.LocalDate
import java.time.LocalDateTime

@Entity
class ApprovedPremisesReferral(
Expand Down Expand Up @@ -35,7 +36,9 @@ class InstitutionalReport(
@Convert(converter = YesNoConverter::class)
val establishment: Boolean,
val custodyId: Long,
val dateRequested: LocalDate
val dateRequested: LocalDate,
val dateRequired: LocalDate,
val dateCompleted: LocalDateTime,
)

@Entity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ object DocumentEntityGenerator {
institutionReportTypeId = INSTITUTIONAL_REPORT_TYPE.id,
custodyId = 1,
establishment = true,
dateRequested = LocalDate.of(2000, 1, 2)
dateRequested = LocalDate.of(2000, 1, 2),
dateRequired = LocalDate.of(2000, 1, 2),
dateCompleted = LocalDateTime.of(2000, 1, 2, 0, 0)
)

fun generateDocument(personId: Long, primaryKeyId: Long?, type: String, tableName: String?) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@ package uk.gov.justice.digital.hmpps.data.generator
import uk.gov.justice.digital.hmpps.data.generator.SentenceGenerator.CURRENT_SENTENCE
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.UpwAppointment
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.UpwDetails
import java.time.LocalDate

object UnpaidWorkGenerator {

val UNPAID_WORK_DETAILS_1 =
UpwDetails(IdGenerator.getAndIncrement(), CURRENT_SENTENCE, 0, ReferenceDataGenerator.HOURS_WORKED)

val APPT1 = UpwAppointment(IdGenerator.getAndIncrement(), 3, "Y", "Y", 0, UNPAID_WORK_DETAILS_1)
val APPT2 = UpwAppointment(IdGenerator.getAndIncrement(), 4, "Y", "Y", 1, UNPAID_WORK_DETAILS_1)
val APPT3 = UpwAppointment(IdGenerator.getAndIncrement(), 0, "N", "N", 1, UNPAID_WORK_DETAILS_1)
val APPT4 = UpwAppointment(IdGenerator.getAndIncrement(), 0, "N", "Y", 1, UNPAID_WORK_DETAILS_1)
val APPT5 = UpwAppointment(IdGenerator.getAndIncrement(), 0, "N", "Y", 1, UNPAID_WORK_DETAILS_1)
val APPT6 = UpwAppointment(IdGenerator.getAndIncrement(), 0, null, null, 1, UNPAID_WORK_DETAILS_1)
val APPT7 = UpwAppointment(IdGenerator.getAndIncrement(), 0, "Y", "Y", 0, UNPAID_WORK_DETAILS_1)
val APPT1 =
UpwAppointment(IdGenerator.getAndIncrement(), 3, "Y", "Y", 0, LocalDate.now(), 1L, UNPAID_WORK_DETAILS_1)
val APPT2 =
UpwAppointment(IdGenerator.getAndIncrement(), 4, "Y", "Y", 1, LocalDate.now(), 1L, UNPAID_WORK_DETAILS_1)
val APPT3 =
UpwAppointment(IdGenerator.getAndIncrement(), 0, "N", "N", 1, LocalDate.now(), 1L, UNPAID_WORK_DETAILS_1)
val APPT4 =
UpwAppointment(IdGenerator.getAndIncrement(), 0, "N", "Y", 1, LocalDate.now(), 1L, UNPAID_WORK_DETAILS_1)
val APPT5 =
UpwAppointment(IdGenerator.getAndIncrement(), 0, "N", "Y", 1, LocalDate.now(), 1L, UNPAID_WORK_DETAILS_1)
val APPT6 =
UpwAppointment(IdGenerator.getAndIncrement(), 0, null, null, 1, LocalDate.now(), 1L, UNPAID_WORK_DETAILS_1)
val APPT7 =
UpwAppointment(IdGenerator.getAndIncrement(), 0, "Y", "Y", 0, LocalDate.now(), 1L, UNPAID_WORK_DETAILS_1)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"documents": [],
"convictions": [
{
"convictionId": "83",
"documents": [
{
"id": "alfrescoId",
"documentName": "filename.txt",
"type": {
"code": "CONVICTION_DOCUMENT",
"description": "Sentence related"
},
"lastModifiedAt": "2024-08-08T15:56:02.88685",
"createdAt": "2024-08-08T15:56:02.88684",
"parentPrimaryKeyId": 83,
"reportDocumentDates": {}
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"mappings": [
{
"request": {
"method": "GET",
"urlPathTemplate": "/secure/offenders/crn/{crn}/documents/grouped"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"bodyFileName": "get_documents_grouped_C123456.json"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package uk.gov.justice.digital.hmpps

import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT
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.api.model.OffenderDocuments
import uk.gov.justice.digital.hmpps.api.resource.advice.ErrorResponse
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = RANDOM_PORT)
internal class DocumentsIntegrationTest {
@Autowired
lateinit var mockMvc: MockMvc

@Test
fun `call documents grouped by CRN`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn

val response = mockMvc
.perform(get("/probation-case/$crn/documents/grouped").withToken())
.andExpect(status().isOk)
.andReturn().response.contentAsJson<OffenderDocuments>()

assertThat(response.documents.size, equalTo(0))
assertThat(response.convictions.size, equalTo(1))
}

@Test
fun `call documents grouped by CRN invalid filter`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn

val response = mockMvc
.perform(get("/probation-case/$crn/documents/grouped?type=INVALID").withToken())
.andExpect(status().isBadRequest)
.andReturn().response.contentAsJson<ErrorResponse>()

assertThat(response.developerMessage, equalTo("type of INVALID was not valid"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ internal class ProxyIntegrationTest {
"CONVICTION_BY_ID_SENTENCE_STATUS": {
"convictionId": "?",
"activeOnly": true
},
"DOCUMENTS_GROUPED": {
"type": null,
"subtype": null
}
}
}
Expand All @@ -269,7 +273,7 @@ internal class ProxyIntegrationTest {
.withToken()
).andExpect(status().is2xxSuccessful).andReturn().response.contentAsJson<CompareAllReport>()

assertThat(res.totalNumberOfRequests, equalTo(14))
assertThat(res.totalNumberOfRequests, equalTo(15))
assertThat(res.totalNumberOfCrns, equalTo(2))
assertThat(res.currentPageNumber, equalTo(1))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package uk.gov.justice.digital.hmpps.api.model

import java.time.LocalDate
import java.time.LocalDateTime

data class OffenderDocumentDetail(
val id: String? = null,
val documentName: String? = null,
val author: String? = null,
val type: KeyValue,
val extendedDescription: String? = null,
val lastModifiedAt: LocalDateTime? = null,
val createdAt: LocalDateTime? = null,
val parentPrimaryKeyId: Long? = null,
val subType: KeyValue? = null,
val reportDocumentDates: ReportDocumentDates? = null
)

data class ReportDocumentDates(
val requestedDate: LocalDate? = null,
val requiredDate: LocalDate? = null,
val completedDate: LocalDateTime? = null
)

data class ConvictionDocuments(
val convictionId: String,
val documents: List<OffenderDocumentDetail> = emptyList()
)

data class OffenderDocuments(
val documents: List<OffenderDocumentDetail> = emptyList(),
val convictions: List<ConvictionDocuments> = emptyList(),
)

data class DocumentFilter(
val type: String? = null,
val subtype: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,12 @@ data class KeyValue(
val description: String
)

data class OffenderDocumentDetail(

val documentName: String,
val author: String?,
val type: DocumentType,
val extendedDescription: String?,
val createdAt: ZonedDateTime?,
val subType: KeyValue?
)

enum class DocumentType(val description: String) {
enum class DocumentType(val description: String, val subtypes: List<SubType> = emptyList()) {
OFFENDER_DOCUMENT("Offender related"),
CONVICTION_DOCUMENT("Sentence related"),
CPSPACK_DOCUMENT("Crown Prosecution Service case pack"),
PRECONS_DOCUMENT("PNC previous convictions"),
COURT_REPORT_DOCUMENT("Court report"),
COURT_REPORT_DOCUMENT("Court report", listOf(SubType.PSR)),
INSTITUTION_REPORT_DOCUMENT("Institution report"),
ADDRESS_ASSESSMENT_DOCUMENT("Address assessment related document"),
APPROVED_PREMISES_REFERRAL_DOCUMENT("Approved premises referral related document"),
Expand All @@ -100,6 +90,10 @@ enum class DocumentType(val description: String) {
PREVIOUS_CONVICTION("Previous conviction document")
}

enum class SubType {
PSR
}

class Breach(
val description: String?,
val status: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.*
import uk.gov.justice.digital.hmpps.api.resource.ConvictionResource
import uk.gov.justice.digital.hmpps.api.resource.DocumentResource
import uk.gov.justice.digital.hmpps.api.resource.ProbationRecordResource
import uk.gov.justice.digital.hmpps.flags.FeatureFlags
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
Expand All @@ -24,6 +25,7 @@ class CommunityApiController(
private val featureFlags: FeatureFlags,
private val communityApiService: CommunityApiService,
private val convictionResource: ConvictionResource,
private val documentResource: DocumentResource,
private val taskExecutor: ThreadPoolTaskExecutor,
private val personRepository: PersonEventRepository,
private val telemetryService: TelemetryService,
Expand Down Expand Up @@ -292,6 +294,27 @@ class CommunityApiController(
return proxy(request)
}

@GetMapping("/offenders/crn/{crn}/documents/grouped")
fun documentsGrouped(
request: HttpServletRequest,
@PathVariable crn: String,
@RequestParam(required = false) type: String?,
@RequestParam(required = false) subtype: String?
): Any {

val params = mutableMapOf<String, String>()
type?.let { params["type"] = it }
subtype?.let { params["subtype"] = it }
sendComparisonReport(
params, Uri.DOCUMENTS_GROUPED, request
)

if (featureFlags.enabled("ccd-document-grouped")) {
return documentResource.getOffenderDocumentsGrouped(crn, type, subtype)
}
return proxy(request)
}

@GetMapping("/**")
fun proxy(request: HttpServletRequest): ResponseEntity<String> {
val headers = request.headerNames.asSequence().associateWith { request.getHeader(it) }.toMutableMap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.client.HttpStatusCodeException
import uk.gov.justice.digital.hmpps.api.resource.advice.CommunityApiControllerAdvice
import uk.gov.justice.digital.hmpps.exception.InvalidRequestException
import uk.gov.justice.digital.hmpps.exception.NotFoundException
import java.io.StringReader
import java.lang.reflect.InvocationTargetException
Expand Down Expand Up @@ -45,6 +46,7 @@ class CommunityApiService(
when (val cause = ex.cause) {
is AccessDeniedException -> controllerAdvice.handleAccessDenied(cause).body
is NotFoundException -> controllerAdvice.handleNotFound(cause).body
is InvalidRequestException -> controllerAdvice.handleInvalidRequest(cause).body
else -> throw ex
}
}
Expand All @@ -68,10 +70,14 @@ class CommunityApiService(

val uri = Uri.valueOf(compare.uri)
val comApiUri = compare.params.entries.fold(uri.comApiUrl) { path, (key, value) ->
path.replace(
"{$key}",
value.toString()
)
if (value != null) {
path.replace(
"{$key}",
value.toString()
)
} else {
path.replace("$key={$key}", "")
}
}.replace(" ", "%20")

val ccdJsonString = try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package uk.gov.justice.digital.hmpps.api.proxy

data class Compare(
val params: Map<String, Any>,
val params: Map<String, Any?>,
val uri: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,11 @@ enum class Uri(
"getConvictionSentenceStatus",
listOf("crn", "convictionId"),
),
DOCUMENTS_GROUPED(
"/secure/offenders/crn/{crn}/documents/grouped?type={type}&subtype={subtype}",
"documentResource",
"getOffenderDocumentsGrouped",
listOf("crn", "type", "subtype"),
),
DUMMY("/dummy", "dummyResource", "getDummy", listOf("crn")),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package uk.gov.justice.digital.hmpps.api.resource

import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.*
import uk.gov.justice.digital.hmpps.api.model.DocumentFilter
import uk.gov.justice.digital.hmpps.integrations.delius.service.DocumentService

@RestController
@RequestMapping("probation-case/{crn}/documents")
@PreAuthorize("hasRole('PROBATION_API__COURT_CASE__CASE_DETAIL')")
class DocumentResource(private val documentService: DocumentService) {

@GetMapping("/grouped")
fun getOffenderDocumentsGrouped(
@PathVariable crn: String,
@RequestParam(required = false) type: String?,
@RequestParam(required = false) subType: String?,
) = documentService.getDocumentsGroupedFor(crn, DocumentFilter(type, subType))
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package uk.gov.justice.digital.hmpps.api.resource.advice

import org.springframework.http.HttpStatus
import org.springframework.http.HttpStatus.FORBIDDEN
import org.springframework.http.HttpStatus.NOT_FOUND
import org.springframework.http.ResponseEntity
import org.springframework.security.access.AccessDeniedException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import uk.gov.justice.digital.hmpps.api.resource.ConvictionResource
import uk.gov.justice.digital.hmpps.api.resource.DocumentResource
import uk.gov.justice.digital.hmpps.api.resource.ProbationRecordResource
import uk.gov.justice.digital.hmpps.exception.InvalidRequestException
import uk.gov.justice.digital.hmpps.exception.NotFoundException

@RestControllerAdvice(basePackageClasses = [ProbationRecordResource::class, ConvictionResource::class])
@RestControllerAdvice(basePackageClasses = [ProbationRecordResource::class, ConvictionResource::class, DocumentResource::class])
class CommunityApiControllerAdvice {

@ExceptionHandler(InvalidRequestException::class)
fun handleInvalidRequest(e: InvalidRequestException) = ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(ErrorResponse(status = HttpStatus.BAD_REQUEST.value(), developerMessage = e.message))

@ExceptionHandler(NotFoundException::class)
fun handleNotFound(e: NotFoundException) = ResponseEntity
.status(NOT_FOUND)
Expand Down
Loading
Loading