diff --git a/projects/prison-identifier-and-delius/deploy/database/access.yml b/projects/prison-identifier-and-delius/deploy/database/access.yml index 8715aba01d..97f18236b6 100644 --- a/projects/prison-identifier-and-delius/deploy/database/access.yml +++ b/projects/prison-identifier-and-delius/deploy/database/access.yml @@ -4,6 +4,7 @@ database: password_key: /prison-identifier-and-delius/db-password tables: - additional_identifier + - contact - custody - offender - offender_prisoner diff --git a/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index b04620c859..5dfdf0c497 100644 --- a/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -11,6 +11,7 @@ import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.generateCustody import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.generateDisposal import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.generateEvent +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.generateOrderManager import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator import uk.gov.justice.digital.hmpps.data.generator.UserGenerator import uk.gov.justice.digital.hmpps.user.AuditUserRepository @@ -33,22 +34,27 @@ class DataLoader( val personWithNomsEvent = generateEvent(PersonGenerator.PERSON_WITH_NOMS) val personWithNomsDisposal = generateDisposal(LocalDate.of(2022, 11, 11), personWithNomsEvent) val personWithNomsCustody = generateCustody(personWithNomsDisposal) + val personWithNomsOrderManager = generateOrderManager(personWithNomsEvent) val personWithNoNomsNumberEvent = generateEvent(PersonGenerator.PERSON_WITH_NO_NOMS) val personWithNoNomsNumberDisposal = generateDisposal(LocalDate.of(2022, 12, 12), personWithNoNomsNumberEvent) val personWithNoNomsNumberCustody = generateCustody(personWithNoNomsNumberDisposal) + val personWithNoNomsNumberOrderManager = generateOrderManager(personWithNoNomsNumberEvent) val personWithMultiMatchEvent = generateEvent(PersonGenerator.PERSON_WITH_MULTI_MATCH) val personWithMultiMatchDisposal = generateDisposal(LocalDate.of(2022, 12, 12), personWithMultiMatchEvent) val personWithMultiMatchCustody = generateCustody(personWithMultiMatchDisposal) + val personWithMultiMatchOrderManager = generateOrderManager(personWithMultiMatchEvent) val personWithNoMatchEvent = generateEvent(PersonGenerator.PERSON_WITH_NO_MATCH) val personWithNoMatchDisposal = generateDisposal(LocalDate.of(2022, 12, 12), personWithNoMatchEvent) val personWithNoMatchCustody = generateCustody(personWithNoMatchDisposal) + val personWithNoMatchOrderManager = generateOrderManager(personWithNoMatchEvent) val personWithNomsInDeliusEvent = generateEvent(PersonGenerator.PERSON_WITH_NOMS_IN_DELIUS) val personWithNomsInDeliusDisposal = generateDisposal(LocalDate.of(2022, 12, 12), personWithNomsInDeliusEvent) val personWithNomsInDeliusCustody = generateCustody(personWithNomsInDeliusDisposal) + val personWithNomsInDeliusOrderManager = generateOrderManager(personWithNomsInDeliusEvent) em.saveAll( ReferenceDataGenerator.GENDER_SET, @@ -58,6 +64,7 @@ class DataLoader( ReferenceDataGenerator.ADDITIONAL_IDENTIFIER_TYPE_SET, ReferenceDataGenerator.DUPLICATE_NOMS, ReferenceDataGenerator.FORMER_NOMS, + ReferenceDataGenerator.CONTACT_TYPE, PersonGenerator.PERSON_WITH_NOMS, PersonGenerator.PERSON_WITH_NO_NOMS, PersonGenerator.PERSON_WITH_MULTI_MATCH, @@ -68,19 +75,23 @@ class DataLoader( personWithNomsEvent, personWithNomsDisposal, personWithNomsCustody, + personWithNomsOrderManager, personWithNoNomsNumberEvent, personWithNoNomsNumberDisposal, personWithNoNomsNumberCustody, + personWithNoNomsNumberOrderManager, personWithMultiMatchEvent, personWithMultiMatchDisposal, personWithMultiMatchCustody, + personWithMultiMatchOrderManager, personWithNoMatchEvent, personWithNoMatchDisposal, personWithNoMatchCustody, + personWithNoMatchOrderManager, personWithNomsInDeliusEvent, personWithNomsInDeliusDisposal, - personWithNomsInDeliusCustody - + personWithNomsInDeliusCustody, + personWithNomsInDeliusOrderManager, ) } diff --git a/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt index 4708cbfef4..023fe9bb26 100644 --- a/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt +++ b/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -43,6 +43,9 @@ object PersonGenerator { fun generateEvent(person: Person, id: Long = IdGenerator.getAndIncrement()) = Event(id = id, person = person, active = true, softDeleted = false) + fun generateOrderManager(event: Event, id: Long = IdGenerator.getAndIncrement()) = + OrderManager(id = id, eventId = event.id, staffId = 9999, teamId = 9999, providerId = 9999) + fun generateDisposal(startDate: LocalDate, event: Event, id: Long = IdGenerator.getAndIncrement()) = Disposal(id, startDate, event, active = true, softDeleted = false) diff --git a/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt b/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt index df276d55ed..aa548ffbb5 100644 --- a/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt +++ b/projects/prison-identifier-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt @@ -1,5 +1,6 @@ package uk.gov.justice.digital.hmpps.data.generator +import uk.gov.justice.digital.hmpps.entity.ContactType import uk.gov.justice.digital.hmpps.entity.ReferenceData import uk.gov.justice.digital.hmpps.entity.ReferenceDataSet @@ -14,6 +15,8 @@ object ReferenceDataGenerator { val DUPLICATE_NOMS = generateIdentifierType("DNOMS") val FORMER_NOMS = generateIdentifierType("XNOMS") + val CONTACT_TYPE = generateContactType("EDSS") + fun generateGender(code: String, id: Long = IdGenerator.getAndIncrement()) = ReferenceData(id, code, GENDER_SET) fun generateCustodyStatus(code: String, id: Long = IdGenerator.getAndIncrement()) = ReferenceData(id, code, CUSTODY_STATUS_SET) @@ -22,4 +25,6 @@ object ReferenceDataGenerator { ReferenceData(id, code, ADDITIONAL_IDENTIFIER_TYPE_SET) fun generateReferenceDataSet(name: String, id: Long = IdGenerator.getAndIncrement()) = ReferenceDataSet(id, name) + + fun generateContactType(code: String, id: Long = IdGenerator.getAndIncrement()) = ContactType(id, code) } \ No newline at end of file diff --git a/projects/prison-identifier-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PrisonMatchingIntegrationTest.kt b/projects/prison-identifier-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PrisonMatchingIntegrationTest.kt index 4ed3ea98ff..b73583ad9d 100644 --- a/projects/prison-identifier-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PrisonMatchingIntegrationTest.kt +++ b/projects/prison-identifier-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PrisonMatchingIntegrationTest.kt @@ -7,10 +7,7 @@ import org.junit.jupiter.api.MethodOrderer import org.junit.jupiter.api.Order import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestMethodOrder -import org.mockito.kotlin.any -import org.mockito.kotlin.never -import org.mockito.kotlin.timeout -import org.mockito.kotlin.verify +import org.mockito.kotlin.* import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest @@ -23,10 +20,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.PERSON_WITH_DUPLICATE_NOMS -import uk.gov.justice.digital.hmpps.entity.AdditionalIdentifierRepository -import uk.gov.justice.digital.hmpps.entity.CustodyRepository -import uk.gov.justice.digital.hmpps.entity.PersonRepository -import uk.gov.justice.digital.hmpps.entity.getByCrn +import uk.gov.justice.digital.hmpps.entity.* import uk.gov.justice.digital.hmpps.telemetry.TelemetryService import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withJson import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken @@ -48,6 +42,9 @@ internal class PrisonMatchingIntegrationTest { @SpyBean lateinit var additionalIdentifierRepository: AdditionalIdentifierRepository + @SpyBean + lateinit var contactRepository: ContactRepository + @MockBean lateinit var telemetryService: TelemetryService @@ -190,6 +187,12 @@ internal class PrisonMatchingIntegrationTest { assertThat(person.nomsNumber, equalTo("G5541WW")) val custody = custodyRepository.findByIdOrNull(custodyId)!! assertThat(custody.prisonerNumber, equalTo("13831A")) + verify(contactRepository).save(check { + assertThat(it.personId, equalTo(person.id)) + assertThat(it.eventId, equalTo(custody.disposal.event.id)) + assertThat(it.type.code, equalTo("EDSS")) + assertThat(it.notes, equalTo("Prison Number: 13831A" + System.lineSeparator())) + }) } @Test diff --git a/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Contact.kt b/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Contact.kt new file mode 100644 index 0000000000..c1c826533e --- /dev/null +++ b/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Contact.kt @@ -0,0 +1,95 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.springframework.data.annotation.CreatedBy +import org.springframework.data.annotation.CreatedDate +import org.springframework.data.annotation.LastModifiedBy +import org.springframework.data.annotation.LastModifiedDate +import org.springframework.data.jpa.domain.support.AuditingEntityListener +import org.springframework.data.jpa.repository.JpaRepository +import uk.gov.justice.digital.hmpps.exception.NotFoundException +import java.time.ZonedDateTime + +@Entity +@EntityListeners(AuditingEntityListener::class) +@SequenceGenerator(name = "contact_id_seq", sequenceName = "contact_id_seq", allocationSize = 1) +class Contact( + @Id + @Column(name = "contact_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "contact_id_seq") + val id: Long = 0, + + @Column(name = "offender_id") + val personId: Long, + + @Column + val eventId: Long, + + @ManyToOne + @JoinColumn(name = "contact_type_id") + val type: ContactType, + + @Lob + val notes: String, + + @Column(name = "probation_area_id") + val providerId: Long, + + @Column(updatable = false) + val teamId: Long, + + @Column(updatable = false) + val staffId: Long, + + @Column(name = "contact_date") + val date: ZonedDateTime = ZonedDateTime.now(), + + @Column(name = "contact_start_time") + val startTime: ZonedDateTime = ZonedDateTime.now(), + + @Column(name = "soft_deleted", columnDefinition = "number") + val softDeleted: Boolean = false, + + @Version + @Column(name = "row_version") + val version: Long = 0, + + @Column + val partitionAreaId: Long = 0, + + @CreatedDate + var createdDatetime: ZonedDateTime = ZonedDateTime.now(), + + @CreatedBy + var createdByUserId: Long = 0, + + @LastModifiedBy + var lastUpdatedUserId: Long = 0, + + @LastModifiedDate + var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now() +) + +@Entity +@Immutable +@Table(name = "r_contact_type") +class ContactType( + @Id + @Column(name = "contact_type_id") + val id: Long, + + val code: String +) { + companion object { + const val CUSTODY_UPDATE = "EDSS" + } +} + +interface ContactRepository : JpaRepository +interface ContactTypeRepository : JpaRepository { + fun findByCode(code: String): ContactType? +} + +fun ContactTypeRepository.getByCode(code: String): ContactType = + findByCode(code) ?: throw NotFoundException("ContactType", "code", code) \ No newline at end of file diff --git a/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/OrderManager.kt b/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/OrderManager.kt new file mode 100644 index 0000000000..203b4d684b --- /dev/null +++ b/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/OrderManager.kt @@ -0,0 +1,43 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.SQLRestriction +import org.springframework.data.jpa.repository.JpaRepository +import uk.gov.justice.digital.hmpps.exception.NotFoundException + +@Entity +@Immutable +@SQLRestriction("soft_deleted = 0 and active_flag = 1") +class OrderManager( + @Id + @Column(name = "order_manager_id", nullable = false) + val id: Long, + + @Column + val eventId: Long, + + @Column(name = "allocation_staff_id") + val staffId: Long, + + @Column(name = "allocation_team_id") + val teamId: Long, + + @Column(name = "probation_area_id") + val providerId: Long, + + @Column(name = "active_flag", columnDefinition = "number") + val active: Boolean = true, + + @Column(columnDefinition = "number", nullable = false) + val softDeleted: Boolean = false +) + +interface OrderManagerRepository : JpaRepository { + fun findByEventId(eventId: Long): OrderManager? +} + +fun OrderManagerRepository.getByEventId(eventId: Long): OrderManager = + findByEventId(eventId) ?: throw NotFoundException("OrderManager", "eventId", eventId) diff --git a/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/MatchWriter.kt b/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/MatchWriter.kt index c3292d5884..72059fd205 100644 --- a/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/MatchWriter.kt +++ b/projects/prison-identifier-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/MatchWriter.kt @@ -12,6 +12,9 @@ class MatchWriter( private val additionalIdentifierRepository: AdditionalIdentifierRepository, private val referenceDataRepository: ReferenceDataRepository, private val prisonerRepository: PrisonerRepository, + private val contactRepository: ContactRepository, + private val contactTypeRepository: ContactTypeRepository, + private val orderManagerRepository: OrderManagerRepository, ) { @Transactional fun update(prisonIdentifiers: PrisonIdentifiers, person: Person, custody: Custody? = null) { @@ -25,6 +28,7 @@ class MatchWriter( person.mostRecentPrisonerNumber = prisonIdentifiers.bookingNumber personRepository.save(person) person.rebuildPrisonerLinks() + custody.createContactForChange() } } @@ -70,4 +74,19 @@ class MatchWriter( .map { prisonerNumber -> Prisoner(PrisonerId(id, prisonerNumber)) } .let(prisonerRepository::saveAll) } + + private fun Custody.createContactForChange() { + val orderManager = orderManagerRepository.getByEventId(disposal.event.id) + contactRepository.save( + Contact( + personId = disposal.event.person.id, + eventId = disposal.event.id, + type = contactTypeRepository.getByCode(ContactType.CUSTODY_UPDATE), + notes = "Prison Number: $prisonerNumber" + System.lineSeparator(), + providerId = orderManager.providerId, + teamId = orderManager.teamId, + staffId = orderManager.staffId + ) + ) + } } \ No newline at end of file