Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PI-1585 Added address processing #2457

Merged
merged 3 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions projects/cas3-and-delius/deploy/database/access.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ database:
tables:
- audited_interaction
- contact
- offender_address

audit:
username: Cas3AndDelius
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.ApplicationListener
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
import uk.gov.justice.digital.hmpps.data.generator.AddressRDGenerator
import uk.gov.justice.digital.hmpps.data.generator.BusinessInteractionGenerator
import uk.gov.justice.digital.hmpps.data.generator.ContactTypeGenerator
import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.data.generator.UserGenerator
import uk.gov.justice.digital.hmpps.user.AuditUserRepository
Expand All @@ -28,6 +30,11 @@ class DataLoader(
@Transactional
override fun onApplicationEvent(are: ApplicationReadyEvent) {
em.saveAll(
DatasetGenerator.ADDRESS_STATUS,
DatasetGenerator.ADDRESS_TYPE,
AddressRDGenerator.CAS3_ADDRESS_TYPE,
AddressRDGenerator.MAIN_ADDRESS_STATUS,
AddressRDGenerator.PREV_ADDRESS_STATUS,
BusinessInteractionGenerator.UPDATE_CONTACT,
ContactTypeGenerator.EARS_CONTACT_TYPE,
ContactTypeGenerator.EACA_CONTACT_TYPE,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package uk.gov.justice.digital.hmpps.data.generator

import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData

object AddressRDGenerator {
val CAS3_ADDRESS_TYPE = generate("A17", DatasetGenerator.ADDRESS_TYPE.id, "Approved Premises")
val MAIN_ADDRESS_STATUS = generate("M", DatasetGenerator.ADDRESS_STATUS.id, "Main Address")
val PREV_ADDRESS_STATUS = generate("P", DatasetGenerator.ADDRESS_STATUS.id, "Previous Address")

fun generate(
code: String,
datasetId: Long,
description: String = "Description of $code",
id: Long = IdGenerator.getAndIncrement()
) = ReferenceData(id, code, description, datasetId)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package uk.gov.justice.digital.hmpps.data.generator

import uk.gov.justice.digital.hmpps.integrations.delius.entity.Dataset
import uk.gov.justice.digital.hmpps.integrations.delius.entity.DatasetCode

object DatasetGenerator {
val ADDRESS_TYPE = Dataset(IdGenerator.getAndIncrement(), DatasetCode.ADDRESS_TYPE)
val ADDRESS_STATUS = Dataset(IdGenerator.getAndIncrement(), DatasetCode.ADDRESS_STATUS)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
},
"bookingId": "14c80733-4b6d-4f35-b724-66955aac320e",
"bookingUrl": "https://approved-premises-dev.hmpps.service.justice.gov.uk/someURLtoTheBooking",
"premises": {
"addressLine1": "12 Church Street",
"addressLine2": "",
"postcode": "BB1 1BB",
"town": "Bimbly Town",
"region": "Bibbinghammcshireshire"
},
"arrivedAt": "2022-11-30T12:00:00",
"notes": "person arrived"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import uk.gov.justice.digital.hmpps.integrations.approvedpremesis.EventDetails
import uk.gov.justice.digital.hmpps.integrations.approvedpremesis.PersonArrived
import uk.gov.justice.digital.hmpps.integrations.approvedpremesis.PersonDeparted
import uk.gov.justice.digital.hmpps.integrations.delius.entity.ContactRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonAddressRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonRepository
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
import uk.gov.justice.digital.hmpps.messaging.crn
import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
import uk.gov.justice.digital.hmpps.telemetry.notificationReceived
Expand All @@ -44,6 +47,12 @@ internal class CASIntegrationTest {
@Autowired
lateinit var contactRepository: ContactRepository

@Autowired
lateinit var addressRepository: PersonAddressRepository

@Autowired
lateinit var personRepository: PersonRepository

@MockBean
lateinit var telemetryService: TelemetryService

Expand Down Expand Up @@ -135,6 +144,15 @@ internal class CASIntegrationTest {
val contact = contactRepository.getByExternalReference(eventDetails.eventDetails.urn)

MatcherAssert.assertThat(contact!!.type.code, Matchers.equalTo("EAAR"))

val person = personRepository.findByCrnAndSoftDeletedIsFalse(event.message.crn())
val address = addressRepository.findMainAddress(person!!.id)

MatcherAssert.assertThat(address!!.type.code, Matchers.equalTo("A17"))
MatcherAssert.assertThat(address.town, Matchers.equalTo(eventDetails.eventDetails.premises.town))
MatcherAssert.assertThat(address.streetName, Matchers.equalTo(eventDetails.eventDetails.premises.addressLine1))
MatcherAssert.assertThat(address.county, Matchers.equalTo(eventDetails.eventDetails.premises.region))
MatcherAssert.assertThat(address.postcode, Matchers.equalTo(eventDetails.eventDetails.premises.postcode))
}

@Test
Expand Down Expand Up @@ -164,7 +182,6 @@ internal class CASIntegrationTest {

// Then it is logged to telemetry
Mockito.verify(telemetryService).notificationReceived(event)
val oldEventDetails = ResourceLoader.file<EventDetails<PersonDeparted>>("cas3-person-departed")
val eventDetails = ResourceLoader.file<EventDetails<PersonDeparted>>("cas3-$eventName")
val contact = contactRepository.getByExternalReference(eventDetails.eventDetails.urn)

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.approvedpremesis
import uk.gov.justice.digital.hmpps.datetime.DeliusDateFormatter
import uk.gov.justice.digital.hmpps.integrations.delius.entity.ContactType
import java.time.ZonedDateTime
import java.util.LinkedList

data class EventDetails<out T : Cas3Event>(
val id: String,
Expand Down Expand Up @@ -70,13 +71,38 @@ data class PersonArrived(
val bookingId: String,
val bookingUrl: String,
val arrivedAt: ZonedDateTime,
val notes: String
val notes: String,
val premises: Address
) : Cas3Event {
override val urn = "urn:hmpps:cas3:person-arrived:$bookingId"
override val noteText = "${DeliusDateFormatter.format(arrivedAt)} $notes $bookingUrl"
override val contactTypeCode = ContactType.PERSON_ARRIVED
}

data class Address(
val addressLine1: String,
val addressLine2: String?,
val postcode: String,
val town: String?,
val region: String
) {
val addressLines: AddressLines
get() {
val lines = LinkedList(addressLine1.chunked(35) + (addressLine2?.chunked(35) ?: listOf()))
return if (lines.size < 3) {
AddressLines(null, lines.pop(), lines.firstOrNull())
} else {
AddressLines(lines.pop(), lines.pop(), lines.pop())
}
}
}

data class AddressLines(
val buildingName: String?,
val streetName: String,
val district: String?
)

data class PersonDeparted(
val applicationId: String?,
val applicationUrl: String?,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package uk.gov.justice.digital.hmpps.integrations.delius

import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.integrations.approvedpremesis.PersonArrived
import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person
import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonAddress
import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonAddressRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceDataRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.cas3AddressType
import uk.gov.justice.digital.hmpps.integrations.delius.entity.mainAddressStatus
import uk.gov.justice.digital.hmpps.integrations.delius.entity.previousAddressStatus
import java.time.LocalDate

@Service
class AddressService(
private val personAddressRepository: PersonAddressRepository,
private val referenceDataRepository: ReferenceDataRepository
) {
fun updateMainAddress(person: Person, details: PersonArrived) {
endMainAddress(person, details.arrivedAt.toLocalDate())
toPersonAddress(person, details).apply(personAddressRepository::save)
}

fun endMainAddress(person: Person, endDate: LocalDate) {
val currentMain = personAddressRepository.findMainAddress(person.id)
currentMain?.apply {
val previousStatus = referenceDataRepository.previousAddressStatus()
currentMain.status = previousStatus
currentMain.endDate = endDate
}
}

private fun toPersonAddress(person: Person, details: PersonArrived): PersonAddress {
val addressLines = details.premises.addressLines
return PersonAddress(
0,
person.id,
referenceDataRepository.cas3AddressType(),
referenceDataRepository.mainAddressStatus(),
buildingName = addressLines.buildingName,
streetName = addressLines.streetName,
district = addressLines.district,
town = details.premises.town,
county = details.premises.region,
postcode = details.premises.postcode,
startDate = details.arrivedAt.toLocalDate()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractio
import uk.gov.justice.digital.hmpps.integrations.delius.entity.Contact
import uk.gov.justice.digital.hmpps.integrations.delius.entity.ContactRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.ContactTypeRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person
import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManagerRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonRepository
import uk.gov.justice.digital.hmpps.integrations.delius.entity.getByCrn
Expand All @@ -28,10 +29,11 @@ class ContactService(

fun <T : Cas3Event> createContact(
crn: String,
person: Person? = null,
getEvent: () -> EventDetails<T>
) = audit(BusinessInteractionCode.UPDATE_CONTACT) {
val event = getEvent()
val person = personRepository.getByCrn(crn)
val personId = person?.id ?: personRepository.getByCrn(crn).id
val existing = contactRepository.getByExternalReference(event.eventDetails.urn)
if (existing != null) {
if (existing.startTime < event.timestamp) {
Expand All @@ -49,7 +51,7 @@ class ContactService(
contactRepository.save(
newContact(
event.timestamp,
person.id,
personId,
event.eventDetails.contactTypeCode,
event.eventDetails.urn,
event.eventDetails.noteText
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package uk.gov.justice.digital.hmpps.integrations.delius.entity

import jakarta.persistence.Column
import jakarta.persistence.Convert
import jakarta.persistence.Entity
import jakarta.persistence.EntityListeners
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.SequenceGenerator
import jakarta.persistence.Table
import org.hibernate.type.YesNoConverter
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 org.springframework.data.jpa.repository.Query
import java.time.LocalDate
import java.time.ZonedDateTime

@Entity
@Table(name = "offender_address")
@EntityListeners(AuditingEntityListener::class)
@SequenceGenerator(name = "offender_address_id_generator", sequenceName = "offender_address_id_seq", allocationSize = 1)
class PersonAddress(
@Id
@Column(name = "offender_address_id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "offender_address_id_generator")
val id: Long,
@Column(name = "offender_id")
val personId: Long,
@ManyToOne
@JoinColumn(name = "address_type_id")
val type: ReferenceData,
@ManyToOne
@JoinColumn(name = "address_status_id")
var status: ReferenceData,
val streetName: String?,
@Column(name = "town_city")
val town: String?,
val county: String?,
val postcode: String?,
val telephoneNumber: String? = null,
val buildingName: String? = null,
val district: String? = null,
val addressNumber: String? = null,
@Convert(converter = YesNoConverter::class)
val noFixedAbode: Boolean? = false,
@Convert(converter = YesNoConverter::class)
val typeVerified: Boolean? = false,
val startDate: LocalDate = LocalDate.now(),
var endDate: LocalDate? = null,
@Column(updatable = false, columnDefinition = "NUMBER")
val softDeleted: Boolean = false,

@CreatedDate
@Column(nullable = false)
var createdDatetime: ZonedDateTime = ZonedDateTime.now(),

@Column(nullable = false)
@CreatedBy
var createdByUserId: Long = 0,

@Column(nullable = false)
@LastModifiedDate
var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now(),

@Column(nullable = false)
@LastModifiedBy
var lastUpdatedUserId: Long = 0,

@Column(nullable = false)
val partitionAreaId: Long = 0
)

interface PersonAddressRepository : JpaRepository<PersonAddress, Long> {
@Query(
"""
select pa from PersonAddress pa
join fetch pa.status
join fetch pa.type
where pa.personId = :personId
and pa.softDeleted = false
and pa.endDate is null
and pa.status.code = 'M'
"""
)
fun findMainAddress(personId: Long): PersonAddress?
}
Loading