Skip to content

Commit

Permalink
PI-1777 Handle CAS2 application status updated messages (#3037)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus-bcl authored Jan 17, 2024
1 parent ecb954c commit eea32f2
Show file tree
Hide file tree
Showing 15 changed files with 207 additions and 43 deletions.
3 changes: 3 additions & 0 deletions projects/cas2-and-delius/deploy/database/access.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ database:
access:
username_key: /cas2-and-delius/db-username
password_key: /cas2-and-delius/db-password
tables:
- audited_interaction
- contact

audit:
username: Cas2AndDelius
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.ApplicationListener
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.data.generator.EntityGenerator.BUSINESS_INTERACTIONS
import uk.gov.justice.digital.hmpps.data.generator.EntityGenerator.BUSINESS_INTERACTION
import uk.gov.justice.digital.hmpps.data.generator.EntityGenerator.CONTACT_TYPES
import uk.gov.justice.digital.hmpps.data.generator.EntityGenerator.MANAGER
import uk.gov.justice.digital.hmpps.data.generator.EntityGenerator.PERSON
Expand All @@ -29,10 +29,10 @@ class DataLoader(
@Transactional
override fun onApplicationEvent(applicationReadyEvent: ApplicationReadyEvent) {
listOf(
BUSINESS_INTERACTION,
PERSON,
MANAGER,
*CONTACT_TYPES,
*BUSINESS_INTERACTIONS,
).forEach {
entityManager.persist(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import uk.gov.justice.digital.hmpps.entity.ContactType.Companion.REFERRAL_UPDATE
import uk.gov.justice.digital.hmpps.entity.Person
import uk.gov.justice.digital.hmpps.entity.PersonManager
import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode.ADD_CONTACT
import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode.UPDATE_CONTACT
import java.time.ZonedDateTime

object EntityGenerator {
Expand All @@ -18,8 +17,5 @@ object EntityGenerator {
ContactType(id(), REFERRAL_SUBMITTED),
ContactType(id(), REFERRAL_UPDATED)
)
val BUSINESS_INTERACTIONS = arrayOf(
BusinessInteraction(id(), ADD_CONTACT.code, ZonedDateTime.now()),
BusinessInteraction(id(), UPDATE_CONTACT.code, ZonedDateTime.now()),
)
val BUSINESS_INTERACTION = BusinessInteraction(id(), ADD_CONTACT.code, ZonedDateTime.now())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"eventType": "applications.cas2.application.status-updated",
"version": 1,
"description": "A CAS2 application has been updated",
"detailUrl": "http://localhost:{wiremock.port}/approved-premises-api/events/cas2/application-status-updated/1",
"occurredAt": "2020-01-01T12:34:56Z[Europe/London]",
"personReference": {
"identifiers": [
{
"type": "CRN",
"value": "A000001"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"id": "1",
"timestamp": "2020-01-01T12:34:56Z[Europe/London]",
"eventType": "applications.cas2.application.status-updated",
"eventDetails": {
"applicationId": "00000000-0000-0000-0000-000000000001",
"applicationUrl": "https://example.com/application/00000000-0000-0000-0000-000000000001",
"updatedAt": "2020-01-01T12:34:56Z[Europe/London]",
"newStatus": {
"name": "moreInfoRequested",
"label": "More information requested",
"description": "More information about the application has been requested from the POM (Prison Offender Manager)."
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
"status": 200,
"bodyFileName": "application-submitted.json"
}
},
{
"request": {
"method": "GET",
"urlPath": "/approved-premises-api/events/cas2/application-status-updated/1"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"bodyFileName": "application-status-updated.json"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,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.hamcrest.Matchers.hasSize
import org.junit.jupiter.api.Test
import org.mockito.kotlin.verify
import org.springframework.beans.factory.annotation.Autowired
Expand All @@ -12,6 +13,7 @@ import org.springframework.boot.test.mock.mockito.MockBean
import uk.gov.justice.digital.hmpps.datetime.EuropeLondon
import uk.gov.justice.digital.hmpps.entity.ContactRepository
import uk.gov.justice.digital.hmpps.entity.ContactType.Companion.REFERRAL_SUBMITTED
import uk.gov.justice.digital.hmpps.entity.ContactType.Companion.REFERRAL_UPDATED
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
import uk.gov.justice.digital.hmpps.telemetry.notificationReceived
Expand Down Expand Up @@ -74,4 +76,47 @@ internal class IntegrationTest {
mapOf()
)
}

@Test
fun `application status updated`() {
// Given a message
val event = prepEvent("application-status-updated", wireMockServer.port())

// When it is received
channelManager.getChannel(queueName).publishAndWait(event)

// Then a contact is created
val contact = contactRepository.findAll().single { it.type.code == REFERRAL_UPDATED }
assertThat(contact.externalReference, equalTo("urn:hmpps:cas2:application-status-updated:1"))
assertThat(
contact.notes, equalTo(
"""
Application status was updated to: More information requested - More information about the application has been requested from the POM (Prison Offender Manager).
Details of the application can be found here: https://example.com/application/00000000-0000-0000-0000-000000000001
""".trimIndent()
)
)

// And it is logged to telemetry
verify(telemetryService).trackEvent(
"ApplicationStatusUpdated",
mapOf(
"crn" to "A000001",
"detailUrl" to "http://localhost:${wireMockServer.port()}/approved-premises-api/events/cas2/application-status-updated/1",
"applicationId" to "00000000-0000-0000-0000-000000000001",
"status" to "moreInfoRequested"
),
mapOf()
)

// And duplicate messages are ignored
channelManager.getChannel(queueName).publishAndWait(event)
assertThat(contactRepository.findAll().filter { it.type.code == REFERRAL_UPDATED }, hasSize(1))
verify(telemetryService).trackEvent(
"ContactAlreadyExists",
mapOf("urn" to "urn:hmpps:cas2:application-status-updated:1"),
mapOf()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ import uk.gov.justice.digital.hmpps.audit.InteractionCode

enum class BusinessInteractionCode(override val code: String) : InteractionCode {
ADD_CONTACT("CLBI003"),
UPDATE_CONTACT("CLBI007"),
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package uk.gov.justice.digital.hmpps.client.approvedpremises

import org.springframework.web.service.annotation.GetExchange
import uk.gov.justice.digital.hmpps.client.approvedpremises.model.ApplicationStatusUpdated
import uk.gov.justice.digital.hmpps.client.approvedpremises.model.ApplicationSubmitted
import uk.gov.justice.digital.hmpps.client.approvedpremises.model.EventDetails
import java.net.URI

interface EventDetailsClient {
@GetExchange
fun getApplicationSubmittedDetails(uri: URI): EventDetails<ApplicationSubmitted>

@GetExchange
fun getApplicationStatusUpdatedDetails(uri: URI): EventDetails<ApplicationStatusUpdated>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package uk.gov.justice.digital.hmpps.client.approvedpremises.model

data class ApplicationStatus(
val name: String,
val label: String,
val description: String,
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package uk.gov.justice.digital.hmpps.client.approvedpremises
package uk.gov.justice.digital.hmpps.client.approvedpremises.model

import java.time.ZonedDateTime

Expand All @@ -14,3 +14,10 @@ data class ApplicationSubmitted(
val applicationUrl: String,
val submittedAt: ZonedDateTime,
)

data class ApplicationStatusUpdated(
val applicationId: String,
val applicationUrl: String,
val newStatus: ApplicationStatus,
val updatedAt: ZonedDateTime,
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Handler(
val event = notification.message
when (event.eventType) {
"applications.cas2.application.submitted" -> cas2Service.applicationSubmitted(event)
"applications.cas2.application.status-updated" -> cas2Service.applicationStatusUpdated(event)

else -> throw IllegalArgumentException("Unexpected event type ('${event.eventType}')")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package uk.gov.justice.digital.hmpps.service
import jakarta.transaction.Transactional
import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.client.approvedpremises.EventDetailsClient
import uk.gov.justice.digital.hmpps.entity.*
import uk.gov.justice.digital.hmpps.entity.ContactType
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.messaging.HmppsDomainEventExtensions.crn
import uk.gov.justice.digital.hmpps.messaging.HmppsDomainEventExtensions.telemetryProperties
Expand All @@ -14,24 +14,40 @@ import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
@Transactional
class Cas2Service(
private val eventDetailsClient: EventDetailsClient,
private val personRepository: PersonRepository,
private val contactService: ContactService,
private val personManagerRepository: PersonManagerRepository,
private val telemetryService: TelemetryService,
) {

fun applicationSubmitted(event: HmppsDomainEvent) {
val details = eventDetailsClient.getApplicationSubmittedDetails(event.url).eventDetails
val person = personRepository.getByCrn(event.crn)
val manager = personManagerRepository.getActiveManager(person.id)
val details = eventDetailsClient.getApplicationSubmittedDetails(event.url)
val success = contactService.createContact(
personId = person.id,
crn = event.crn,
type = ContactType.REFERRAL_SUBMITTED,
date = details.submittedAt,
manager = manager,
notes = "Details of the application can be found here: ${details.applicationUrl}",
urn = "urn:hmpps:cas2:application-submitted:${details.applicationId}",
date = details.eventDetails.submittedAt,
notes = "Details of the application can be found here: ${details.eventDetails.applicationUrl}",
urn = "urn:hmpps:cas2:application-submitted:${details.eventDetails.applicationId}",
)
if (success) telemetryService.trackEvent("ApplicationSubmitted", event.telemetryProperties)
}

fun applicationStatusUpdated(event: HmppsDomainEvent) {
val details = eventDetailsClient.getApplicationStatusUpdatedDetails(event.url)
val success = contactService.createContact(
crn = event.crn,
type = ContactType.REFERRAL_UPDATED,
date = details.eventDetails.updatedAt,
notes = """
Application status was updated to: ${details.eventDetails.newStatus.label} - ${details.eventDetails.newStatus.description}
Details of the application can be found here: ${details.eventDetails.applicationUrl}
""".trimIndent(),
urn = "urn:hmpps:cas2:application-status-updated:${details.id}",
)
if (success) telemetryService.trackEvent(
"ApplicationStatusUpdated", event.telemetryProperties + mapOf(
"applicationId" to details.eventDetails.applicationId,
"status" to details.eventDetails.newStatus.name
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,27 @@ class ContactService(
auditedInteractionService: AuditedInteractionService,
private val contactRepository: ContactRepository,
private val contactTypeRepository: ContactTypeRepository,
private val personRepository: PersonRepository,
private val personManagerRepository: PersonManagerRepository,
private val telemetryService: TelemetryService,
) : AuditableService(auditedInteractionService) {

fun createContact(
personId: Long,
crn: String,
type: String,
date: ZonedDateTime,
manager: PersonManager,
notes: String,
urn: String,
) = if (contactRepository.existsByExternalReference(urn)) {
telemetryService.trackEvent("ContactAlreadyExists", mapOf("urn" to urn))
false
} else audit(BusinessInteractionCode.ADD_CONTACT) { audit ->
val person = personRepository.getByCrn(crn)
val manager = personManagerRepository.getActiveManager(person.id)
val contact = contactRepository.save(
Contact(
personId = personId,
type = contactTypeRepository.getByCode(ContactType.REFERRAL_SUBMITTED),
personId = person.id,
type = contactTypeRepository.getByCode(type),
date = date.toLocalDate(),
startTime = date,
staffId = manager.staffId,
Expand All @@ -43,7 +46,7 @@ class ContactService(
)
)
audit["contactId"] = contact.id
audit["offenderId"] = personId
audit["offenderId"] = person.id
true
}
}
Loading

0 comments on commit eea32f2

Please sign in to comment.