Skip to content

Commit

Permalink
Pi 2105 crn crn convictions conviction id requirements (#3951)
Browse files Browse the repository at this point in the history
* PI-2105 add model, service and repo files

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update service and repo layer

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 add resource layer and update service

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 add integration test and small refactor

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 small refactor

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update model and integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update model and integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update model and integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update model and integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update model and integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update model and integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update model and integration test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 service and integration refactor

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 update test

Signed-off-by: Amardeep Chimber <[email protected]>

* PI-2105 - remove commented code

* PI-2105 - fix np error in dev

---------

Signed-off-by: Amardeep Chimber <[email protected]>
  • Loading branch information
achimber-moj authored Jun 26, 2024
1 parent ef711bf commit 8314e4e
Show file tree
Hide file tree
Showing 13 changed files with 432 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class DataLoader(
ReferenceDataGenerator.LENGTH_UNITS,
ReferenceDataGenerator.TERMINATION_REASON,
ReferenceDataGenerator.CUSTODIAL_STATUS,
ReferenceDataGenerator.MONTHS,
ReferenceDataGenerator.REQUIREMENT_MAIN_CAT,
ReferenceDataGenerator.REQUIREMENT_SUB_CAT,
ReferenceDataGenerator.AD_REQUIREMENT_MAIN_CAT,
Expand Down Expand Up @@ -154,7 +155,6 @@ class DataLoader(
val currentManager = SentenceGenerator.CURRENT_ORDER_MANAGER
val mainOffence = SentenceGenerator.MAIN_OFFENCE_DEFAULT
val additionalOffence = SentenceGenerator.ADDITIONAL_OFFENCE_DEFAULT
val requirement = SentenceGenerator.generateRequirement(disposal = currentSentence)
val licenceCondition = SentenceGenerator.generateLicenseCondition(disposal = currentSentence)
val breachNsi = SentenceGenerator.generateBreachNsi(disposal = currentSentence)
val pssRequirement = SentenceGenerator.generatePssRequirement(custody.id)
Expand All @@ -167,6 +167,10 @@ class DataLoader(
SentenceGenerator.INACTIVE_EVENT,
SentenceGenerator.INACTIVE_EVENT_1,
currentSentence,
RequirementsGenerator.ACTIVE_REQ,
RequirementsGenerator.INACTIVE_REQ,
RequirementsGenerator.DELETED_REQ,
RequirementsGenerator.INACTIVE_AND_DELETED_REQ,
AdditionalSentenceGenerator.SENTENCE_DISQ,
ReferenceDataGenerator.HOURS_WORKED,
UnpaidWorkGenerator.UNPAID_WORK_DETAILS_1,
Expand All @@ -192,7 +196,6 @@ class DataLoader(
SentenceGenerator.MAIN_OFFENCE_FOR_INACTIVE_EVENT,
SentenceGenerator.MAIN_OFFENCE_FOR_INACTIVE_EVENT_1,
additionalOffence,
requirement,
licenceCondition,
breachNsi,
pssRequirement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,17 @@ object ReferenceDataGenerator {
IdGenerator.getAndIncrement()
)

val MONTHS = ReferenceData(
"M",
"months",
IdGenerator.getAndIncrement()
)

val REQUIREMENT_MAIN_CAT = RequirementMainCategory(
"Main",
"Main cat",
MONTHS,
"N",
IdGenerator.getAndIncrement()
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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.conviction.entity.Requirement
import java.time.LocalDate

object RequirementsGenerator {

val ACTIVE_REQ = Requirement(
IdGenerator.getAndIncrement(),
CURRENT_SENTENCE.id,
"notes",
LocalDate.of(2024, 1, 1),
LocalDate.of(2024, 1, 2),
LocalDate.of(2024, 1, 3),
LocalDate.of(2024, 1, 4),
LocalDate.of(2024, 1, 5),
ReferenceDataGenerator.REQUIREMENT_SUB_CAT,
ReferenceDataGenerator.REQUIREMENT_MAIN_CAT,
ReferenceDataGenerator.AD_REQUIREMENT_MAIN_CAT,
ReferenceDataGenerator.AD_REQUIREMENT_SUB_CAT,
ReferenceDataGenerator.TERMINATION_REASON,
3,
active = true
)

val INACTIVE_REQ = generate(CURRENT_SENTENCE.id, active = false, softDeleted = false)

val DELETED_REQ = generate(CURRENT_SENTENCE.id, active = true, softDeleted = true)

val INACTIVE_AND_DELETED_REQ = generate(CURRENT_SENTENCE.id, active = false, softDeleted = true)

fun generate(
disposalId: Long,
active: Boolean,
softDeleted: Boolean,
) = Requirement(
IdGenerator.getAndIncrement(),
disposalId,
active = active,
softDeleted = softDeleted,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import java.time.LocalDate

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import java.time.LocalDate

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

Expand All @@ -54,7 +54,7 @@ internal class ConvictionIntegrationByCrnTest {
}

@Test
fun `retun a list of active events for a person`() {
fun `return a list of active events for a person`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn
val event = SentenceGenerator.CURRENTLY_MANAGED
val mainOffence = SentenceGenerator.MAIN_OFFENCE_DEFAULT
Expand Down Expand Up @@ -245,7 +245,7 @@ internal class ConvictionIntegrationByCrnTest {
}

@Test
fun `retun a list of active and inactive events for a person`() {
fun `return a list of active and inactive events for a person`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn

mockMvc
Expand All @@ -257,7 +257,7 @@ internal class ConvictionIntegrationByCrnTest {
}

@Test
fun `retun a empty list for a person with no active events`() {
fun `return a empty list for a person with no active events`() {
val crn = PersonGenerator.NO_ACTIVE_EVENTS.crn
mockMvc
.perform(get("/probation-case/$crn/convictions?activeOnly=true").withToken())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package uk.gov.justice.digital.hmpps

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource
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.MockMvcResultHandlers.print
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import uk.gov.justice.digital.hmpps.api.model.KeyValue
import uk.gov.justice.digital.hmpps.api.model.conviction.ConvictionRequirements
import uk.gov.justice.digital.hmpps.api.model.conviction.Requirement
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.data.generator.RequirementsGenerator
import uk.gov.justice.digital.hmpps.data.generator.SentenceGenerator
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 RequirementsByEventIdIntegrationTest {
@Autowired
lateinit var mockMvc: MockMvc

@Test
fun `unauthorized status returned`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn
mockMvc
.perform(get("/probation-case/$crn/convictions/123/requirements"))
.andExpect(status().isUnauthorized)
}

@Test
fun `probation record not found`() {
mockMvc
.perform(get("/probation-case/A123456/convictions/123/requirements").withToken())
.andExpect(status().isNotFound)
.andExpect(jsonPath("$.message").value("Person with crn of A123456 not found"))
}

@Test
fun `sentence not found`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn

mockMvc
.perform(get("/probation-case/$crn/convictions/3/requirements").withToken())
.andExpect(status().isNotFound)
.andExpect(jsonPath("$.message").value("Conviction with convictionId 3 not found"))
}

@Test
fun `return list of requirements`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn
val event = SentenceGenerator.CURRENTLY_MANAGED

val requirement = RequirementsGenerator.ACTIVE_REQ
val expectedResponse = ConvictionRequirements(
listOf(
Requirement(
requirement.id,
requirement.notes,
requirement.commencementDate,
requirement.startDate,
requirement.terminationDate,
requirement.expectedStartDate,
requirement.expectedEndDate,
requirement.active,
requirement.subCategory?.let { KeyValue(it.code, it.description) },
requirement.mainCategory?.let { KeyValue(it.code, it.description) },
requirement.adMainCategory?.let { KeyValue(it.code, it.description) },
requirement.adSubCategory?.let { KeyValue(it.code, it.description) },
requirement.terminationReason?.let { KeyValue(it.code, it.description) },
requirement.length,
requirement.mainCategory?.let { it.units?.description },
restrictive = false,
softDeleted = false,
rarCount = requirement.rarCount
)
)
)

val response = mockMvc
.perform(get("/probation-case/$crn/convictions/${event.id}/requirements").withToken())
.andExpect(status().isOk)
.andDo(print())
.andReturn().response.contentAsJson<ConvictionRequirements>()

assertEquals(expectedResponse, response)
}

@Test
fun `return empty list of requirements`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn
val event = SentenceGenerator.INACTIVE_EVENT

mockMvc
.perform(get("/probation-case/$crn/convictions/${event.id}/requirements").withToken())
.andExpect(status().isOk)
.andExpect(jsonPath("$.requirements").isEmpty)
}

@ParameterizedTest
@CsvSource(
"activeOnly=false,false,false",
"excludeSoftDeleted=false,true,true",
"activeOnly=false&&excludeSoftDeleted=false,false,true"
)
fun `return list based on request parameters`(requestParams: String, active: Boolean, deleted: Boolean) {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn
val event = SentenceGenerator.CURRENTLY_MANAGED

mockMvc
.perform(get("/probation-case/$crn/convictions/${event.id}/requirements?$requestParams").withToken())
.andExpect(status().isOk)
.andDo(print())
.andExpect(jsonPath("$.requirements.length()").value(1))
.andExpect(jsonPath("$.requirements[0].active").value(active))
.andExpect(jsonPath("$.requirements[0].softDeleted").value(deleted))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ data class Institution(
val description: String,
val institutionName: String?,
val establishmentType: KeyValue?,
val isPrivate: Boolean,
val isPrivate: Boolean?,
val nomsPrisonInstitutionCode: String? = null
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package uk.gov.justice.digital.hmpps.api.model.conviction

import io.swagger.v3.oas.annotations.media.Schema
import uk.gov.justice.digital.hmpps.api.model.KeyValue
import java.time.LocalDate

data class ConvictionRequirements(
val requirements: List<Requirement>
)

data class Requirement(
@Schema(description = "Unique identifier for the requirement", required = true)
val requirementId: Long,
@Schema(description = "Name of the requirement", required = true)
val requirementNotes: String?,
val commencementDate: LocalDate?,
val startDate: LocalDate?,
val terminationDate: LocalDate?,
val expectedStartDate: LocalDate?,
val expectedEndDate: LocalDate?,
@Schema(description = "Is the requirement currently active")
val active: Boolean,
val requirementTypeSubCategory: KeyValue?,
val requirementTypeMainCategory: KeyValue?,
val adRequirementTypeMainCategory: KeyValue?,
val adRequirementTypeSubCategory: KeyValue?,
val terminationReason: KeyValue?,
@Schema(description = "The number of temporal units to complete the requirement (see lengthUnit field for unit)")
val length: Long?,
@Schema(description = "The temporal unit corresponding to the length field")
val lengthUnit: String?,
@Schema(description = "Is the main category restrictive")
val restrictive: Boolean?,
val softDeleted: Boolean,
@Schema(description = "Total RAR days completed")
val rarCount: Long?
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ 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.integrations.delius.service.ConvictionService
import uk.gov.justice.digital.hmpps.integrations.delius.service.RequirementService

@RestController
@RequestMapping("probation-case/{crn}/convictions")
@PreAuthorize("hasRole('PROBATION_API__COURT_CASE__CASE_DETAIL')")
class ConvictionResource(private val convictionService: ConvictionService) {
class ConvictionResource(
private val convictionService: ConvictionService,
private val requirementService: RequirementService,
) {

@GetMapping
fun getConvictionsForOffenderByCrn(
Expand All @@ -20,4 +24,12 @@ class ConvictionResource(private val convictionService: ConvictionService) {
@PathVariable crn: String,
@PathVariable convictionId: Long
) = convictionService.getConvictionFor(crn, convictionId)

@GetMapping("/{convictionId}/requirements")
fun getRequirementsForConviction(
@PathVariable crn: String,
@PathVariable convictionId: Long,
@RequestParam(required = false, defaultValue = "true") activeOnly: Boolean,
@RequestParam(required = false, defaultValue = "true") excludeSoftDeleted: Boolean,
) = requirementService.getRequirementsByConvictionId(crn, convictionId, activeOnly, !excludeSoftDeleted)
}
Loading

0 comments on commit 8314e4e

Please sign in to comment.