Skip to content

Commit

Permalink
PI-2106: Added sentence status endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
pmcphee77 committed Aug 7, 2024
1 parent 357447d commit c59ef9e
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,19 +125,20 @@ class DataLoader(
PersonGenerator.generatePersonManager(PersonGenerator.CURRENTLY_MANAGED),
)

val noSentenceEvent =
SentenceGenerator.generateEvent(PersonGenerator.NO_SENTENCE, referralDate = LocalDate.now())
// val noSentenceEvent =
// SentenceGenerator.generateEvent(PersonGenerator.NO_SENTENCE, referralDate = LocalDate.now())
val noSentenceManager =
SentenceGenerator.generateOrderManager(
noSentenceEvent,
SentenceGenerator.NO_SENTENCE_EVENT,
StaffGenerator.UNALLOCATED,
CourtGenerator.PROBATION_AREA,
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, LocalDateTime.now())
em.saveAll(noSentenceEvent, noSentenceManager, outcome, courtAppearance)
val courtAppearance =
SentenceGenerator.generateCourtAppearance(SentenceGenerator.NO_SENTENCE_EVENT, outcome, LocalDateTime.now())
em.saveAll(SentenceGenerator.NO_SENTENCE_EVENT, noSentenceManager, outcome, courtAppearance)

