Skip to content

Commit

Permalink
Feature/pi 2104 crn convictions conviction id pss requirements (#4051)
Browse files Browse the repository at this point in the history
* PI-2104 - add new api

* PI-2104 - update tests

* Formatting changes

* PI-2104 - refactor model object

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
achimber-moj and github-actions[bot] authored Jul 18, 2024
1 parent 9b7c13a commit 77d9aab
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
import uk.gov.justice.digital.hmpps.api.model.DocumentType
import uk.gov.justice.digital.hmpps.data.generator.*
import uk.gov.justice.digital.hmpps.datetime.EuropeLondon
import uk.gov.justice.digital.hmpps.user.AuditUserRepository
import java.time.LocalDate
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZonedDateTime

@Component
Expand Down Expand Up @@ -131,8 +131,8 @@ class DataLoader(
noSentenceEvent,
StaffGenerator.UNALLOCATED,
CourtGenerator.PROBATION_AREA,
ZonedDateTime.of(LocalDate.now(), LocalTime.NOON, ZoneId.of("Europe/London")),
ZonedDateTime.of(LocalDate.now().minusDays(1), LocalTime.NOON, ZoneId.of("Europe/London"))
ZonedDateTime.of(LocalDate.now(), LocalTime.NOON, EuropeLondon),
ZonedDateTime.of(LocalDate.now().minusDays(1), LocalTime.NOON, EuropeLondon)
)
val outcome = SentenceGenerator.OUTCOME
val courtAppearance = SentenceGenerator.generateCourtAppearance(noSentenceEvent, outcome, ZonedDateTime.now())
Expand All @@ -146,8 +146,8 @@ class DataLoader(
newEvent,
StaffGenerator.UNALLOCATED,
CourtGenerator.PROBATION_AREA,
ZonedDateTime.of(LocalDate.now().minusDays(1), LocalTime.NOON, ZoneId.of("Europe/London")),
ZonedDateTime.of(LocalDate.now().minusDays(3), LocalTime.NOON, ZoneId.of("Europe/London"))
ZonedDateTime.of(LocalDate.now().minusDays(1), LocalTime.NOON, EuropeLondon),
ZonedDateTime.of(LocalDate.now().minusDays(3), LocalTime.NOON, EuropeLondon)
)
em.saveAll(newEvent, newSentence, newManager)

Expand All @@ -159,7 +159,8 @@ class DataLoader(
val additionalOffence = SentenceGenerator.ADDITIONAL_OFFENCE_DEFAULT
val licenceCondition = SentenceGenerator.generateLicenseCondition(disposal = currentSentence)
val breachNsi = SentenceGenerator.BREACH_NSIS
val pssRequirement = SentenceGenerator.generatePssRequirement(custody.id)
val activePssRequirement = SentenceGenerator.generatePssRequirement(custody.id, active = true)
val inactivePssRequirement = SentenceGenerator.generatePssRequirement(custody.id, active = false)
val currentCourtAppearance = SentenceGenerator.COURT_APPEARANCE
val currentCourtReport = SentenceGenerator.generateCourtReport(currentCourtAppearance)
val reportManager = SentenceGenerator.generateCourtReportManager(currentCourtReport)
Expand Down Expand Up @@ -203,7 +204,8 @@ class DataLoader(
breachNsi,
NsiManagerGenerator.ACTIVE,
NsiManagerGenerator.INACTIVE,
pssRequirement,
activePssRequirement,
inactivePssRequirement,
currentCourtAppearance,
currentCourtReport,
reportManager
Expand All @@ -227,8 +229,8 @@ class DataLoader(
preEvent,
StaffGenerator.ALLOCATED,
CourtGenerator.PROBATION_AREA,
ZonedDateTime.of(LocalDate.now().minusDays(7), LocalTime.NOON, ZoneId.of("Europe/London")),
ZonedDateTime.of(LocalDate.now().minusDays(10), LocalTime.NOON, ZoneId.of("Europe/London"))
ZonedDateTime.of(LocalDate.now().minusDays(7), LocalTime.NOON, EuropeLondon),
ZonedDateTime.of(LocalDate.now().minusDays(10), LocalTime.NOON, EuropeLondon)
)
em.saveAll(preEvent, preSentence, preManager)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,12 +357,14 @@ object SentenceGenerator {
CourtGenerator.PROBATION_AREA
)

fun generatePssRequirement(custodyId: Long, id: Long = IdGenerator.getAndIncrement()) = PssRequirement(
custodyId,
ReferenceDataGenerator.PSS_MAIN_CAT,
ReferenceDataGenerator.PSS_SUB_CAT,
id = id
)
fun generatePssRequirement(custodyId: Long, id: Long = IdGenerator.getAndIncrement(), active: Boolean) =
PssRequirement(
custodyId,
ReferenceDataGenerator.PSS_MAIN_CAT,
ReferenceDataGenerator.PSS_SUB_CAT,
active = active,
id = id
)

fun generateCourtReport(courtAppearance: CourtAppearance, id: Long = IdGenerator.getAndIncrement()) =
CourtReport(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package uk.gov.justice.digital.hmpps

import org.junit.jupiter.api.Assertions.assertEquals
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.MockMvcResultHandlers
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.conviction.PssRequirement
import uk.gov.justice.digital.hmpps.api.model.conviction.PssRequirements
import uk.gov.justice.digital.hmpps.api.model.keyValueOf
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator
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 PssRequirementsByCrnAndEventIdIntegrationTest {
@Autowired
lateinit var mockMvc: MockMvc

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

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

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

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

@Test
fun `API call retuns pss requirements by crn convictionId`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn
val event = SentenceGenerator.CURRENTLY_MANAGED

val pssRequirements = listOf(
PssRequirement(
ReferenceDataGenerator.PSS_MAIN_CAT.keyValueOf(),
ReferenceDataGenerator.PSS_SUB_CAT.keyValueOf(),
true
),
PssRequirement(
ReferenceDataGenerator.PSS_MAIN_CAT.keyValueOf(),
ReferenceDataGenerator.PSS_SUB_CAT.keyValueOf(),
false
),
)

val expectedResponse = PssRequirements(pssRequirements)

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

assertEquals(expectedResponse, response)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData
import uk.gov.justice.digital.hmpps.integrations.delius.event.courtappearance.entity.CourtReportType
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.AdRequirementMainCategory
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.RequirementMainCategory
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.PssRequirementMainCat
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.PssRequirementSubCat
import java.time.LocalDate
import java.time.ZonedDateTime

fun ReferenceData.keyValueOf() = KeyValue(code, description)
fun RequirementMainCategory.keyValueOf() = KeyValue(code, description)
fun AdRequirementMainCategory.keyValueOf() = KeyValue(code, description)
fun CourtReportType.keyValueOf() = KeyValue(code, description)
fun PssRequirementMainCat.keyValueOf(): KeyValue = KeyValue(code, description)
fun PssRequirementSubCat.keyValueOf(): KeyValue = KeyValue(code, description)

data class Conviction(
val active: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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

data class PssRequirements(
@Schema(description = "List of pssRequirements associated with this conviction")
val pssRequirements: List<PssRequirement>
)

data class PssRequirement(
val type: KeyValue?,
val subType: KeyValue?,
@Schema(description = "Is the requirement currently active")
val active: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,10 @@ class ConvictionResource(
)
@NotEmpty @RequestParam(required = true) nsiCodes: List<String>
) = interventionService.getNsiByCodes(crn, convictionId, nsiCodes)

@GetMapping("/{convictionId}/pssRequirements")
fun getPssRequirementsByConvictionId(
@PathVariable crn: String,
@PathVariable convictionId: Long
) = requirementService.getPssRequirementsByConvictionId(crn, convictionId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import uk.gov.justice.digital.hmpps.exception.NotFoundException
import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.AdRequirementMainCategory
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.RequirementMainCategory
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.Custody
import java.time.LocalDate
import java.time.ZonedDateTime
import uk.gov.justice.digital.hmpps.api.model.conviction.Requirement as RequirementModel
Expand Down Expand Up @@ -119,7 +120,10 @@ class Event(
val id: Long,

@Column(name = "offender_id")
val offenderId: Long
val offenderId: Long,

@OneToOne(mappedBy = "event")
val disposal: Disposal? = null,
)

interface ConvictionEventRepository : JpaRepository<Event, Long> {
Expand All @@ -141,6 +145,25 @@ class Disposal(
@OneToOne
@JoinColumn(name = "event_id")
val event: Event,

@OneToOne(mappedBy = "disposal")
val custody: Custody?,
)

@Entity(name = "conviction_custody")
@Table(name = "custody")
@Immutable
class Custody(
@Id
@Column(name = "custody_id")
val id: Long,

@Column(name = "disposal_id")
val disposalId: Long,

@OneToOne
@JoinColumn(name = "disposal_id", updatable = false, insertable = false)
val disposal: Disposal,
)

interface ConvictionRequirementRepository : JpaRepository<Requirement, Long> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class Custody(
@Entity
@Immutable
@Table(name = "pss_rqmnt")
@SQLRestriction("soft_deleted = 0 and active_flag = 1")
@SQLRestriction("soft_deleted = 0")
class PssRequirement(

@Column(name = "custody_id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,66 @@ package uk.gov.justice.digital.hmpps.integrations.delius.service

import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.api.model.conviction.ConvictionRequirements
import uk.gov.justice.digital.hmpps.api.model.conviction.PssRequirement
import uk.gov.justice.digital.hmpps.api.model.conviction.PssRequirements
import uk.gov.justice.digital.hmpps.api.model.keyValueOf
import uk.gov.justice.digital.hmpps.integrations.delius.event.conviction.entity.ConvictionEventRepository
import uk.gov.justice.digital.hmpps.integrations.delius.event.conviction.entity.ConvictionRequirementRepository
import uk.gov.justice.digital.hmpps.integrations.delius.event.conviction.entity.Event
import uk.gov.justice.digital.hmpps.integrations.delius.event.conviction.entity.getByEventId
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.PssRequirementRepository
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonRepository
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.getPerson
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.PssRequirement as PssRequirementEntity

@Service
class RequirementService(
private val personRepository: PersonRepository,
private val convictionEventRepository: ConvictionEventRepository,
private val convictionRequirementRepository: ConvictionRequirementRepository
private val convictionRequirementRepository: ConvictionRequirementRepository,
private val pssRequirementRepository: PssRequirementRepository
) {
fun getRequirementsByConvictionId(
crn: String,
convictionId: Long,
includeInactive: Boolean,
includeDeleted: Boolean
): ConvictionRequirements {

val person = personRepository.getPerson(crn)
val event = convictionEventRepository.getByEventId(convictionId, person.id)
val event = getEventForPersonByCrnAndEventId(crn, convictionId)

return ConvictionRequirements(
convictionRequirementRepository
.getRequirements(event.id, includeInactive, includeDeleted)
.map { it.toRequirementModel() }
)
}
}

fun getPssRequirementsByConvictionId(crn: String, convictionId: Long): PssRequirements {
val event = getEventForPersonByCrnAndEventId(crn, convictionId)

return PssRequirements(getPssRequirements(event.disposal?.custody?.id))
}

fun getEventForPersonByCrnAndEventId(crn: String, convictionId: Long): Event {
val person = personRepository.getPerson(crn)
return convictionEventRepository.getByEventId(convictionId, person.id)
}

fun getPssRequirements(custodyId: Long?) = if (custodyId == null) {
listOf()
} else {
pssRequirementRepository.findAllByCustodyId(custodyId).map {
it.toPssRequirement()
}
}
}

fun PssRequirementEntity.toPssRequirement(): PssRequirement =
PssRequirement(
mainCategory?.let { mainCategory.keyValueOf() },
subCategory?.let { subCategory.keyValueOf() },
active
)



Loading

0 comments on commit 77d9aab

Please sign in to comment.