Skip to content

Commit

Permalink
Merge branch 'main' into gradlew-update-8.7
Browse files Browse the repository at this point in the history
  • Loading branch information
anthony-britton-moj authored Mar 25, 2024
2 parents 434f1bc + a903476 commit 35dc5e8
Show file tree
Hide file tree
Showing 19 changed files with 148 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class QueuePublisher(
private val sqsTemplate: SqsTemplate,
private val objectMapper: ObjectMapper,
@Value("\${messaging.producer.queue}") private val queue: String,
@Value("\${messaging.producer.concurrency:100}") private val limit: Int
@Value("\${messaging.producer.concurrency:75}") private val limit: Int
) : NotificationPublisher {

private val permit = Semaphore(limit)
Expand Down
6 changes: 6 additions & 0 deletions projects/feature-flags/deploy/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ generic-service:
flipt-db:
FLIPT_DB_URL: URL

allowlist:
dxw-vpn: 54.76.254.148/32
groups:
- internal
- unilink_staff

custommetrics:
enabled: true
metricsPath: /metrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ 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.Name
import uk.gov.justice.digital.hmpps.api.model.sentence.*
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson
Expand All @@ -27,7 +28,9 @@ class SentenceIntegrationTest {
.andExpect(MockMvcResultMatchers.status().isOk)
.andReturn().response.contentAsJson<SentenceOverview>()

val expected = SentenceOverview(listOf())
val expected = SentenceOverview(
Name("Caroline", "Louise", "Bloggs"), listOf()
)

assertEquals(expected, response)
}
Expand All @@ -40,9 +43,11 @@ class SentenceIntegrationTest {
.andReturn().response.contentAsJson<SentenceOverview>()

val expected = SentenceOverview(
Name("Forename", "Middle1", "Surname"),
listOf(
Sentence(
OffenceDetails(
"7654321",
Offence("Murder", 1),
LocalDate.now(),
"overview",
Expand All @@ -60,6 +65,7 @@ class SentenceIntegrationTest {
),
Sentence(
OffenceDetails(
"1234567",
Offence("Another Murder", 1),
LocalDate.now(),
"overview",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package uk.gov.justice.digital.hmpps.api.model.sentence
import java.time.LocalDate

data class OffenceDetails(
val eventNumber: String,
val offence: Offence?,
val dateOfOffence: LocalDate?,
val notes: String?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package uk.gov.justice.digital.hmpps.api.model.sentence

data class Sentence(
val offence: OffenceDetails,
val offenceDetails: OffenceDetails,
val conviction: Conviction? = null,

)
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package uk.gov.justice.digital.hmpps.api.model.sentence

import uk.gov.justice.digital.hmpps.api.model.Name

data class SentenceOverview(
val name: Name,
val sentences: List<Sentence>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.Event
interface EventSentenceRepository : JpaRepository<Event, Long> {
@Query(
"SELECT e FROM Event e " +
"JOIN Person p ON p.id = e.personId " +
"LEFT JOIN FETCH e.court c " +
"LEFT JOIN FETCH e.mainOffence m " +
"LEFT JOIN FETCH e.additionalOffences ao " +
"LEFT JOIN FETCH m.offence mo " +
"LEFT JOIN FETCH ao.offence aoo " +
"WHERE p.crn = :crn " +
"WHERE e.personId = :id " +
"AND e.active = true "
)
fun findActiveSentencesByCrn(crn: String): List<Event>
fun findActiveSentencesByPersonId(id: Long): List<Event>
}

interface CourtAppearanceRepository : JpaRepository<CourtAppearance, Long> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package uk.gov.justice.digital.hmpps.service

import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.api.model.Name
import uk.gov.justice.digital.hmpps.api.model.sentence.*
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.Event
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.PersonRepository
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.PersonSummaryEntity
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.getSummary
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.AdditionalSentenceRepository
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.CourtAppearance
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.CourtAppearanceRepository
Expand All @@ -12,20 +16,25 @@ import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.Addition
@Service
class SentenceService(
private val eventRepository: EventSentenceRepository,
private val courtApperanceRepository: CourtAppearanceRepository,
private val additionalSentenceRepository: AdditionalSentenceRepository
private val courtAppearanceRepository: CourtAppearanceRepository,
private val additionalSentenceRepository: AdditionalSentenceRepository,
private val personRepository: PersonRepository
) {
fun getMostRecentActiveEvent(crn: String): SentenceOverview {
val events = eventRepository.findActiveSentencesByCrn(crn)
return SentenceOverview(events.map {
val courtAppearance = courtApperanceRepository.getFirstCourtAppearanceByEventIdOrderByDate(it.id)
val additionalSentences = additionalSentenceRepository.getAllByEventId(it.id)
it.toSentence(courtAppearance, additionalSentences)
})
val person = personRepository.getSummary(crn)
val events = eventRepository.findActiveSentencesByPersonId(person.id)
return SentenceOverview(
name = person.toName(),
sentences = events.map {
val courtAppearance = courtAppearanceRepository.getFirstCourtAppearanceByEventIdOrderByDate(it.id)
val additionalSentences = additionalSentenceRepository.getAllByEventId(it.id)
it.toSentence(courtAppearance, additionalSentences)
})
}

fun Event.toSentence(courtAppearance: CourtAppearance?, additionalSentences: List<ExtraSentence>) = Sentence(
OffenceDetails(
eventNumber = eventNumber,
offence = mainOffence?.let { Offence(it.offence.description, it.offenceCount) },
dateOfOffence = mainOffence?.date,
notes = notes,
Expand All @@ -43,4 +52,7 @@ class SentenceService(

fun ExtraSentence.toAdditionalSentence(): AdditionalSentence =
AdditionalSentence(length, amount, notes, type.description)

fun PersonSummaryEntity.toName() =
Name(forename, secondName, surname)
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
package uk.gov.justice.digital.hmpps.service

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.*
import uk.gov.justice.digital.hmpps.api.model.Name
import uk.gov.justice.digital.hmpps.api.model.sentence.*
import uk.gov.justice.digital.hmpps.data.generator.AdditionalSentenceGenerator
import uk.gov.justice.digital.hmpps.data.generator.CourtAppearanceGenerator
import uk.gov.justice.digital.hmpps.data.generator.CourtGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.PersonRepository
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.AdditionalSentenceRepository
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.CourtAppearanceRepository
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.EventSentenceRepository
import uk.gov.justice.digital.hmpps.utils.Summary
import java.time.LocalDate

@ExtendWith(MockitoExtension::class)
Expand All @@ -29,22 +33,40 @@ class SentenceServiceTest {
@Mock
lateinit var additionalSentenceRepository: AdditionalSentenceRepository

@Mock
lateinit var personRepository: PersonRepository

@InjectMocks
lateinit var service: SentenceService

private lateinit var personSummary: Summary

@BeforeEach
fun setup() {
personSummary = Summary(
id = 1,
forename = "TestName",
surname = "TestSurname", crn = "CRN", pnc = "PNC", dateOfBirth = LocalDate.now().minusYears(50)
)
}

@Test
fun `no active sentences`() {

whenever(eventRepository.findActiveSentencesByCrn(PersonGenerator.OVERVIEW.crn)).thenReturn(
whenever(personRepository.findSummary(PersonGenerator.OVERVIEW.crn)).thenReturn(personSummary)
whenever(eventRepository.findActiveSentencesByPersonId(personSummary.id)).thenReturn(
listOf()
)

val expected = SentenceOverview(Name("TestName", surname = "TestSurname"), listOf())
val response = service.getMostRecentActiveEvent(PersonGenerator.OVERVIEW.crn)

assertEquals(SentenceOverview(listOf()), response)
verify(eventRepository, times(1)).findActiveSentencesByCrn(PersonGenerator.OVERVIEW.crn)
assertEquals(expected, response)
verify(personRepository, times(1)).findSummary(PersonGenerator.OVERVIEW.crn)
verify(eventRepository, times(1)).findActiveSentencesByPersonId(personSummary.id)

verifyNoMoreInteractions(eventRepository)
verifyNoMoreInteractions(personRepository)
verifyNoInteractions(courtAppearanceRepository)
verifyNoInteractions(additionalSentenceRepository)
}
Expand All @@ -63,7 +85,8 @@ class SentenceServiceTest {
additionalOffences = listOf(PersonGenerator.ADDITIONAL_OFFENCE_1)
)

whenever(eventRepository.findActiveSentencesByCrn(PersonGenerator.OVERVIEW.crn)).thenReturn(
whenever(personRepository.findSummary(PersonGenerator.OVERVIEW.crn)).thenReturn(personSummary)
whenever(eventRepository.findActiveSentencesByPersonId(personSummary.id)).thenReturn(
listOf(
event
)
Expand All @@ -81,9 +104,11 @@ class SentenceServiceTest {
val response = service.getMostRecentActiveEvent(PersonGenerator.OVERVIEW.crn)

val expected = SentenceOverview(
Name("TestName", surname = "TestSurname"),
listOf(
Sentence(
OffenceDetails(
"123457",
Offence("Murder", 1),
LocalDate.now(),
"overview",
Expand All @@ -105,10 +130,12 @@ class SentenceServiceTest {
)

assertEquals(expected, response)
verify(eventRepository, times(1)).findActiveSentencesByCrn(PersonGenerator.OVERVIEW.crn)
verify(eventRepository, times(1)).findActiveSentencesByPersonId(personSummary.id)
verify(additionalSentenceRepository, times(1)).getAllByEventId(event.id)
verify(courtAppearanceRepository, times(1)).getFirstCourtAppearanceByEventIdOrderByDate(event.id)

verifyNoMoreInteractions(eventRepository)
verifyNoMoreInteractions(additionalSentenceRepository)
verifyNoMoreInteractions(courtAppearanceRepository)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package uk.gov.justice.digital.hmpps

import com.github.tomakehurst.wiremock.WireMockServer
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.mockito.Mockito.verify
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
Expand Down Expand Up @@ -35,7 +32,7 @@ internal class MergeIntegrationTest {

verify(telemetryService).trackEvent(
"MergeResultSuccess", mapOf(
"reason" to "Replaced NOMS numbers for 1 records",
"reason" to "Replaced NOMS numbers for 1 record",
"existingNomsNumber" to "A0007AA",
"updatedNomsNumber" to "B0007BB",
"matches" to """[{"crn":"A000007"}]""",
Expand All @@ -45,14 +42,19 @@ internal class MergeIntegrationTest {
}

@Test
fun `merge fails if the new noms number is already assigned`() {
fun `logs event if the new noms number is already assigned`() {
val event = prepEvent("prisoner-merged", wireMockServer.port()).apply {
message.additionalInformation["nomsNumber"] = PERSON_WITH_NOMS.nomsNumber!!
}

val exception = assertThrows<IllegalArgumentException> { handler.handle(event) }
handler.handle(event)

assertThat(exception.message, equalTo("NOMS number E1234XS is already assigned to A000001"))
verify(telemetryService).trackEvent(
"MergeResultIgnored", mapOf(
"reason" to "NOMS number E1234XS is already assigned to A000001",
"dryRun" to "false",
)
)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@ class MatchWriter(
private val orderManagerRepository: OrderManagerRepository,
) {
@Transactional
fun update(prisonIdentifiers: PrisonIdentifiers, person: Person, custody: Custody? = null) {
if (person.nomsNumber != prisonIdentifiers.prisonerNumber) {
fun update(prisonIdentifiers: PrisonIdentifiers, person: Person, custody: Custody? = null): Boolean {
val nomsNumberChanged = person.nomsNumber != prisonIdentifiers.prisonerNumber
if (nomsNumberChanged) {
removeDuplicateNomsNumbers(person, prisonIdentifiers.prisonerNumber)
updateNomsNumber(person, prisonIdentifiers.prisonerNumber)
}
if (custody != null && custody.prisonerNumber != prisonIdentifiers.prisonerNumber) {
val bookingNumberChanged = custody?.prisonerNumber != prisonIdentifiers.bookingNumber
if (bookingNumberChanged && custody != null) {
custody.prisonerNumber = prisonIdentifiers.bookingNumber
custodyRepository.save(custody)
person.mostRecentPrisonerNumber = prisonIdentifiers.bookingNumber
personRepository.save(person)
person.rebuildPrisonerLinks()
custody.createContactForChange()
}
return nomsNumberChanged || bookingNumberChanged
}

private fun removeDuplicateNomsNumbers(person: Person, nomsNumber: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class PrisonMatchingService(
val matchResult = findMatchingPrisonRecord(crn)
if (!dryRun && matchResult is Success) {
with(matchResult) {
matchWriter.update(prisonIdentifiers, person, custody)
notifier.identifierAdded(crn, prisonIdentifiers)
val changes = matchWriter.update(prisonIdentifiers, person, custody)
if (changes) notifier.identifierAdded(person.crn, prisonIdentifiers)
}
}
return matchResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ class ProbationMatchingService(
val matchResult = findMatchingProbationRecord(nomsNumber)
if (!dryRun && matchResult is Success) {
with(matchResult) {
matchWriter.update(prisonIdentifiers, person, custody)
notifier.identifierAdded(person.crn, prisonIdentifiers)
val changes = matchWriter.update(prisonIdentifiers, person, custody)
if (changes) notifier.identifierAdded(person.crn, prisonIdentifiers)
}
}
return matchResult
}

fun replaceIdentifiers(oldNomsNumber: String, newNomsNumber: String, dryRun: Boolean): MergeResult {
personRepository.findAllByNomsNumber(newNomsNumber).joinToString { it.crn }.takeIf { it.isNotEmpty() }?.let {
throw IllegalArgumentException("NOMS number $newNomsNumber is already assigned to $it")
return MergeResult.Ignored("NOMS number $newNomsNumber is already assigned to $it")
}

val existing = personRepository.findAllByNomsNumber(oldNomsNumber)
Expand All @@ -43,12 +43,12 @@ class ProbationMatchingService(
}
if (!dryRun) {
existing.forEach {
matchWriter.update(PrisonIdentifiers(newNomsNumber), it)
notifier.identifierUpdated(it.crn, newNomsNumber, oldNomsNumber)
val changes = matchWriter.update(PrisonIdentifiers(newNomsNumber), it)
if (changes) notifier.identifierUpdated(it.crn, newNomsNumber, oldNomsNumber)
}
}
return MergeResult.Success(
"Replaced NOMS numbers for ${existing.size} records", mapOf(
"Replaced NOMS numbers for ${existing.size} record${if (existing.size == 1) "" else "s"}", mapOf(
"existingNomsNumber" to oldNomsNumber,
"updatedNomsNumber" to newNomsNumber,
"matches" to objectMapper.writeValueAsString(existing.map { mapOf("crn" to it.crn) })
Expand Down
Loading

0 comments on commit 35dc5e8

Please sign in to comment.