Skip to content

Commit

Permalink
PI-2605 Send domain events for address changes (#4399)
Browse files Browse the repository at this point in the history
* PI-2605 Send domain events for address changes

* Formatting changes

---------

Co-authored-by: probation-integration-bot[bot] <177347787+probation-integration-bot[bot]@users.noreply.github.com>
  • Loading branch information
1 parent 6b9090f commit 5da437f
Show file tree
Hide file tree
Showing 18 changed files with 324 additions and 77 deletions.
2 changes: 2 additions & 0 deletions projects/approved-premises-and-delius/deploy/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ generic-service:
SENTRY_DSN: SENTRY_DSN
approved-premises-and-delius-queue:
MESSAGING_CONSUMER_QUEUE: QUEUE_NAME
hmpps-domain-events-topic:
MESSAGING_PRODUCER_TOPIC: topic_arn

generic-prometheus-alerts:
targetApplication: approved-premises-and-delius
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.containsString
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation
import org.junit.jupiter.api.Order
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -36,6 +37,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.person.address.PersonAdd
import uk.gov.justice.digital.hmpps.integrations.delius.referencedata.ApprovedPremisesCategoryCode
import uk.gov.justice.digital.hmpps.integrations.delius.staff.StaffRepository
import uk.gov.justice.digital.hmpps.integrations.delius.staff.getByCode
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
import uk.gov.justice.digital.hmpps.messaging.crn
import uk.gov.justice.digital.hmpps.messaging.telemetryProperties
Expand All @@ -51,6 +53,9 @@ internal class MessagingIntegrationTest {
@Value("\${messaging.consumer.queue}")
lateinit var queueName: String

@Value("\${messaging.producer.topic}")
lateinit var topicName: String

@Autowired
lateinit var channelManager: HmppsChannelManager

Expand Down Expand Up @@ -81,6 +86,14 @@ internal class MessagingIntegrationTest {
@Autowired
private lateinit var staffRepository: StaffRepository

@BeforeEach
fun clearTopic() {
val topic = channelManager.getChannel(topicName)
do {
val message = topic.receive()?.also { topic.done(it.id) }
} while (message != null)
}

@Test
fun `application submission creates an alert contact`() {
// Given an application-submitted event
Expand Down Expand Up @@ -299,6 +312,13 @@ internal class MessagingIntegrationTest {
assertThat(main.postcode, equalTo(ap.postcode))
assertThat(main.telephoneNumber, equalTo(ap.telephoneNumber))

// And a domain event is published for the new address
val domainEvent = channelManager.getChannel(topicName).receive()?.message as HmppsDomainEvent
assertThat(domainEvent.eventType, equalTo("probation-case.address.created"))
assertThat(domainEvent.crn(), equalTo(event.message.crn()))
assertThat(domainEvent.additionalInformation["addressId"], equalTo(main.id))
assertThat(domainEvent.additionalInformation["addressStatus"], equalTo("Main Address"))

val keyWorker = staffRepository.getByCode("N54A001")
val residences = residenceRepository.findAll().filter { it.personId == contact.person.id }
assertThat(residences.size, equalTo(1))
Expand Down Expand Up @@ -350,6 +370,11 @@ internal class MessagingIntegrationTest {

assertNull(personAddressRepository.findMainAddress(PersonGenerator.DEFAULT.id))

val domainEvent = channelManager.getChannel(topicName).receive()?.message as HmppsDomainEvent
assertThat(domainEvent.eventType, equalTo("probation-case.address.updated"))
assertThat(domainEvent.crn(), equalTo(event.message.crn()))
assertThat(domainEvent.additionalInformation["addressStatus"], equalTo("Previous Address"))

val residence = residenceRepository.findAll().first { it.personId == contact.person.id }
assertThat(residence.departureDate, equalTo(nsi.actualEndDate))
assertThat(residence.departureReasonId, equalTo(ReferenceDataGenerator.ORDER_EXPIRED.id))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package uk.gov.justice.digital.hmpps.messaging

import org.openfolder.kotlinasyncapi.annotation.Schema
import org.openfolder.kotlinasyncapi.annotation.channel.Channel
import org.openfolder.kotlinasyncapi.annotation.channel.Message
import org.openfolder.kotlinasyncapi.annotation.channel.Subscribe
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.message.*
import uk.gov.justice.digital.hmpps.publisher.NotificationPublisher

@Service
@Channel("hmpps-domain-events-topic")
class Notifier(@Qualifier("topicPublisher") private val topicPublisher: NotificationPublisher) {
@Subscribe(
messages = [
Message(title = "probation-case.address.created", payload = Schema(HmppsDomainEvent::class)),
Message(title = "probation-case.address.updated", payload = Schema(HmppsDomainEvent::class))
]
)
fun addressCreated(crn: String, addressId: Long, addressStatus: String) {
topicPublisher.publish(
Notification(
message = HmppsDomainEvent(
version = 1,
eventType = "probation-case.address.created",
description = "A new address has been created on the probation case",
personReference = PersonReference(
identifiers = listOf(
PersonIdentifier("CRN", crn),
),
),
additionalInformation = mapOf(
"addressStatus" to addressStatus,
"addressId" to addressId
)
),
attributes = MessageAttributes("probation-case.address.created")
)
)
}

fun addressUpdated(crn: String, addressId: Long, addressStatus: String) {
topicPublisher.publish(
Notification(
message = HmppsDomainEvent(
version = 1,
eventType = "probation-case.address.updated",
description = "An address has been updated on the probation case",
personReference = PersonReference(
identifiers = listOf(
PersonIdentifier("CRN", crn),
),
),
additionalInformation = mapOf(
"addressStatus" to addressStatus,
"addressId" to addressId
)
),
attributes = MessageAttributes("probation-case.address.updated")
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@ class AddressService(
private val personAddressRepository: PersonAddressRepository,
private val referenceDataRepository: ReferenceDataRepository
) {
fun updateMainAddress(person: Person, details: PersonArrived, ap: ApprovedPremises) {
endMainAddress(person, details.arrivedAt.toLocalDate())
ap.arrival(person, details).apply(personAddressRepository::save)
fun updateMainAddress(
person: Person,
details: PersonArrived,
ap: ApprovedPremises
): Pair<PersonAddress?, PersonAddress> {
val previous = endMainAddress(person, details.arrivedAt.toLocalDate())
val current = ap.arrival(person, details).let(personAddressRepository::save)
return previous to current
}

fun endMainAddress(person: Person, endDate: LocalDate) {
fun endMainAddress(person: Person, endDate: LocalDate): PersonAddress? {
val currentMain = personAddressRepository.findMainAddress(person.id)
currentMain?.apply {
return currentMain?.also {
val previousStatus = referenceDataRepository.previousAddressStatus()
currentMain.status = previousStatus
currentMain.endDate = endDate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.person.getByCrn
import uk.gov.justice.digital.hmpps.integrations.delius.staff.StaffRepository
import uk.gov.justice.digital.hmpps.integrations.delius.staff.getByCode
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.messaging.Notifier
import uk.gov.justice.digital.hmpps.messaging.crn
import uk.gov.justice.digital.hmpps.messaging.url

Expand All @@ -24,7 +25,8 @@ class ApprovedPremisesService(
private val eventRepository: EventRepository,
private val contactService: ContactService,
private val nsiService: NsiService,
private val referralService: ReferralService
private val referralService: ReferralService,
private val notifier: Notifier,
) {
fun applicationSubmitted(event: HmppsDomainEvent) {
val details = approvedPremisesApiClient.getApplicationSubmittedDetails(event.url()).eventDetails
Expand Down Expand Up @@ -115,13 +117,18 @@ class ApprovedPremisesService(
val details = approvedPremisesApiClient.getPersonArrivedDetails(event.url()).eventDetails
val person = personRepository.getByCrn(event.crn())
val ap = approvedPremisesRepository.getApprovedPremises(details.premises.legacyApCode)
nsiService.personArrived(person, details, ap)
nsiService.personArrived(person, details, ap)?.let { (previousAddress, newAddress) ->
notifier.addressCreated(person.crn, newAddress.id, newAddress.status.description)
previousAddress?.let { notifier.addressUpdated(person.crn, it.id, it.status.description) }
}
}

fun personDeparted(event: HmppsDomainEvent) {
val details = approvedPremisesApiClient.getPersonDepartedDetails(event.url()).eventDetails
val person = personRepository.getByCrn(event.crn())
val ap = approvedPremisesRepository.getApprovedPremises(details.premises.legacyApCode)
nsiService.personDeparted(person, details, ap)
nsiService.personDeparted(person, details, ap)?.let { updatedAddress ->
notifier.addressUpdated(person.crn, updatedAddress.id, updatedAddress.status.description)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.contact.outcome.ContactO
import uk.gov.justice.digital.hmpps.integrations.delius.contact.type.ContactTypeCode
import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention.entity.*
import uk.gov.justice.digital.hmpps.integrations.delius.person.Person
import uk.gov.justice.digital.hmpps.integrations.delius.person.address.PersonAddress
import uk.gov.justice.digital.hmpps.integrations.delius.referencedata.ReferenceDataRepository
import uk.gov.justice.digital.hmpps.integrations.delius.referencedata.referralCompleted
import uk.gov.justice.digital.hmpps.integrations.delius.staff.StaffRepository
Expand Down Expand Up @@ -38,7 +39,7 @@ class NsiService(
person: Person,
details: PersonArrived,
ap: ApprovedPremises
) {
): Pair<PersonAddress?, PersonAddress>? {
val externalReference = Nsi.EXT_REF_BOOKING_PREFIX + details.bookingId
nsiRepository.findByPersonIdAndExternalReference(person.id, externalReference) ?: run {
val staff = staffRepository.getByCode(details.keyWorker.staffCode)
Expand Down Expand Up @@ -69,7 +70,6 @@ class NsiService(
transferReason = transferReasonRepository.getNsiTransferReason()
)
)
addressService.updateMainAddress(person, details, ap)
contactService.createContact(
ContactDetails(
date = details.arrivedAt,
Expand All @@ -88,15 +88,16 @@ class NsiService(
probationAreaCode = ap.probationArea.code
)
referralService.personArrived(person, ap, details)
return addressService.updateMainAddress(person, details, ap)
}
return null
}

fun personDeparted(person: Person, details: PersonDeparted, ap: ApprovedPremises) {
fun personDeparted(person: Person, details: PersonDeparted, ap: ApprovedPremises): PersonAddress? {
val nsi =
nsiRepository.findByPersonIdAndExternalReference(person.id, Nsi.EXT_REF_BOOKING_PREFIX + details.bookingId)
nsi?.actualEndDate = details.departedAt
nsi?.outcome = referenceDataRepository.referralCompleted()
addressService.endMainAddress(person, details.departedAt.toLocalDate())
contactService.createContact(
ContactDetails(
date = details.departedAt,
Expand All @@ -114,5 +115,6 @@ class NsiService(
probationAreaCode = ap.probationArea.code
)
referralService.personDeparted(person, details)
return addressService.endMainAddress(person, details.departedAt.toLocalDate())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ wiremock.enabled: true
context.initializer.classes: uk.gov.justice.digital.hmpps.wiremock.WireMockInitialiser

messaging.consumer.queue: message-queue
messaging.producer.topic: domain-events

integrations:
approved-premises-api:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.staff.Staff
import uk.gov.justice.digital.hmpps.integrations.delius.staff.StaffRepository
import uk.gov.justice.digital.hmpps.integrations.delius.team.Team
import uk.gov.justice.digital.hmpps.integrations.delius.team.TeamRepository
import uk.gov.justice.digital.hmpps.messaging.Notifier
import uk.gov.justice.digital.hmpps.messaging.crn
import uk.gov.justice.digital.hmpps.messaging.url
import uk.gov.justice.digital.hmpps.prepEvent
Expand Down Expand Up @@ -131,6 +132,9 @@ internal class ApprovedPremisesServiceTest {
@Mock
lateinit var applicationStartedEvent: ApplicationStartedEvent

@Mock
lateinit var notifier: Notifier

lateinit var addressService: AddressService
lateinit var contactService: ContactService
lateinit var nsiService: NsiService
Expand Down Expand Up @@ -191,7 +195,8 @@ internal class ApprovedPremisesServiceTest {
eventRepository,
contactService,
nsiService,
referralService
referralService,
notifier,
)
}

Expand Down Expand Up @@ -304,6 +309,7 @@ internal class ApprovedPremisesServiceTest {
givenAddressTypes(listOf(ReferenceDataGenerator.AP_ADDRESS_TYPE))
givenAuditUser()
givenReferral(person, details.eventDetails.bookingId)
whenever(personAddressRepository.save(any())).thenAnswer { it.arguments[0] }

approvedPremisesService.personArrived(personArrivedEvent)

Expand Down
2 changes: 2 additions & 0 deletions projects/cas3-and-delius/deploy/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ generic-service:
SENTRY_DSN: SENTRY_DSN
cas3-and-delius-queue:
MESSAGING_CONSUMER_QUEUE: QUEUE_NAME
hmpps-domain-events-topic:
MESSAGING_PRODUCER_TOPIC: topic_arn

generic-prometheus-alerts:
targetApplication: cas3-and-delius
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import uk.gov.justice.digital.hmpps.integrations.approvedpremises.*
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.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
import uk.gov.justice.digital.hmpps.messaging.crn
import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader
Expand All @@ -37,6 +38,9 @@ internal class CASIntegrationTest {
@Value("\${messaging.consumer.queue}")
lateinit var queueName: String

@Value("\${messaging.producer.topic}")
lateinit var topicName: String

@Autowired
lateinit var channelManager: HmppsChannelManager

Expand Down Expand Up @@ -182,6 +186,12 @@ internal class CASIntegrationTest {
assertThat(address.streetName, equalTo("12 Church Street"))
assertThat(address.county, equalTo("Bibbinghammcshireshire"))
assertThat(address.postcode, equalTo("BB1 1BB"))

val domainEvent = channelManager.getChannel(topicName).receive()?.message as HmppsDomainEvent
assertThat(domainEvent.eventType, equalTo("probation-case.address.created"))
assertThat(domainEvent.crn(), equalTo(event.message.crn()))
assertThat(domainEvent.additionalInformation["addressId"], equalTo(address.id))
assertThat(domainEvent.additionalInformation["addressStatus"], equalTo("Main Address"))
}

@Test
Expand Down Expand Up @@ -215,6 +225,12 @@ internal class CASIntegrationTest {
assertThat(address!!.status.code, equalTo("P"))
assertThat(contact.teamId, equalTo(ProviderGenerator.DEFAULT_TEAM.id))
assertThat(contact.staffId, equalTo(ProviderGenerator.DEFAULT_STAFF.id))

val domainEvent = channelManager.getChannel(topicName).receive()?.message as HmppsDomainEvent
assertThat(domainEvent.eventType, equalTo("probation-case.address.updated"))
assertThat(domainEvent.crn(), equalTo(event.message.crn()))
assertThat(domainEvent.additionalInformation["addressId"], equalTo(address.id))
assertThat(domainEvent.additionalInformation["addressStatus"], equalTo("Main Address"))
}

@Test
Expand Down
Loading

0 comments on commit 5da437f

Please sign in to comment.