val newEvent = SentenceGenerator.generateEvent(PersonGenerator.NEW_TO_PROBATION, referralDate = LocalDate.now())
val newSentence =
Expand Down Expand Up @@ -188,6 +189,8 @@ class DataLoader(
UnpaidWorkGenerator.APPT7,
currentManager,
custody,
SentenceGenerator.RELEASE_1,
SentenceGenerator.RELEASE_2,
SentenceGenerator.CONDITIONAL_RELEASE_KEY_DATE,
SentenceGenerator.LED_KEY_DATE,
SentenceGenerator.HDC_KEY_DATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,18 @@ object SentenceGenerator {
lengthInDays = 99
)

val NO_SENTENCE_EVENT = generateEvent(PersonGenerator.NO_SENTENCE, referralDate = LocalDate.now())

val CURRENT_CUSTODY = generateCustody(
CURRENT_SENTENCE,
ReferenceDataGenerator.CUSTODIAL_STATUS,
"FD1234",
InstitutionGenerator.WSIHMP
)

val RELEASE_1 = generateRelease(LocalDateTime.now().minusDays(3))
val RELEASE_2 = generateRelease(LocalDateTime.now().minusDays(2))

val OUTCOME = Outcome(
Outcome.Code.AWAITING_PSR.value,
Outcome.Code.AWAITING_PSR.description,
Expand Down Expand Up @@ -407,4 +412,10 @@ object SentenceGenerator {

fun generateKeyDates(date: LocalDate, custody: Custody, keyDateType: ReferenceData) =
KeyDate(IdGenerator.getAndIncrement(), date, custody, keyDateType)

fun generateRelease(date: LocalDateTime) = Release(
id = IdGenerator.getAndIncrement(),
custody = CURRENT_CUSTODY,
date = date
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"sentenceId": 87,
"custodialType": {
"code": "C1",
"description": "Custodial status"
},
"sentence": {
"description": "Curfew Order"
},
"mainOffence": {
"description": "Main Offence"
},
"sentenceDate": "2024-08-07",
"actualReleaseDate": "2024-08-05",
"lengthUnit": "Months"
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
{
"mappings": [
{
"request": {
"method": "GET",
"urlPathTemplate": "/secure/offenders/crn/{crn}/convictions/{convictionId}/sentenceStatus"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"bodyFileName": "get_sentence_status_C123456.json"
}
},
{
"request": {
"method": "GET",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import uk.gov.justice.digital.hmpps.api.model.Attendances
import uk.gov.justice.digital.hmpps.api.model.KeyValue
import uk.gov.justice.digital.hmpps.api.model.LicenceConditions
import uk.gov.justice.digital.hmpps.api.model.conviction.*
import uk.gov.justice.digital.hmpps.api.resource.advice.ErrorResponse
import uk.gov.justice.digital.hmpps.data.generator.AdditionalSentenceGenerator.SENTENCE_DISQ
import uk.gov.justice.digital.hmpps.data.generator.ContactGenerator.ATTENDANCE_CONTACT_1
import uk.gov.justice.digital.hmpps.data.generator.CourtGenerator.BHAM
Expand Down Expand Up @@ -314,4 +315,30 @@ internal class ConvictionByCrnAndEventIdIntegrationTest {
assertThat(response.licenceConditions.size, equalTo(1))
assertThat(response.licenceConditions[0].licenceConditionNotes, equalTo("Licence Condition notes"))
}

@Test
fun `call convictions by id and sentence status`() {
val crn = PersonGenerator.CURRENTLY_MANAGED.crn
val event = SentenceGenerator.CURRENTLY_MANAGED

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

assertThat(response.actualReleaseDate, equalTo(SentenceGenerator.RELEASE_2.date.toLocalDate()))
}

@Test
fun `call convictions by id and sentence status not found`() {
val crn = PersonGenerator.NO_SENTENCE.crn
val event = SentenceGenerator.NO_SENTENCE_EVENT

val response = mockMvc
.perform(get("/probation-case/$crn/convictions/${event.id}/sentenceStatus").withToken())
.andExpect(status().isNotFound)
.andReturn().response.contentAsJson<ErrorResponse>()

assertThat(response.developerMessage, equalTo("Sentence not found for crn '$crn', convictionId '${event.id}'"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ internal class ProxyIntegrationTest {
"CONVICTION_BY_ID_LICENCE_CONDITIONS": {
"convictionId": "?",
"activeOnly": true
},
"CONVICTION_BY_ID_SENTENCE_STATUS": {
"convictionId": "?",
"activeOnly": true
}
}
}
Expand All @@ -265,7 +269,7 @@ internal class ProxyIntegrationTest {
.withToken()
).andExpect(status().is2xxSuccessful).andReturn().response.contentAsJson<CompareAllReport>()

assertThat(res.totalNumberOfRequests, equalTo(13))
assertThat(res.totalNumberOfRequests, equalTo(14))
assertThat(res.totalNumberOfCrns, equalTo(2))
assertThat(res.currentPageNumber, equalTo(1))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ data class Offence(
)

data class KeyValue(
val code: String,
val code: String? = null,
val description: String
)

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

import uk.gov.justice.digital.hmpps.api.model.KeyValue
import java.time.LocalDate

data class SentenceStatus(
val sentenceId: Long,
val custodialType: KeyValue,
val sentence: KeyValue,
val mainOffence: KeyValue?,
val sentenceDate: LocalDate?,
val actualReleaseDate: LocalDate?,
val licenceExpiryDate: LocalDate?,
val pssEndDate: LocalDate? = null,
val length: Long?,
val lengthUnit: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class CommunityApiController(
}

@GetMapping("/offenders/crn/{crn}/convictions/{convictionId}/licenceConditions")
fun convictionByIdCLicenceConditions(
fun convictionByIdLicenceConditions(
request: HttpServletRequest,
@PathVariable crn: String,
@PathVariable convictionId: Long,
Expand All @@ -272,6 +272,26 @@ class CommunityApiController(
return proxy(request)
}

@GetMapping("/offenders/crn/{crn}/convictions/{convictionId}/sentenceStatus")
fun convictionByIdSentenceStatus(
request: HttpServletRequest,
@PathVariable crn: String,
@PathVariable convictionId: Long,
): Any {

sendComparisonReport(
mapOf(
"crn" to crn,
"convictionId" to convictionId
), Uri.CONVICTION_BY_ID_SENTENCE_STATUS, request
)

if (featureFlags.enabled("ccd-conviction-by-id-sentence-status")) {
return convictionResource.getConvictionSentenceStatus(crn, convictionId)
}
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 @@ -79,5 +79,11 @@ enum class Uri(
"getConvictionLicenceConditions",
listOf("crn", "convictionId"),
),
CONVICTION_BY_ID_SENTENCE_STATUS(
"/secure/offenders/crn/{crn}/convictions/{convictionId}/sentenceStatus",
"convictionResource",
"getConvictionSentenceStatus",
listOf("crn", "convictionId"),
),
DUMMY("/dummy", "dummyResource", "getDummy", listOf("crn")),
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,10 @@ class ConvictionResource(
@PathVariable crn: String,
@PathVariable convictionId: Long
) = requirementService.getLicenceConditionsForConvictionId(crn, convictionId)

@GetMapping("/{convictionId}/sentenceStatus")
fun getConvictionSentenceStatus(
@PathVariable crn: String,
@PathVariable convictionId: Long
) = convictionService.sentenceStatusFor(crn, convictionId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.Event
import java.math.BigDecimal
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime

@Entity
Expand Down Expand Up @@ -81,6 +82,25 @@ class Disposal(
val id: Long
)

@Immutable
@Entity
@Table(name = "release")
class Release(
@Id
@Column(name = "release_id")
val id: Long,

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

@Column(name = "actual_release_date")
val date: LocalDateTime,

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

interface DisposalRepository : JpaRepository<Disposal, Long> {

@Query(
Expand Down Expand Up @@ -215,6 +235,12 @@ class Custody(
@OneToMany(mappedBy = "custody")
val keyDates: List<KeyDate> = listOf(),

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

@Column(name = "pss_start_date")
val pssStartDate: LocalDate? = null,

@Id
@Column(name = "custody_id")
val id: Long
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package uk.gov.justice.digital.hmpps.integrations.delius.service
import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.api.model.KeyValue
import uk.gov.justice.digital.hmpps.api.model.conviction.*
import uk.gov.justice.digital.hmpps.exception.NotFoundException
import uk.gov.justice.digital.hmpps.integrations.delius.event.courtappearance.entity.CourtAppearance
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.*
import uk.gov.justice.digital.hmpps.integrations.delius.event.sentence.entity.*
Expand Down Expand Up @@ -39,6 +40,13 @@ class ConvictionService(
return event.toConviction()
}

fun sentenceStatusFor(crn: String, eventId: Long): SentenceStatus {
val person = personRepository.getPerson(crn)
val event = eventRepository.getByPersonAndEventNumber(person, eventId)
return event.disposal?.let(Disposal::toSentenceStatus)
?: throw NotFoundException("Sentence not found for crn '$crn', convictionId '$eventId'")
}

fun Event.toConviction(): Conviction =
Conviction(
id,
Expand Down Expand Up @@ -280,4 +288,18 @@ enum class KeyDateTypes(val code: String) {
SENTENCE_EXPIRY_DATE("SED")
}

fun Disposal.toSentenceStatus() = SentenceStatus(
sentenceId = id,
custodialType = KeyValue(
custody?.status?.code ?: "NOT_IN_CUSTODY",
custody?.status?.description ?: "Not in custody"
),
sentence = KeyValue(description = disposalType.description),
mainOffence = event.mainOffence?.let { KeyValue(description = it.offence.description) },
sentenceDate = startDate,
actualReleaseDate = custody?.releases?.maxByOrNull { it.date }?.date?.toLocalDate(),
licenceExpiryDate = custody?.pssStartDate,
length = length,
lengthUnit = "Months"

)

0 comments on commit c59ef9e

Please sign in to comment.