Skip to content

Commit

Permalink
PI-2111 update EPF detail endpoint (#3646)
Browse files Browse the repository at this point in the history
* PI-2111 update EPF detail endpoint

* Formatting changes

* PI-2111 update EPF detail endpoint

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
anthony-britton-moj and github-actions[bot] authored Apr 18, 2024
1 parent 222b8eb commit 645fc25
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ class DataLoader(
SentenceGenerator.generateOgrsAssessment(LocalDate.now().minusDays(1), 3),
SentenceGenerator.generateOgrsAssessment(LocalDate.now().minusDays(5), 1),
SentenceGenerator.generateOgrsAssessment(LocalDate.now(), 5, softDeleted = true),
PersonGenerator.RELEASED,
PersonGenerator.WITH_RELEASE_DATE,
ManagerGenerator.RELEASED_PERSON_MANAGER,
SentenceGenerator.RELEASE_DATE_TYPE,
SentenceGenerator.RELEASED_EVENT,
SentenceGenerator.RELEASED_COURT_APPEARANCE,
SentenceGenerator.RELEASED_SENTENCE,
SentenceGenerator.RELEASED_CUSTODY,
SentenceGenerator.RELEASE
SentenceGenerator.RELEASE_DATE
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ object ManagerGenerator {
val DEFAULT_PERSON_MANAGER = personManagerGenerator(PersonGenerator.DEFAULT)
val DEFAULT_RESPONSIBLE_OFFICER =
responsibleOfficerGenerator(communityManager = DEFAULT_PERSON_MANAGER, prisonManager = null, endDate = null)
val RELEASED_PERSON_MANAGER = personManagerGenerator(PersonGenerator.RELEASED)
val RELEASED_PERSON_MANAGER = personManagerGenerator(PersonGenerator.WITH_RELEASE_DATE)

fun responsibleOfficerGenerator(
id: Long = IdGenerator.getAndIncrement(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object PersonGenerator {
val DEFAULT = generate("N123456", "A1234YZ")
val EXCLUDED = generate("E123456", currentExclusion = true)
val RESTRICTED = generate("R123456", currentRestriction = true)
val RELEASED = generate("F123456")
val WITH_RELEASE_DATE = generate("F123456")

fun generate(
crn: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ package uk.gov.justice.digital.hmpps.data.generator

import uk.gov.justice.digital.hmpps.epf.entity.*
import java.time.LocalDate
import java.time.ZonedDateTime

object SentenceGenerator {
val DEFAULT_COURT = generateCourt()
val RELEASE_DATE_TYPE = generateKeyDateType(KeyDate.Type.EXPECTED_RELEASE_DATE.code)

val DEFAULT_EVENT = generateEvent()
val DEFAULT_COURT_APPEARANCE = generateCourtAppearance(DEFAULT_EVENT)
val DEFAULT_SENTENCE = generateSentence(DEFAULT_EVENT)

val RELEASED_EVENT = generateEvent(person = PersonGenerator.RELEASED)
val RELEASED_EVENT = generateEvent(person = PersonGenerator.WITH_RELEASE_DATE)
val RELEASED_COURT_APPEARANCE = generateCourtAppearance(RELEASED_EVENT)
val RELEASED_SENTENCE = generateSentence(RELEASED_EVENT)
val RELEASED_CUSTODY = generateCustody(RELEASED_SENTENCE)
val RELEASE = generateRelease(RELEASED_CUSTODY)
val RELEASE_DATE = generateExpectedReleaseDate(RELEASED_CUSTODY, LocalDate.now().plusWeeks(6))

fun generateSentence(
event: Event,
Expand Down Expand Up @@ -54,12 +54,19 @@ object SentenceGenerator {
disposal: Disposal,
softDeleted: Boolean = false,
id: Long = IdGenerator.getAndIncrement()
) = Custody(disposal, listOf(), softDeleted, id)
) = Custody(disposal, softDeleted, id)

fun generateRelease(
fun generateKeyDateType(
code: String,
description: String = "Key Date Type of $code",
id: Long = IdGenerator.getAndIncrement()
) = ReferenceData(id, code, description)

fun generateExpectedReleaseDate(
custody: Custody,
date: LocalDate = LocalDate.now(),
createdDateTime: ZonedDateTime = ZonedDateTime.now(),
type: ReferenceData = RELEASE_DATE_TYPE,
softDeleted: Boolean = false,
id: Long = IdGenerator.getAndIncrement()
) = Release(custody, date, createdDateTime, id)
) = KeyDate(custody, type, date, softDeleted, id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal class IntegrationTest {

@Test
fun `release details are correctly displayed`() {
val person = PersonGenerator.RELEASED
val person = PersonGenerator.WITH_RELEASE_DATE
val crn = person.crn
val eventNumber = 1
val detailResponse = mockMvc
Expand All @@ -66,14 +66,12 @@ internal class IntegrationTest {
Name(person.forename, person.secondName, person.surname),
person.dateOfBirth,
person.gender.description,
Conviction(
SentenceGenerator.RELEASED_EVENT.convictionDate!!,
Appearance(
SentenceGenerator.DEFAULT_COURT_APPEARANCE.appearanceDate,
Court(SentenceGenerator.DEFAULT_COURT.name)
),
Sentence(
SentenceGenerator.RELEASED_SENTENCE.date,
Court(SentenceGenerator.DEFAULT_COURT.name),
SentenceGenerator.RELEASE.date
SentenceGenerator.RELEASE_DATE.date
),
Provider(ProviderGenerator.DEFAULT.code, ProviderGenerator.DEFAULT.description),
null
Expand All @@ -92,12 +90,11 @@ internal class IntegrationTest {
),
PersonGenerator.DEFAULT.dateOfBirth,
PersonGenerator.DEFAULT.gender.description,
Conviction(SentenceGenerator.DEFAULT_EVENT.convictionDate!!, Court(SentenceGenerator.DEFAULT_COURT.name)),
Sentence(
SentenceGenerator.DEFAULT_SENTENCE.date,
Court(SentenceGenerator.DEFAULT_COURT.name),
null
Appearance(
SentenceGenerator.DEFAULT_COURT_APPEARANCE.appearanceDate,
Court(SentenceGenerator.DEFAULT_COURT.name)
),
null,
Provider(ProviderGenerator.DEFAULT.code, ProviderGenerator.DEFAULT.description),
3
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ data class CaseDetails(
val name: Name,
val dateOfBirth: LocalDate,
val gender: String,
val conviction: Conviction?,
val courtAppearance: Appearance?,
val sentence: Sentence?,
val responsibleProvider: Provider?,
val ogrsScore: Long?
Expand All @@ -18,19 +18,17 @@ data class CaseDetails(
get() = YEARS.between(dateOfBirth, LocalDate.now())

val ageAtRelease
get() = sentence?.releaseDate?.let { YEARS.between(dateOfBirth, it) }
get() = sentence?.expectedReleaseDate?.let { YEARS.between(dateOfBirth, it) }
}

data class Name(val forename: String, val middleName: String?, val surname: String)
data class Conviction(
data class Appearance(
val date: LocalDate,
val court: Court,
val court: Court
)

data class Sentence(
val date: LocalDate,
val sentencingCourt: Court,
val releaseDate: LocalDate?
val expectedReleaseDate: LocalDate?
)

data class Court(val name: String)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package uk.gov.justice.digital.hmpps.epf

import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import uk.gov.justice.digital.hmpps.epf.entity.*

@Service
Expand All @@ -10,30 +11,25 @@ class CaseDetailsService(
private val personManagerRepository: PersonManagerRepository,
private val courtAppearanceRepository: CourtAppearanceRepository,
private val eventRepository: EventRepository,
private val keyDateRepository: KeyDateRepository,
private val ogrsAssessmentRepository: OgrsAssessmentRepository
) {
@Transactional
fun caseDetails(crn: String, eventNumber: Int): CaseDetails {
val person = personRepository.getPerson(crn)
val provider = responsibleOfficerRepository.findByPersonIdAndEndDateIsNull(person.id)?.provider()
?: personManagerRepository.findByPersonId(person.id)?.provider()
val event = eventRepository.getEvent(person.crn, eventNumber.toString())
val courtName = courtAppearanceRepository.findMostRecentCourtNameByEventId(event.id)
val appearance = courtAppearanceRepository.findByEventIdOrderByAppearanceDateDesc(event.id)
val erd = event.disposal?.custody?.let { keyDateRepository.getExpectedReleaseDate(it.id) }
val ogrsScore = ogrsAssessmentRepository.findFirstByEventIdOrderByAssessmentDateDesc(event.id)?.score
return CaseDetails(
person.nomsId,
person.name(),
person.dateOfBirth,
person.gender.description,
event.convictionDate?.let {
Conviction(it, Court(courtName))
},
event.disposal?.date?.let {
Sentence(
it,
Court(courtName),
event.disposal.custody?.mostRecentRelease()?.date
)
},
appearance?.let { Appearance(it.appearanceDate, Court(it.court.name)) },
erd?.let { Sentence(it.date) },
provider,
ogrsScore
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package uk.gov.justice.digital.hmpps.epf.entity

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import jakarta.persistence.*
import org.hibernate.annotations.Immutable
import org.hibernate.annotations.SQLRestriction
import org.springframework.data.domain.PageRequest
import org.springframework.data.jpa.repository.EntityGraph
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import java.time.LocalDate

@Entity
Expand Down Expand Up @@ -51,15 +46,11 @@ class CourtAppearance(
val softDeleted: Boolean = false
)

interface CourtRepository : JpaRepository<Court, Long>
interface CourtAppearanceRepository : JpaRepository<CourtAppearance, Long> {

@Query(
"""
select ca.court.name as name from CourtAppearance ca
where ca.event.id = :eventId
order by ca.appearanceDate desc
"""
)
fun findMostRecentCourtNameByEventId(eventId: Long, page: PageRequest = PageRequest.of(0, 1)): String
@EntityGraph(attributePaths = ["court"])
fun findByEventIdOrderByAppearanceDateDesc(
eventId: Long,
page: PageRequest = PageRequest.of(0, 1)
): CourtAppearance?
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import uk.gov.justice.digital.hmpps.exception.NotFoundException
import java.time.LocalDate
import java.time.ZonedDateTime

@Immutable
@Entity
Expand Down Expand Up @@ -70,36 +69,41 @@ class Custody(
@JoinColumn(name = "disposal_id", updatable = false)
val disposal: Disposal,

@OneToMany(mappedBy = "custody")
val releases: List<Release>,

@Column(columnDefinition = "number", nullable = false)
val softDeleted: Boolean,

@Id
@Column(name = "custody_id")
val id: Long
) {
fun mostRecentRelease() = releases.maxWithOrNull(compareBy({ it.date }, { it.createdDateTime }))
}
)

@Immutable
@Entity
class Release(
@Immutable
@SQLRestriction("soft_deleted = 0")
class KeyDate(

@ManyToOne
@JoinColumn(name = "custody_id", nullable = false)
@JoinColumn(name = "custody_id")
val custody: Custody,

@Column(name = "actual_release_date")
val date: LocalDate,
@ManyToOne
@JoinColumn(name = "key_date_type_id")
val type: ReferenceData,

@Column(name = "key_date")
var date: LocalDate,

@Column(name = "created_datetime")
val createdDateTime: ZonedDateTime,
@Column(columnDefinition = "number")
val softDeleted: Boolean,

@Id
@Column(name = "release_id", nullable = false)
@Column(name = "key_date_id")
val id: Long
)
) {
enum class Type(val code: String) {
EXPECTED_RELEASE_DATE("EXP")
}
}

interface EventRepository : JpaRepository<Event, Long> {

Expand All @@ -109,7 +113,6 @@ interface EventRepository : JpaRepository<Event, Long> {
join fetch e.person p
left join fetch e.disposal d
left join fetch d.custody c
left join fetch c.releases
where e.number = :number
and p.crn = :crn
"""
Expand All @@ -119,3 +122,10 @@ interface EventRepository : JpaRepository<Event, Long> {

fun EventRepository.getEvent(crn: String, number: String) =
findEventByCrnAndEventNumber(crn, number) ?: throw NotFoundException("Event", "crn", crn)

interface KeyDateRepository : JpaRepository<KeyDate, Long> {
fun findByCustodyIdAndTypeCode(custodyId: Long, typeCode: String): KeyDate?
}

fun KeyDateRepository.getExpectedReleaseDate(custodyId: Long) =
findByCustodyIdAndTypeCode(custodyId, KeyDate.Type.EXPECTED_RELEASE_DATE.code)
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ internal class CaseDetailsServiceTest {
@Mock
internal lateinit var eventRepository: EventRepository

@Mock
internal lateinit var keyDateRepository: KeyDateRepository

@Mock
internal lateinit var ogrsAssessmentRepository: OgrsAssessmentRepository

Expand All @@ -46,7 +49,8 @@ internal class CaseDetailsServiceTest {
whenever(responsibleOfficerRepository.findByPersonIdAndEndDateIsNull(person.id)).thenReturn(null)
whenever(personManagerRepository.findByPersonId(person.id)).thenReturn(ManagerGenerator.DEFAULT_PERSON_MANAGER)
whenever(eventRepository.findEventByCrnAndEventNumber(person.crn, event.number)).thenReturn(event)
whenever(courtAppearanceRepository.findMostRecentCourtNameByEventId(event.id)).thenReturn(SentenceGenerator.DEFAULT_COURT.name)
whenever(courtAppearanceRepository.findByEventIdOrderByAppearanceDateDesc(event.id))
.thenReturn(SentenceGenerator.generateCourtAppearance(event))

val res = service.caseDetails(person.crn, event.number.toInt())
assertNotNull(res.responsibleProvider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ internal class CaseDetailsTest {
Name("John", "", "Smith"),
LocalDate.of(1982, 8, 3),
"Male",
Conviction(LocalDate.now(), Court("NA Court")),
Sentence(LocalDate.of(2013, 9, 23), Court("NA Court"), LocalDate.of(2022, 8, 2)),
Appearance(LocalDate.now(), Court("NA Court")),
Sentence(LocalDate.of(2022, 8, 2)),
Provider("N00", "London"),
null
)

private fun CaseDetails.withReleaseDate(releaseDate: LocalDate) =
copy(sentence = this.sentence?.copy(releaseDate = releaseDate))
copy(sentence = this.sentence?.copy(expectedReleaseDate = releaseDate))

@JvmStatic
fun ageAtRelease() = listOf(
Expand Down

0 comments on commit 645fc25

Please sign in to comment.