Skip to content

Commit

Permalink
Man 28 sentence license condition long notes (#4326)
Browse files Browse the repository at this point in the history
* MAN-28 - add id attribute to lc note

* MAN-28 - do not include lc notes if there are not any

* MAN-28 - add id to LicenceCondition data class

* MAN-28 - add new api to get individual note

* MAN-28 - update api so that single note call is not truncated

* MAN-28 - update api so that empty list is returned where no lc note is returned from db

* MAN-28 - update api return spec

* MAN-28 - update api

* Formatting changes

---------

Co-authored-by: probation-integration-bot[bot] <177347787+probation-integration-bot[bot]@users.noreply.github.com>
  • Loading branch information
1 parent 919536f commit 4ac4ff5
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import java.time.LocalDate

object LicenceConditionGenerator {

val LONG_NOTE = """
Licence Condition created automatically from the Create and Vary a licence system of\nAllow person(s) as designated by your supervising officer to install an electronic monitoring tag on you and access to install any associated equipment in your property, and for the purpose of ensuring that equipment is functioning correctly. You must not damage or tamper with these devices and ensure that the tag is charged, and report to your supervising officer and the EM provider immediately if the tag or the associated equipment are not working correctly. This will be for the purpose of monitoring your alcohol abstinence licence condition(s) unless otherwise authorised by your supervising officer. Licence Condition created automatically from the Create and Vary a licence system of\nAllow person(s) as designated by your supervising officer to install an electronic monitoring tag on you and access to install any associated equipment in your property, and for the purpose of ensuring that equipment is functioning correctly. You must not damage or tamper with these devices and ensure that the tag is charged, and report to your supervising officer and the EM provider immediately if the tag or the associated equipment are not working correctly. This will be for the purpose of monitoring your alcohol abstinence licence condition(s) unless otherwise authorised by your supervising officer.Licence Condition created automatically from the Create and Vary a licence system of\nAllow person(s) as desi123456
""".trimIndent()

val LIC_COND_MAIN_CAT = LicenceConditionMainCategory(
IdGenerator.getAndIncrement(),
"LicMain",
Expand Down Expand Up @@ -39,7 +43,7 @@ object LicenceConditionGenerator {
LocalDate.now(),
"""
Comment added by CVL Service on 22/04/2024 at 10:00
Licence Condition created automatically from the Create and Vary a licence system of\nAllow person(s) as designated by your supervising officer to install an electronic monitoring tag on you and access to install any associated equipment in your property, and for the purpose of ensuring that equipment is functioning correctly. You must not damage or tamper with these devices and ensure that the tag is charged, and report to your supervising officer and the EM provider immediately if the tag or the associated equipment are not working correctly. This will be for the purpose of monitoring your alcohol abstinence licence condition(s) unless otherwise authorised by your supervising officer. Licence Condition created automatically from the Create and Vary a licence system of\nAllow person(s) as designated by your supervising officer to install an electronic monitoring tag on you and access to install any associated equipment in your property, and for the purpose of ensuring that equipment is functioning correctly. You must not damage or tamper with these devices and ensure that the tag is charged, and report to your supervising officer and the EM provider immediately if the tag or the associated equipment are not working correctly. This will be for the purpose of monitoring your alcohol abstinence licence condition(s) unless otherwise authorised by your supervising officer.Licence Condition created automatically from the Create and Vary a licence system of\nAllow person(s) as desi123456
$LONG_NOTE
---------------------------------------------------------
Comment added by Joe Root on 23/04/2024 at 13:45
You must not drink any alcohol until Wednesday 7th August 2024 unless your
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
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.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
import uk.gov.justice.digital.hmpps.api.model.sentence.LicenceConditionNote
import uk.gov.justice.digital.hmpps.api.model.sentence.LicenceConditionNoteDetail
import uk.gov.justice.digital.hmpps.data.generator.LicenceConditionGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.service.toSummary
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken
import java.time.LocalDate
import uk.gov.justice.digital.hmpps.api.model.sentence.LicenceCondition
import uk.gov.justice.digital.hmpps.data.generator.LicenceConditionGenerator.LC_WITH_NOTES
import uk.gov.justice.digital.hmpps.data.generator.LicenceConditionGenerator.LIC_COND_MAIN_CAT
import uk.gov.justice.digital.hmpps.data.generator.LicenceConditionGenerator.LIC_COND_SUB_CAT

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class LicenceConditionIntegrationTest {
@Autowired
lateinit var mockMvc: MockMvc

@Test
fun `unauthorized status returned`() {
mockMvc
.perform(MockMvcRequestBuilders.get("/sentence/${PersonGenerator.OVERVIEW.crn}/licence-condition/1/note/1"))
.andExpect(MockMvcResultMatchers.status().isUnauthorized)
}

@Test
fun `licence condition not found`() {
val response = mockMvc
.perform(
MockMvcRequestBuilders.get("/sentence/${PersonGenerator.OVERVIEW.crn}/licence-condition/1/note/6")
.withToken()
)
.andExpect(MockMvcResultMatchers.status().isOk)
.andReturn().response.contentAsJson<LicenceConditionNoteDetail>()

val expected = LicenceConditionNoteDetail(PersonGenerator.OVERVIEW.toSummary())

assertEquals(expected, response)
}

@Test
fun `note not found`() {
val response = mockMvc
.perform(
MockMvcRequestBuilders.get("/sentence/${PersonGenerator.OVERVIEW.crn}/licence-condition/${LC_WITH_NOTES.id}/note/7")
.withToken()
)
.andExpect(MockMvcResultMatchers.status().isOk)
.andReturn().response.contentAsJson<LicenceConditionNoteDetail>()

val expected = LicenceConditionNoteDetail(
PersonGenerator.OVERVIEW.toSummary(),
LicenceCondition(
LC_WITH_NOTES.id,
LIC_COND_MAIN_CAT.description,
LIC_COND_SUB_CAT.description,
LocalDate.now().minusDays(7),
LocalDate.now()
)
)

assertEquals(expected, response)
}

@Test
fun `get note for licence condition`() {
val response = mockMvc
.perform(
MockMvcRequestBuilders.get("/sentence/${PersonGenerator.OVERVIEW.crn}/licence-condition/${LC_WITH_NOTES.id}/note/0")
.withToken()
)
.andExpect(MockMvcResultMatchers.status().isOk)
.andReturn().response.contentAsJson<LicenceConditionNoteDetail>()

val expected = LicenceConditionNoteDetail(
PersonGenerator.OVERVIEW.toSummary(),
LicenceCondition(
LC_WITH_NOTES.id,
LIC_COND_MAIN_CAT.description,
LIC_COND_SUB_CAT.description,
LocalDate.now().minusDays(7),
LocalDate.now(),
note = LicenceConditionNote(
0,
"CVL Service",
LocalDate.of(2024, 4, 22),
"""
${LicenceConditionGenerator.LONG_NOTE}
""".trimIndent() + System.lineSeparator()
)
)
)

assertEquals(expected, response)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import uk.gov.justice.digital.hmpps.api.model.overview.Rar
import uk.gov.justice.digital.hmpps.api.model.sentence.*
import uk.gov.justice.digital.hmpps.data.generator.CourtReportGenerator.COURT_DOCUMENT
import uk.gov.justice.digital.hmpps.data.generator.CourtReportGenerator.EVENT_DOCUMENT
import uk.gov.justice.digital.hmpps.data.generator.LicenceConditionGenerator.LC_WITHOUT_NOTES
import uk.gov.justice.digital.hmpps.data.generator.LicenceConditionGenerator.LC_WITH_NOTES
import uk.gov.justice.digital.hmpps.data.generator.LicenceConditionGenerator.LC_WITH_NOTES_WITHOUT_ADDED_BY
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.data.generator.personalDetails.PersonDetailsGenerator
import uk.gov.justice.digital.hmpps.service.toSummary
Expand Down Expand Up @@ -120,12 +123,14 @@ class SentenceIntegrationTest {
"3 minutes completed (of 12 hours)",
listOf(
LicenceCondition(
LC_WITH_NOTES.id,
LIC_COND_MAIN_CAT.description,
LIC_COND_SUB_CAT.description,
LocalDate.now().minusDays(7),
LocalDate.now(),
listOf(
LicenceConditionNote(
0,
"CVL Service",
LocalDate.of(2024, 4, 22),
"""
Expand All @@ -134,6 +139,7 @@ class SentenceIntegrationTest {
true
),
LicenceConditionNote(
1,
"Joe Root",
LocalDate.of(2024, 4, 23),
"""
Expand All @@ -146,16 +152,20 @@ class SentenceIntegrationTest {
)
),
LicenceCondition(
LC_WITHOUT_NOTES.id,
LIC_COND_MAIN_CAT.description,
imposedReleasedDate = LocalDate.now().minusDays(14),
notes = listOf()
),
LicenceCondition(
LC_WITH_NOTES_WITHOUT_ADDED_BY.id,
LIC_COND_MAIN_CAT.description,
LIC_COND_SUB_CAT.description,
LocalDate.now().minusDays(7),
LocalDate.now(),
listOf(
LicenceConditionNote(
0,
note = "He shall not contact or associate with Peter Jones without the prior approval of the supervising officer;",
hasNotesBeenTruncated = false
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import uk.gov.justice.digital.hmpps.service.ContactService
import uk.gov.justice.digital.hmpps.service.OffenceService
import uk.gov.justice.digital.hmpps.service.OrdersService
import uk.gov.justice.digital.hmpps.service.SentenceService
import uk.gov.justice.digital.hmpps.service.*

@RestController
@Tag(name = "Sentence")
Expand All @@ -20,7 +17,8 @@ class SentenceController(
private val sentenceService: SentenceService,
private val ordersService: OrdersService,
private val offenceService: OffenceService,
private val contactService: ContactService
private val contactService: ContactService,
private val licenceConditionService: LicenceConditionService
) {

@GetMapping
Expand All @@ -39,4 +37,12 @@ class SentenceController(
@GetMapping("/contacts")
@Operation(summary = "Display contacts")
fun getContacts(@PathVariable crn: String) = contactService.getContacts(crn)

@GetMapping("/licence-condition/{licenceConditionId}/note/{noteId}")
@Operation(summary = "Get licence condition note")
fun getLicenceConditionNote(
@PathVariable crn: String,
@PathVariable licenceConditionId: Long,
@PathVariable noteId: Int
) = licenceConditionService.getLicenceConditionNote(crn, licenceConditionId, noteId)
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
package uk.gov.justice.digital.hmpps.api.model.sentence

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

data class LicenceCondition(
val id: Long,
val mainDescription: String,
val subTypeDescription: String? = null,
val imposedReleasedDate: LocalDate,
val actualStartDate: LocalDate? = null,
val notes: List<LicenceConditionNote> = listOf()
val notes: List<LicenceConditionNote>? = null,
val note: LicenceConditionNote? = null
)

data class LicenceConditionNote(
val id: Int,
val createdBy: String? = null,
val createdByDate: LocalDate? = null,
val note: String,
val hasNotesBeenTruncated: Boolean? = null
)

data class LicenceConditionNoteDetail(
val personSummary: PersonSummary,
val licenceCondition: LicenceCondition? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ class LicenceCondition(
)

interface LicenceConditionRepository : JpaRepository<LicenceCondition, Long> {

fun findAllByDisposalId(disposalId: Long): List<LicenceCondition>
}

fun LicenceConditionRepository.getByLicenceConditionId(id: Long) = findById(id)

@Immutable
@Table(name = "r_lic_cond_type_main_cat")
@Entity
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package uk.gov.justice.digital.hmpps.service

import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.api.model.sentence.LicenceCondition
import uk.gov.justice.digital.hmpps.api.model.sentence.LicenceConditionNote
import uk.gov.justice.digital.hmpps.api.model.sentence.LicenceConditionNoteDetail
import uk.gov.justice.digital.hmpps.datetime.DeliusDateFormatter
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.PersonRepository
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.getPerson
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.LicenceConditionRepository
import java.time.LocalDate
import kotlin.jvm.optionals.getOrNull
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.LicenceCondition as EntityLicenceCondition

@Service
class LicenceConditionService(
private val personRepository: PersonRepository,
private val licenceConditionRepository: LicenceConditionRepository
) {

fun getLicenceConditionNote(crn: String, licenceConditionId: Long, noteId: Int): LicenceConditionNoteDetail {
val person = personRepository.getPerson(crn)

val licenceCondition = licenceConditionRepository.findById(licenceConditionId).getOrNull()

return LicenceConditionNoteDetail(
person.toSummary(),
licenceCondition?.toLicenceConditionSingleNote(noteId, false)
)
}
}

fun EntityLicenceCondition.toLicenceCondition() =
LicenceCondition(
id,
mainCategory.description,
subCategory?.description,
imposedReleasedDate,
actualStartDate,
toLicenceConditionNote(true)
)

fun EntityLicenceCondition.toLicenceConditionSingleNote(noteId: Int, truncateNote: Boolean) =
LicenceCondition(
id,
mainCategory.description,
subCategory?.description,
imposedReleasedDate,
actualStartDate,
note = toLicenceConditionNote(truncateNote).elementAtOrNull(noteId)
)

fun EntityLicenceCondition.toLicenceConditionNote(truncateNote: Boolean): List<LicenceConditionNote> {

return notes?.let {
val splitParam = "---------------------------------------------------------" + System.lineSeparator()
notes.split(splitParam).mapIndexed { index, note ->
val matchResult = Regex(
"^Comment added by (.+?) on (\\d{2}/\\d{2}/\\d{4}) at \\d{2}:\\d{2}"
+ System.lineSeparator()
).find(note)
val commentLine = matchResult?.value
val commentText = commentLine?.let { note.removePrefix(commentLine) } ?: note

val userCreatedBy = matchResult?.groupValues?.get(1)
val dateCreatedBy = matchResult?.groupValues?.get(2)
?.let { LocalDate.parse(it, DeliusDateFormatter) }


LicenceConditionNote(
index,
userCreatedBy,
dateCreatedBy,
when (truncateNote) {
true -> commentText.removeSuffix(System.lineSeparator()).chunked(1500)[0]
else -> commentText
},
when (truncateNote) {
true -> note.length > 1500
else -> null
}
)
}
} ?: listOf()
}
Loading

0 comments on commit 4ac4ff5

Please sign in to comment.