From e37d9947ecdc6264ea782fd70899fba76bc8e97a Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Wed, 16 Oct 2024 09:07:35 +0100 Subject: [PATCH 01/17] PI-2575 - Create common-platform-and-delius service --- .../deploy/database/access.yml | 10 +- .../justice/digital/hmpps/data/DataLoader.kt | 14 +- .../hmpps/data/generator/MessageGenerator.kt | 5 +- .../hmpps/data/generator/PersonGenerator.kt | 48 +++++++ .../data/generator/ReferenceDataGenerator.kt | 38 +++++ .../hmpps/data/generator/StaffGenerator.kt | 42 ++++++ .../src/dev/resources/db/h2.sql | 8 ++ ...mon-platform-hearing-validation-error.json | 29 ++++ .../messages/common-platform-hearing.json | 29 ++++ .../resources/messages/example-message.json | 17 --- .../probation-search-multiple-results.json | 33 +++++ .../__files/probation-search-no-results.json | 4 + .../probation-search-single-result.json | 83 +++++++++++ .../justice/digital/hmpps/IntegrationTest.kt | 133 ++++++++++++++++-- .../digital/hmpps/config/RestClientConfig.kt | 11 +- .../client/ProbationSearchClient.kt | 53 +++++++ .../delius/audit/BusinessInteractionCode.kt | 7 + .../integrations/delius/entity/Equality.kt | 40 ++++++ .../integrations/delius/entity/Person.kt | 67 +++++++++ .../delius/entity/PersonManager.kt | 104 ++++++++++++++ .../delius/entity/ReferenceData.kt | 113 +++++++++++++++ .../entity/repository/EqualityRepository.kt | 6 + .../repository/PersonManagerRepository.kt | 16 +++ .../entity/repository/PersonRepository.kt | 7 + .../repository/ReferenceDataRepository.kt | 29 ++++ .../integrations/example/ExampleClient.kt | 9 -- .../hmpps/messaging/CommonPlatformHearing.kt | 112 +++++++++++++++ .../digital/hmpps/messaging/Converter.kt | 22 +++ .../digital/hmpps/messaging/Handler.kt | 109 ++++++++++++-- .../digital/hmpps/service/PersonService.kt | 81 +++++++++++ .../src/main/resources/application.yml | 8 +- .../digital/hmpps/messaging/HandlerTest.kt | 18 +-- .../digital/hmpps/service/ServiceTest.kt | 99 +++++++++++++ 33 files changed, 1321 insertions(+), 83 deletions(-) create mode 100644 projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt create mode 100644 projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt create mode 100644 projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt create mode 100644 projects/common-platform-and-delius/src/dev/resources/db/h2.sql create mode 100644 projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-validation-error.json create mode 100644 projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json delete mode 100644 projects/common-platform-and-delius/src/dev/resources/messages/example-message.json create mode 100644 projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-multiple-results.json create mode 100644 projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-no-results.json create mode 100644 projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-single-result.json create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/client/ProbationSearchClient.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt delete mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/example/ExampleClient.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Converter.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt create mode 100644 projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt diff --git a/projects/common-platform-and-delius/deploy/database/access.yml b/projects/common-platform-and-delius/deploy/database/access.yml index db47e38201..1813a0db8d 100644 --- a/projects/common-platform-and-delius/deploy/database/access.yml +++ b/projects/common-platform-and-delius/deploy/database/access.yml @@ -3,7 +3,15 @@ database: username_key: /common-platform-and-delius/db-username password_key: /common-platform-and-delius/db-password + tables: + - offender + - offender_manager + - equality + - audited_interaction + packages: + - offender_support_api # for generating crn + audit: username: CommonPlatformAndDelius forename: Common Platform - surname: Service + surname: Service \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index f6ea94c9a7..c17997c905 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -1,16 +1,22 @@ package uk.gov.justice.digital.hmpps.data import jakarta.annotation.PostConstruct +import jakarta.persistence.EntityManager 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 org.springframework.transaction.annotation.Transactional +import uk.gov.justice.digital.hmpps.data.generator.CourtGenerator +import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator +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 @Component @ConditionalOnProperty("seed.database") class DataLoader( + private val entityManager: EntityManager, private val auditUserRepository: AuditUserRepository ) : ApplicationListener { @@ -19,7 +25,13 @@ class DataLoader( auditUserRepository.save(UserGenerator.AUDIT_USER) } + @Transactional override fun onApplicationEvent(are: ApplicationReadyEvent) { - // Perform dev/test database setup here, using JPA repositories and generator classes... + entityManager.run { + persist(ProviderGenerator.DEFAULT) + persist(ReferenceDataGenerator.GENDER_MALE) + persist(ReferenceDataGenerator.GENDER_FEMALE) + persist(CourtGenerator.UNKNOWN_COURT_N07_PROVIDER) + } } } diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt index 5ed8de87fc..6d6f4067f5 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt @@ -1,8 +1,9 @@ package uk.gov.justice.digital.hmpps.data.generator -import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent +import uk.gov.justice.digital.hmpps.messaging.CommonPlatformHearing import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader object MessageGenerator { - val EXAMPLE = ResourceLoader.message("example-message") + val COMMON_PLATFORM_EVENT = ResourceLoader.message("common-platform-hearing") + val COMMON_PLATFORM_EVENT_VALIDATION_ERROR = ResourceLoader.message("common-platform-hearing-validation-error") } diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt new file mode 100644 index 0000000000..778db68c86 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -0,0 +1,48 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.integrations.delius.entity.* +import java.time.LocalDate +import java.time.LocalDateTime +import java.util.* +import kotlin.random.Random + +object PersonGenerator { + val DEFAULT = generate(crn = "A000001") + + fun generate( + crn: String, + id: Long? = IdGenerator.getAndIncrement() + ) = Person( + id = id, + crn = crn, + forename = UUID.randomUUID().toString().substring(0, 15), + surname = UUID.randomUUID().toString().substring(0, 15), + dateOfBirth = LocalDate.now().minusYears(Random.nextInt(16, 76).toLong()), + gender = if (Random.nextBoolean()) ReferenceDataGenerator.GENDER_MALE else ReferenceDataGenerator.GENDER_FEMALE + ) +} + +object PersonManagerGenerator { + + val DEFAULT = generate(person = PersonGenerator.DEFAULT) + + fun generate( + id: Long = IdGenerator.getAndIncrement(), + person: Person, + provider: Provider = ProviderGenerator.DEFAULT, + team: Team = TeamGenerator.UNALLOCATED, + staff: Staff = StaffGenerator.UNALLOCATED, + allocationDate: LocalDateTime = LocalDateTime.of(1900, 1, 1, 0, 0), + allocationReason: ReferenceData = ReferenceDataGenerator.INITIAL_ALLOCATION + ) = PersonManager( + id = id, + person = person, + provider = provider, + staff = staff, + staffEmployeeID = staff.id, + team = team, + trustProviderTeamId = team.id, + allocationDate = allocationDate, + allocationReason = allocationReason + ) +} diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt new file mode 100644 index 0000000000..a7b47c0c71 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt @@ -0,0 +1,38 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator.GENDER +import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator.OM_ALLOCATION_REASON +import uk.gov.justice.digital.hmpps.integrations.delius.entity.* + +object ReferenceDataGenerator { + + val GENDER_FEMALE = generate("F", GENDER.id, "Female") + val GENDER_MALE = generate("M", GENDER.id, "Male") + val INITIAL_ALLOCATION = generate("IN1", OM_ALLOCATION_REASON.id, "Initial Allocation") + + fun generate( + code: String, + datasetId: Long, + description: String = "Description of $code", + id: Long = IdGenerator.getAndIncrement() + ) = ReferenceData(id = id, code = code, datasetId = datasetId, description = description) +} + +object DatasetGenerator { + val ALL_DATASETS = DatasetCode.entries.map { Dataset(IdGenerator.getAndIncrement(), it) }.associateBy { it.code } + val GENDER = ALL_DATASETS[DatasetCode.GENDER]!! + val OM_ALLOCATION_REASON = ALL_DATASETS[DatasetCode.OM_ALLOCATION_REASON]!! + fun all() = ALL_DATASETS.values +} + +object CourtGenerator { + val UNKNOWN_COURT_N07_PROVIDER = generate(code = "UNKNCT") + + fun generate( + id: Long = IdGenerator.getAndIncrement(), + code: String, + selectable: Boolean = true, + courtName: String = "Court not known", + provider: Provider = ProviderGenerator.DEFAULT, + ) = Court(id = id, code = code, selectable = selectable, courtName = courtName, probationArea = provider) +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt new file mode 100644 index 0000000000..202e3479e1 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt @@ -0,0 +1,42 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Provider +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Staff +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Team +import java.util.concurrent.atomic.AtomicLong + +object StaffGenerator { + val UNALLOCATED = generate("N07UATU") + val ALLOCATED = generate("N07T01A") + fun generate( + code: String, + id: Long = IdGenerator.getAndIncrement(), + ) = + Staff(code = code, id = id) +} + +object ProviderGenerator { + val DEFAULT = generate() + fun generate(id: Long = IdGenerator.getAndIncrement()) = Provider( + id = id, + selectable = true, + code = "N07", + description = "London", + endDate = null, + ) +} + +object TeamGenerator { + private val teamCodeGenerator = AtomicLong(1) + val ALLOCATED = generate(code = "N07T01") + val UNALLOCATED = generate(code = "N07UAT") + + fun generate( + code: String = "N07${teamCodeGenerator.getAndIncrement().toString().padStart(3, '0')}", + description: String = "Description of Team $code", + ) = Team( + id = IdGenerator.getAndIncrement(), + code = code, + description = description, + ) +} diff --git a/projects/common-platform-and-delius/src/dev/resources/db/h2.sql b/projects/common-platform-and-delius/src/dev/resources/db/h2.sql new file mode 100644 index 0000000000..89bdf0a265 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/db/h2.sql @@ -0,0 +1,8 @@ +DROP SCHEMA IF EXISTS offender_support_api CASCADE; + +CREATE SCHEMA offender_support_api; + +CREATE ALIAS offender_support_api.getNextCRN AS +'String getNextCRN() { + return "A111111"; +}'; \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-validation-error.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-validation-error.json new file mode 100644 index 0000000000..42b65e18c1 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-validation-error.json @@ -0,0 +1,29 @@ +{ + "Type": "Notification", + "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", + "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", + "Message" : "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2015-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":null,\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", + "Timestamp": "2022-07-27T14:22:08.509Z", + "SignatureVersion": "1", + "Signature": "EXAMPLE", + "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", + "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", + "MessageAttributes": { + "tracestate": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + }, + "eventType": { + "Type": "String", + "Value": "COMMON_PLATFORM_HEARING" + }, + "hearingEventType": { + "Type": "String", + "Value": "ConfirmedOrUpdated" + }, + "traceparent": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + } + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json new file mode 100644 index 0000000000..d4aa789163 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json @@ -0,0 +1,29 @@ +{ + "Type": "Notification", + "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", + "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", + "Message" : "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":null,\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", + "Timestamp": "2022-07-27T14:22:08.509Z", + "SignatureVersion": "1", + "Signature": "EXAMPLE", + "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", + "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", + "MessageAttributes": { + "tracestate": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + }, + "eventType": { + "Type": "String", + "Value": "COMMON_PLATFORM_HEARING" + }, + "hearingEventType": { + "Type": "String", + "Value": "ConfirmedOrUpdated" + }, + "traceparent": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + } + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/example-message.json b/projects/common-platform-and-delius/src/dev/resources/messages/example-message.json deleted file mode 100644 index 3ec3f10524..0000000000 --- a/projects/common-platform-and-delius/src/dev/resources/messages/example-message.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "Type": "Notification", - "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", - "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", - "Message": "{\"eventType\":\"example\",\"version\":1,\"description\":\"Example event\",\"detailUrl\":\"http://localhost:{wiremock.port}/example/123\",\"occurredAt\":\"2022-07-27T15:22:08.452612281+01:00\",\"additionalInformation\":{\"exampleId\":\"123\"},\"personReference\":{\"identifiers\":[{\"type\":\"CRN\",\"value\":\"A000001\"}]}}", - "Timestamp": "2022-07-27T14:22:08.509Z", - "SignatureVersion": "1", - "Signature": "EXAMPLE", - "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", - "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", - "MessageAttributes": { - "eventType": { - "Type": "String", - "Value": "example" - } - } -} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-multiple-results.json b/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-multiple-results.json new file mode 100644 index 0000000000..a1150c6bb5 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-multiple-results.json @@ -0,0 +1,33 @@ +{ + "matches": [ + { + "offender": { + "offenderId": 1, + "title": "Mr", + "firstName": "Bill", + "middleNames": [], + "surname": "Jones", + "dateOfBirth": "1960-04-07", + "gender": "Male", + "otherIds": { + "crn": "A000002" + } + } + }, + { + "offender": { + "offenderId": 2, + "title": "Mr", + "firstName": "Bob", + "middleNames": [], + "surname": "Smith", + "dateOfBirth": "1960-04-07", + "gender": "Male", + "otherIds": { + "crn": "A000001" + } + } + } + ], + "matchedBy": "ALL_SUPPLIED" +} diff --git a/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-no-results.json b/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-no-results.json new file mode 100644 index 0000000000..a83d51cf3a --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-no-results.json @@ -0,0 +1,4 @@ +{ + "matches": [], + "matchedBy": "NONE" +} diff --git a/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-single-result.json b/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-single-result.json new file mode 100644 index 0000000000..2ffb6260bc --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/simulations/__files/probation-search-single-result.json @@ -0,0 +1,83 @@ +{ + "matches": [ + { + "offender": { + "offenderId": 1, + "title": "Mr", + "firstName": "Bob", + "middleNames": [], + "surname": "Smith", + "dateOfBirth": "1960-04-07", + "gender": "Smith", + "otherIds": { + "crn": "A000001", + "croNumber": "AB12/123456C", + "niNumber": "JJ123456C" + }, + "contactDetails": { + "phoneNumbers": [], + "emailAddresses": [] + }, + "offenderProfile": { + "offenderLanguages": { + "requiresInterpreter": false + }, + "previousConviction": { + "detail": {} + } + }, + "offenderManagers": [ + { + "staff": { + "code": "N57UATU", + "forenames": "Unallocated", + "surname": "Staff" + }, + "partitionArea": "National Data", + "softDeleted": false, + "team": { + "code": "N57UAT", + "description": "Unallocated Team(N57)", + "district": { + "code": "N57UAT", + "description": "Unallocated Level 3(N57)" + }, + "borough": { + "code": "N57UAT", + "description": "Unallocated Level2(N57)" + } + }, + "probationArea": { + "code": "N57", + "description": "Kent Surrey Sussex Region", + "nps": false + }, + "fromDate": "1900-01-01", + "active": true, + "allocationReason": { + "code": "IN1", + "description": "Initial Allocation" + } + } + ], + "softDeleted": false, + "currentDisposal": "0", + "partitionArea": "National Data", + "currentRestriction": true, + "restrictionMessage": "This is a restricted offender record. Please contact a system administrator", + "currentExclusion": false, + "exclusionMessage": "You are excluded from viewing this offender record. Please contact a system administrator", + "currentTier": "UD0", + "activeProbationManagedSentence": false, + "probationStatus": { + "status": "NOT_SENTENCED", + "inBreach": false, + "preSentenceActivity": false, + "awaitingPsr": false + }, + "age": 63 + } + } + ], + "matchedBy": "ALL_SUPPLIED" +} diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 2c6461b551..a75123b587 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -1,20 +1,36 @@ package uk.gov.justice.digital.hmpps +import com.github.tomakehurst.wiremock.WireMockServer +import com.github.tomakehurst.wiremock.client.WireMock.* +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.atLeastOnce -import org.mockito.kotlin.verify +import org.mockito.kotlin.* import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.boot.test.mock.mockito.SpyBean +import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator +import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.CourtRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.PersonRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.ReferenceDataRepository import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager -import uk.gov.justice.digital.hmpps.telemetry.TelemetryService +import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived -import java.util.concurrent.TimeoutException +import uk.gov.justice.digital.hmpps.telemetry.TelemetryService -@SpringBootTest +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) internal class IntegrationTest { @Value("\${messaging.consumer.queue}") lateinit var queueName: String @@ -22,22 +38,111 @@ internal class IntegrationTest { @Autowired lateinit var channelManager: HmppsChannelManager + @Autowired + lateinit var wireMockServer: WireMockServer + + @Mock + lateinit var auditedInteractionService: AuditedInteractionService + @MockBean lateinit var telemetryService: TelemetryService + @MockBean + lateinit var referenceDataRepository: ReferenceDataRepository + + @MockBean + lateinit var courtRepository: CourtRepository + + @SpyBean + lateinit var personRepository: PersonRepository + + @SpyBean + lateinit var personService: PersonService + @Test - fun `message is logged to telemetry`() { - // Given a message - val notification = Notification(message = MessageGenerator.EXAMPLE) + fun `Message is logged to telemetry`() { + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) + channelManager.getChannel(queueName).publishAndWait(notification) + verify(telemetryService, atLeastOnce()).notificationReceived(notification) + } - // When it is received - try { + @Test + fun `When a probation search match is detected then a person is not inserted`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-single-result.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) + channelManager.getChannel(queueName).publishAndWait(notification) + verify(personService, never()).insertPerson(any(), any()) + verify(personRepository, never()).save(any()) + verify(auditedInteractionService, Mockito.never()).createAuditedInteraction( + any(), + any(), + any(), + any(), + anyOrNull() + ) + } + + @Test + fun `When a person is 10 years old or under a person is not inserted`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-no-results.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_VALIDATION_ERROR) + val exception = assertThrows { channelManager.getChannel(queueName).publishAndWait(notification) - } catch (_: TimeoutException) { - // Note: Remove this try/catch when the MessageListener logic has been implemented } - // Then it is logged to telemetry - verify(telemetryService, atLeastOnce()).notificationReceived(notification) + assert(exception.message!!.contains("Date of birth would indicate person is under ten years old")) + + verify(personService, never()).insertPerson(any(), any()) + verify(personRepository, never()).save(any()) + verify(auditedInteractionService, Mockito.never()) + .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) + } + + @Test + fun `When a probation search match is not detected then a person is inserted`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-no-results.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) + channelManager.getChannel(queueName).publishAndWait(notification) + + verify(personService).insertPerson(any(), any()) + + verify(personRepository).save(check { + assertThat(it.forename, Matchers.equalTo("Example First Name")) + assertThat(it.surname, Matchers.equalTo("Example Last Name")) + }) + verify(auditedInteractionService).createAuditedInteraction( + eq(BusinessInteractionCode.INSERT_PERSON), + any(), + any(), + any(), + anyOrNull() + ) } -} +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/RestClientConfig.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/RestClientConfig.kt index d81e4461ed..9341e1a5a1 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/RestClientConfig.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/RestClientConfig.kt @@ -5,17 +5,12 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.web.client.RestClient import uk.gov.justice.digital.hmpps.config.security.createClient -import uk.gov.justice.digital.hmpps.integrations.example.ExampleClient +import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient @Configuration class RestClientConfig(private val oauth2Client: RestClient) { @Bean - fun exampleClient(@Value("\${integrations.example.url}") apiBaseUrl: String): ExampleClient { - return createClient( - oauth2Client.mutate() - .baseUrl(apiBaseUrl) - .build() - ) - } + fun probationSearchClient(@Value("\${integrations.probation-search.url}") apiBaseUrl: String): ProbationSearchClient = + createClient(oauth2Client.mutate().baseUrl(apiBaseUrl).build()) } diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/client/ProbationSearchClient.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/client/ProbationSearchClient.kt new file mode 100644 index 0000000000..4824a83091 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/client/ProbationSearchClient.kt @@ -0,0 +1,53 @@ +package uk.gov.justice.digital.hmpps.integrations.client + +import com.fasterxml.jackson.annotation.JsonFormat +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.service.annotation.PostExchange +import java.time.LocalDate + +interface ProbationSearchClient { + @PostExchange(url = "/match") + fun match(@RequestBody body: ProbationMatchRequest): ProbationMatchResponse +} + +data class ProbationMatchRequest( + val firstName: String, + val surname: String, + @JsonFormat(pattern = "yyyy-MM-dd") + val dateOfBirth: LocalDate, + val nomsNumber: String? = null, + val activeSentence: Boolean = false, + val pncNumber: String? = null, + val croNumber: String? = null, +) + +data class ProbationMatchResponse( + val matches: List, + val matchedBy: String, +) + +data class OffenderMatch( + val offender: OffenderDetail, +) + +data class OffenderDetail( + val otherIds: IDs, + val previousSurname: String? = null, + val title: String? = null, + val firstName: String? = null, + val middleNames: List? = null, + val surname: String? = null, + val dateOfBirth: LocalDate? = null, + val gender: String? = null, + val currentDisposal: String? = null, +) + +data class IDs( + val crn: String, + val pncNumber: String? = null, + val croNumber: String? = null, + val niNumber: String? = null, + val nomsNumber: String? = null, + val immigrationNumber: String? = null, + val mostRecentPrisonerNumber: String? = null, +) \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt new file mode 100644 index 0000000000..a4ea180eac --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt @@ -0,0 +1,7 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.audit + +import uk.gov.justice.digital.hmpps.audit.InteractionCode + +enum class BusinessInteractionCode(override val code: String) : InteractionCode { + INSERT_PERSON("OIBI025") +} diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt new file mode 100644 index 0000000000..04a4929bb3 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt @@ -0,0 +1,40 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity + +import jakarta.persistence.* +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 java.time.ZonedDateTime + +@Entity +@Table(name = "equality") +@SequenceGenerator(name = "equality_id_seq", sequenceName = "equality_id_seq", allocationSize = 1) +class Equality( + @Id + @Column(name = "equality_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "equality_id_seq") + val id: Long? = null, + + @Column(name = "offender_id") + val personId: Long, + + @CreatedBy + var createdByUserId: Long = 0, + + @CreatedDate + var createdDatetime: ZonedDateTime = ZonedDateTime.now(), + + @LastModifiedBy + var lastUpdatedUserId: Long = 0, + + @LastModifiedDate + var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now(), + + @Column + val softDeleted: Boolean, + + @Column + @Version + val rowVersion: Long = 0L +) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt new file mode 100644 index 0000000000..508b67bfe6 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt @@ -0,0 +1,67 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity + +import jakarta.persistence.* +import org.hibernate.annotations.SQLRestriction +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 java.time.LocalDate +import java.time.ZonedDateTime + +@Entity +@Table(name = "offender") +@SQLRestriction("soft_deleted = 0") +@SequenceGenerator(name = "offender_id_seq", sequenceName = "offender_id_seq", allocationSize = 1) +@EntityListeners(AuditingEntityListener::class) +class Person( + @Id + @Column(name = "offender_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "offender_id_seq") + val id: Long? = null, + + @Column(columnDefinition = "char(7)") + val crn: String, + + @Column + val croNumber: String? = null, + + @Column(columnDefinition = "char(13)") + val pncNumber: String? = null, + + @Column(name = "first_name", length = 35) + val forename: String, + + @Column(name = "second_name", length = 35) + val secondName: String? = null, + + @Column(name = "surname", length = 35) + val surname: String, + + @Column(name = "date_of_birth_date") + val dateOfBirth: LocalDate, + + @ManyToOne + @JoinColumn(name = "gender_id") + val gender: ReferenceData, + + @Column(columnDefinition = "number") + val softDeleted: Boolean = false, + + @Column + @Version + val rowVersion: Long = 0L, + + @CreatedDate + var createdDatetime: ZonedDateTime = ZonedDateTime.now(), + + @LastModifiedDate + var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now(), + + @CreatedBy + var createdByUserId: Long = 0, + + @LastModifiedBy + var lastUpdatedUserId: Long = 0, +) \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt new file mode 100644 index 0000000000..ab719be0a5 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt @@ -0,0 +1,104 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.SQLRestriction +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 java.time.LocalDate +import java.time.LocalDateTime +import java.time.ZonedDateTime + +@Entity +@Table(name = "offender_manager") +@SQLRestriction("soft_deleted = 0 and active_flag = 1") +@SequenceGenerator(name = "offender_manager_id_seq", sequenceName = "offender_manager_id_seq", allocationSize = 1) +class PersonManager( + @Id + @Column(name = "offender_manager_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "offender_id_seq") + val id: Long? = null, + + @Column(name = "allocation_date") + val allocationDate: LocalDateTime, + + @ManyToOne + @JoinColumn(name = "allocation_reason_id") + val allocationReason: ReferenceData, + + @Column(name = "end_date") + val endDate: LocalDate? = null, + + @ManyToOne + @JoinColumn(name = "offender_id") + val person: Person, + + @Version + @Column(name = "row_version") + val version: Long = 0, + + @Column(name = "soft_deleted", columnDefinition = "number") + val softDeleted: Boolean = false, + + @ManyToOne + @JoinColumn(name = "allocation_staff_id") + val staff: Staff, + + @Column(name = "staff_employee_id") + val staffEmployeeID: Long, + + @ManyToOne + @JoinColumn(name = "team_id") + val team: Team, + + @Column(name = "trust_provider_team_id") + val trustProviderTeamId: Long, + + @ManyToOne + @JoinColumn(name = "probation_area_id") + val provider: Provider, + + @Column(name = "active_flag", columnDefinition = "number") + val active: Boolean = true, + + @CreatedDate + var createdDatetime: ZonedDateTime = ZonedDateTime.now(), + + @LastModifiedDate + var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now(), + + @CreatedBy + var createdByUserId: Long = 0, + + @LastModifiedBy + var lastUpdatedUserId: Long = 0, +) + +@Immutable +@Entity +@Table(name = "staff") +class Staff( + @Id + @Column(name = "staff_id") + val id: Long, + + @Column(name = "officer_code", columnDefinition = "char(7)") + val code: String, +) + +@Immutable +@Entity +@Table(name = "team") +class Team( + @Id + @Column(name = "team_id") + val id: Long = 0, + + @Column(columnDefinition = "char(6)") + val code: String, + + @Column + val description: String, +) \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt new file mode 100644 index 0000000000..2c2c167075 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt @@ -0,0 +1,113 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.hibernate.type.YesNoConverter +import java.time.LocalDate + +@Entity +@Immutable +@Table(name = "r_standard_reference_list") +class ReferenceData( + @Id + @Column(name = "standard_reference_list_id", nullable = false) + val id: Long, + + @Column(name = "code_value", length = 100, nullable = false) + val code: String, + + @Column(name = "reference_data_master_id", nullable = false) + val datasetId: Long, + + @Column(name = "code_description", length = 500, nullable = false) + val description: String, +) { + enum class GenderCode(val commonPlatformValue: String, val deliusValue: String) { + MALE("MALE", "M"), + FEMALE("FEMALE", "F"), + OTHER("OTHER", "O"), + NOT_KNOWN("NOT KNOWN", "N") + } + + enum class AllocationCode(val code: String) { + INITIAL_ALLOCATION("IN1") + } +} + +@Immutable +@Entity +@Table(name = "r_reference_data_master") +class Dataset( + @Id + @Column(name = "reference_data_master_id") + val id: Long, + + @Convert(converter = DatasetCodeConverter::class) + @Column(name = "code_set_name", nullable = false) + val code: DatasetCode +) + +enum class DatasetCode(val value: String) { + OM_ALLOCATION_REASON("OM ALLOCATION REASON"), + GENDER("GENDER"); + + companion object { + private val index = DatasetCode.entries.associateBy { it.value } + fun fromString(value: String): DatasetCode = + index[value] ?: throw IllegalArgumentException("Invalid DatasetCode") + } +} + +@Converter +class DatasetCodeConverter : AttributeConverter { + override fun convertToDatabaseColumn(attribute: DatasetCode): String = attribute.value + + override fun convertToEntityAttribute(dbData: String): DatasetCode = DatasetCode.fromString(dbData) +} + +@Entity +@Immutable +@Table(name = "probation_area") +class Provider( + @Id + @Column(name = "probation_area_id") + val id: Long, + + @Column(name = "code", columnDefinition = "char(3)") + val code: String, + + @Column + val description: String, + + @Convert(converter = YesNoConverter::class) + val selectable: Boolean = true, + + @Column + val endDate: LocalDate? = null +) + +@Entity +@Immutable +@Table(name = "court") +class Court( + @Id + @Column(name = "court_id", nullable = false) + val id: Long, + + @Column(name = "code", length = 6, nullable = false) + val code: String, + + @Convert(converter = YesNoConverter::class) + val selectable: Boolean = true, + + @Column(name = "code_description", length = 80) + val courtName: String, + + @ManyToOne + @JoinColumn(name = "probation_area_id") + val probationArea: Provider, +) { + enum class CourtCode(val commonPlatformValue: String, val deliusValue: String) { + TEST("A00AA00", "UNKNCT") + } +} diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt new file mode 100644 index 0000000000..c8c263cb26 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt @@ -0,0 +1,6 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository + +import org.springframework.data.jpa.repository.JpaRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality + +interface EqualityRepository : JpaRepository \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt new file mode 100644 index 0000000000..fe0df47a88 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt @@ -0,0 +1,16 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository + +import org.springframework.data.jpa.repository.JpaRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManager +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Staff +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Team + +interface PersonManagerRepository : JpaRepository + +interface TeamRepository : JpaRepository { + fun findByCode(code: String): Team +} + +interface StaffRepository : JpaRepository { + fun findByCode(code: String): Staff +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt new file mode 100644 index 0000000000..2551bba051 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt @@ -0,0 +1,7 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository + +import org.springframework.data.jpa.repository.JpaRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person + +interface PersonRepository : JpaRepository + diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt new file mode 100644 index 0000000000..8fbd8d8bf7 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt @@ -0,0 +1,29 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import uk.gov.justice.digital.hmpps.exception.NotFoundException +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Court +import uk.gov.justice.digital.hmpps.integrations.delius.entity.DatasetCode +import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData + +interface ReferenceDataRepository : JpaRepository { + fun findByCode(code: String): ReferenceData + + @Query( + """ + select rd from ReferenceData rd + join Dataset ds on rd.datasetId = ds.id + where ds.code = :datasetCode and rd.code = :code + """ + ) + fun findByCodeAndDatasetCode(code: String, datasetCode: DatasetCode): ReferenceData? +} + +fun ReferenceDataRepository.initialAllocationReason() = + findByCodeAndDatasetCode(ReferenceData.AllocationCode.INITIAL_ALLOCATION.code, DatasetCode.OM_ALLOCATION_REASON) + ?: throw NotFoundException("Allocation Reason", "code", ReferenceData.AllocationCode.INITIAL_ALLOCATION.code) + +interface CourtRepository : JpaRepository { + fun findByCode(code: String): Court +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/example/ExampleClient.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/example/ExampleClient.kt deleted file mode 100644 index c164d63afd..0000000000 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/example/ExampleClient.kt +++ /dev/null @@ -1,9 +0,0 @@ -package uk.gov.justice.digital.hmpps.integrations.example - -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.service.annotation.GetExchange - -interface ExampleClient { - @GetExchange(value = "/example/{inputId}") - fun getExampleAPICall(@PathVariable("inputId") inputId: String): String -} diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt new file mode 100644 index 0000000000..05dc305ccf --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt @@ -0,0 +1,112 @@ +package uk.gov.justice.digital.hmpps.messaging + +import org.openfolder.kotlinasyncapi.annotation.channel.Message +import java.time.LocalDate +import java.time.ZonedDateTime + +@Message +data class CommonPlatformHearing( + val hearing: Hearing +) + +data class Hearing( + val id: String, + val courtCentre: CourtCentre, + val type: HearingType, + val jurisdictionType: String, + val hearingDays: List, + val prosecutionCases: List +) + +data class ProsecutionCase( + val id: String, + val initiationCode: String, + val prosecutionCaseIdentifier: ProsecutionCaseIdentifier, + val defendants: List, + val caseStatus: String, + val caseMarkers: List = emptyList() +) + +data class ProsecutionCaseIdentifier( + val prosecutionAuthorityCode: String, + val prosecutionAuthorityId: String, + val caseURN: String +) + +data class Defendant( + val id: String, + val offences: List, + val prosecutionCaseId: String, + val personDefendant: PersonDefendant?, + val legalEntityDefendant: Any? = null, + val masterDefendantId: String, + val pncId: String, + val croNumber: String +) + +data class Offence( + val id: String, + val offenceDefinitionId: String, + val offenceCode: String, + val offenceTitle: String, + val wording: String, + val offenceLegislation: String, + val listingNumber: Int, + val judicialResults: List = emptyList(), + val plea: Any? = null, + val verdict: Any? = null +) + +data class PersonDefendant( + val personDetails: PersonDetails +) + +data class PersonDetails( + val gender: String, + val lastName: String, + val middleName: String? = null, + val firstName: String, + val dateOfBirth: LocalDate, + val address: Address, + val contact: Contact, + val ethnicity: Ethnicity +) + +data class Address( + val address1: String, + val address2: String, + val address3: String, + val address4: String? = null, + val address5: String? = null, + val postcode: String +) + +data class Contact( + val home: String? = null, + val mobile: String, + val work: String? = null +) + +data class HearingType( + val id: String, + val description: String, + val welshDescription: String? = null +) + +data class Ethnicity( + val observedEthnicityDescription: String, + val selfDefinedEthnicityDescription: String +) + +data class CourtCentre( + val id: String, + val code: String, + val roomId: String, + val roomName: String +) + +data class HearingDay( + val sittingDay: ZonedDateTime, + val listedDurationMinutes: Int, + val listingSequence: Int +) \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Converter.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Converter.kt new file mode 100644 index 0000000000..cdb5725335 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Converter.kt @@ -0,0 +1,22 @@ +package uk.gov.justice.digital.hmpps.messaging + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.springframework.context.annotation.Primary +import org.springframework.stereotype.Component +import uk.gov.justice.digital.hmpps.converter.NotificationConverter +import uk.gov.justice.digital.hmpps.message.Notification + +@Primary +@Component +class Converter(objectMapper: ObjectMapper) : NotificationConverter(objectMapper) { + override fun getMessageType() = CommonPlatformHearing::class + + override fun fromMessage(message: String): Notification { + val stringMessage = objectMapper.readValue(message, jacksonTypeRef>()) + return Notification( + message = objectMapper.readValue(stringMessage.message, CommonPlatformHearing::class.java), + attributes = stringMessage.attributes + ) + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 1411b9fb01..94002e9446 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -1,29 +1,110 @@ 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.Publish +import org.slf4j.Logger +import org.slf4j.LoggerFactory import org.springframework.stereotype.Component import uk.gov.justice.digital.hmpps.converter.NotificationConverter -import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent +import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchRequest +import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Court +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData +import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.ReferenceDataRepository import uk.gov.justice.digital.hmpps.message.Notification -import uk.gov.justice.digital.hmpps.telemetry.TelemetryService +import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived +import uk.gov.justice.digital.hmpps.telemetry.TelemetryService +import java.time.LocalDate +import java.time.Period @Component @Channel("common-platform-and-delius-queue") class Handler( - override val converter: NotificationConverter, - private val telemetryService: TelemetryService -) : NotificationHandler { - @Publish( - messages = [ - // TODO list the event types here that this service will subscribe to. For example, - // Message(name = "approved-premises/application-assessed"), - // Message(title = "probation-case.prison-identifier.added"), - ] - ) - override fun handle(notification: Notification) { + override val converter: NotificationConverter, + private val telemetryService: TelemetryService, + private val personService: PersonService, + private val referenceDataRepository: ReferenceDataRepository, + private val probationSearchClient: ProbationSearchClient +) : NotificationHandler { + + @Publish(messages = [Message(title = "COMMON_PLATFORM_HEARING", payload = Schema(CommonPlatformHearing::class))]) + override fun handle(notification: Notification) { telemetryService.notificationReceived(notification) - TODO("Not yet implemented") + + val dateOfBirth = notification.message.hearing.prosecutionCases + .firstOrNull()?.defendants?.firstOrNull() + ?.personDefendant?.personDetails?.dateOfBirth + ?: throw IllegalArgumentException("Date of birth not found in message") + + // Under 10 years old validation + dateOfBirth.let { + val age = Period.between(it, LocalDate.now()).years + require(age > 10) { + "Date of birth would indicate person is under ten years old: $it" + } + } + + val defendant = notification.message.hearing.prosecutionCases.firstOrNull()?.defendants?.firstOrNull() + ?: throw IllegalArgumentException("No prosecution cases found") + val courtCode = notification.message.hearing.courtCentre.code.toDeliusCourtCode() + + val matchRequest = notification.message.toProbationMatchRequest() + val matchedPersonResponse = probationSearchClient.match(matchRequest) + + if (matchedPersonResponse.matches.isNotEmpty()) { + log.debug("Matching offender(s) found for: {}", matchRequest) + return + } + personService.insertPerson(defendant.toPerson(), courtCode) + } + + companion object { + val log: Logger = LoggerFactory.getLogger(this::class.java) + } + + fun Defendant.toPerson(): Person { + val personDetails = personDefendant?.personDetails ?: throw IllegalArgumentException("No person found") + val genderCode = personDetails.gender.toDeliusGender() + + return Person( + id = null, + crn = personService.generateCrn(), + croNumber = this.croNumber, + pncNumber = this.pncId, + forename = personDetails.firstName, + secondName = personDetails.middleName, + surname = personDetails.lastName, + dateOfBirth = personDetails.dateOfBirth, + gender = referenceDataRepository.findByCode(genderCode), + softDeleted = false + ) + } + + fun CommonPlatformHearing.toProbationMatchRequest(): ProbationMatchRequest { + val defendant = this.hearing.prosecutionCases.firstOrNull()?.defendants?.firstOrNull() + val personDetails = + defendant?.personDefendant?.personDetails ?: throw IllegalArgumentException("Person details are required") + return ProbationMatchRequest( + firstName = personDetails.firstName, + surname = personDetails.lastName, + dateOfBirth = personDetails.dateOfBirth, + pncNumber = defendant.pncId, + croNumber = defendant.croNumber + ) } + + fun String.toDeliusGender() = ReferenceData.GenderCode.entries.find { it.commonPlatformValue == this }?.deliusValue + ?: throw IllegalStateException("Gender not found: $this") + + fun String.toDeliusCourtCode() = Court.CourtCode.entries.find { it.commonPlatformValue == this }?.deliusValue + ?: throw IllegalStateException("Court not found: $this") } + + + + + diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt new file mode 100644 index 0000000000..c748248fe0 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -0,0 +1,81 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.jdbc.core.SqlOutParameter +import org.springframework.jdbc.core.simple.SimpleJdbcCall +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import uk.gov.justice.digital.hmpps.audit.service.AuditableService +import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService +import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManager +import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.* +import java.sql.Types +import java.time.LocalDateTime + +@Service +class PersonService( + jdbcTemplate: JdbcTemplate, + auditedInteractionService: AuditedInteractionService, + private val personRepository: PersonRepository, + private val courtRepository: CourtRepository, + private val equalityRepository: EqualityRepository, + private val personManagerRepository: PersonManagerRepository, + private val teamRepository: TeamRepository, + private val staffRepository: StaffRepository, + private val referenceDataRepository: ReferenceDataRepository, +) : AuditableService(auditedInteractionService) { + + private val generateCrn = SimpleJdbcCall(jdbcTemplate) + .withCatalogName("offender_support_api") + .withProcedureName("getNextCRN") + .withoutProcedureColumnMetaDataAccess() + .declareParameters( + SqlOutParameter("CRN", Types.VARCHAR) + ) + + @Transactional + fun insertPerson(person: Person, courtCode: String) = audit(BusinessInteractionCode.INSERT_PERSON) { audit -> + // Person record + val savedPerson = personRepository.save(person) + + val courtLinkedProvider = courtRepository.findByCode(courtCode).probationArea + val initialAllocation = referenceDataRepository.initialAllocationReason() + val unallocatedTeam = teamRepository.findByCode(courtLinkedProvider.code + "UAT") + val unallocatedStaff = staffRepository.findByCode(unallocatedTeam.code + "U") + + // Person manager record + val manager = PersonManager( + person = savedPerson, + staff = unallocatedStaff, + team = unallocatedTeam, + provider = courtLinkedProvider, + softDeleted = false, + active = true, + allocationReason = initialAllocation, + staffEmployeeID = unallocatedStaff.id, + trustProviderTeamId = unallocatedTeam.id, + allocationDate = LocalDateTime.of(1900, 1, 1, 0, 0) + + ) + personManagerRepository.save(manager) + + // Equality record + val equality = Equality( + id = null, + personId = savedPerson.id!!, + softDeleted = false, + ) + + equalityRepository.save(equality) + + audit["offenderId"] = savedPerson.id + true + } + + fun generateCrn(): String { + return generateCrn.execute()["CRN"] as String + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/resources/application.yml b/projects/common-platform-and-delius/src/main/resources/application.yml index 7a2d427f19..9d57424855 100644 --- a/projects/common-platform-and-delius/src/main/resources/application.yml +++ b/projects/common-platform-and-delius/src/main/resources/application.yml @@ -46,7 +46,10 @@ server.shutdown: immediate spring: datasource.url: jdbc:h2:file:./dev;MODE=Oracle;DEFAULT_NULL_ORDERING=HIGH;AUTO_SERVER=true;AUTO_SERVER_PORT=9092 - jpa.hibernate.ddl-auto: create-drop + sql.init.mode: always + sql.init.data-locations: classpath:db/h2.sql + jpa: + hibernate.ddl-auto: create-drop seed.database: true wiremock.enabled: true @@ -55,8 +58,7 @@ context.initializer.classes: uk.gov.justice.digital.hmpps.wiremock.WireMockIniti messaging.consumer.queue: message-queue integrations: - example: - url: http://localhost:${wiremock.port}/example + probation-search.url: http://localhost:${wiremock.port}/probation-search oauth2: client-id: common-platform-and-delius diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 5345a539df..448ff172e6 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -8,10 +8,9 @@ import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.verify import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator -import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent import uk.gov.justice.digital.hmpps.message.Notification -import uk.gov.justice.digital.hmpps.telemetry.TelemetryService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived +import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @ExtendWith(MockitoExtension::class) internal class HandlerTest { @@ -19,24 +18,15 @@ internal class HandlerTest { lateinit var telemetryService: TelemetryService @Mock - lateinit var converter: NotificationConverter + lateinit var converter: NotificationConverter @InjectMocks lateinit var handler: Handler @Test fun `message is logged to telemetry`() { - // Given a message - val notification = Notification(message = MessageGenerator.EXAMPLE) - - // When it is received - try { - handler.handle(notification) - } catch (_: NotImplementedError) { - // Note: Remove this try/catch when the Handler logic has been implemented - } - - // Then it is logged to telemetry + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) + handler.handle(notification) verify(telemetryService).notificationReceived(notification) } } diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt new file mode 100644 index 0000000000..36d8d7de03 --- /dev/null +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt @@ -0,0 +1,99 @@ +package uk.gov.justice.digital.hmpps.service + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.anyString +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.whenever +import org.springframework.jdbc.core.JdbcTemplate +import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService +import uk.gov.justice.digital.hmpps.data.generator.* +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManager +import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.* +import java.time.LocalDateTime + +@ExtendWith(MockitoExtension::class) +class PersonServiceTest { + @Mock + lateinit var auditedInteractionService: AuditedInteractionService + + @Mock + private lateinit var personRepository: PersonRepository + + @Mock + private lateinit var courtRepository: CourtRepository + + @Mock + private lateinit var equalityRepository: EqualityRepository + + @Mock + private lateinit var personManagerRepository: PersonManagerRepository + + @Mock + private lateinit var teamRepository: TeamRepository + + @Mock + private lateinit var staffRepository: StaffRepository + + @Mock + private lateinit var referenceDataRepository: ReferenceDataRepository + + @Mock + private lateinit var jdbcTemplate: JdbcTemplate + + @InjectMocks + private lateinit var personService: PersonService + + @Test + fun `insert person successfully inserts person, person manager and equality records`() { + val person = PersonGenerator.DEFAULT + val savedPerson = PersonGenerator.generate("A000002") + val court = CourtGenerator.UNKNOWN_COURT_N07_PROVIDER + val unallocatedTeam = TeamGenerator.UNALLOCATED + val unallocatedStaff = StaffGenerator.UNALLOCATED + val initialAllocation = ReferenceDataGenerator.INITIAL_ALLOCATION + + whenever(personRepository.save(person)).thenReturn(savedPerson) + whenever(courtRepository.findByCode(anyString())).thenReturn(court) + whenever(referenceDataRepository.findByCodeAndDatasetCode(anyString(), any())).thenReturn(initialAllocation) + whenever(teamRepository.findByCode(anyString())).thenReturn(unallocatedTeam) + whenever(staffRepository.findByCode(anyString())).thenReturn(unallocatedStaff) + + personService.insertPerson(person, court.code) + + verify(personRepository).save(person) + verify(personManagerRepository).save(any()) + verify(equalityRepository).save(any()) + + // Verify person record is saved successfully + val personCaptor = argumentCaptor() + verify(personRepository).save(personCaptor.capture()) + assertEquals(person.forename, personCaptor.firstValue.forename) + assertEquals(person.surname, personCaptor.firstValue.surname) + assertEquals(person.gender, personCaptor.firstValue.gender) + + // Verify manager record is saved successfully + val managerCaptor = argumentCaptor() + verify(personManagerRepository).save(managerCaptor.capture()) + assertEquals(savedPerson, managerCaptor.firstValue.person) + assertEquals(unallocatedStaff, managerCaptor.firstValue.staff) + assertEquals(unallocatedTeam, managerCaptor.firstValue.team) + assertEquals(court.probationArea, managerCaptor.firstValue.provider) + assertEquals(LocalDateTime.of(1900, 1, 1, 0, 0), managerCaptor.firstValue.allocationDate) + + // Verify equality is created successfully + val equalityCaptor = argumentCaptor() + verify(equalityRepository).save(equalityCaptor.capture()) + assertEquals(savedPerson.id, equalityCaptor.firstValue.personId) + assertFalse(equalityCaptor.firstValue.softDeleted) + } +} From 990723eb97dbef456e71a7273a85793e0985a615 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 08:11:07 +0000 Subject: [PATCH 02/17] Formatting changes --- .../justice/digital/hmpps/data/generator/MessageGenerator.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt index 6d6f4067f5..442e984f79 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt @@ -5,5 +5,6 @@ import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader object MessageGenerator { val COMMON_PLATFORM_EVENT = ResourceLoader.message("common-platform-hearing") - val COMMON_PLATFORM_EVENT_VALIDATION_ERROR = ResourceLoader.message("common-platform-hearing-validation-error") + val COMMON_PLATFORM_EVENT_VALIDATION_ERROR = + ResourceLoader.message("common-platform-hearing-validation-error") } From 9897dace43acd47cb674d2a786be2727fe6b3601 Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Wed, 16 Oct 2024 13:34:12 +0100 Subject: [PATCH 03/17] PI-2575 - Update handler tests --- .../hmpps/data/generator/MessageGenerator.kt | 3 ++ .../common-platform-hearing-no-cases.json | 29 +++++++++++++++ .../digital/hmpps/messaging/Handler.kt | 8 ++-- .../digital/hmpps/messaging/HandlerTest.kt | 37 +++++++++++++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt index 442e984f79..56a7c48749 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt @@ -7,4 +7,7 @@ object MessageGenerator { val COMMON_PLATFORM_EVENT = ResourceLoader.message("common-platform-hearing") val COMMON_PLATFORM_EVENT_VALIDATION_ERROR = ResourceLoader.message("common-platform-hearing-validation-error") + val COMMON_PLATFORM_EVENT_NO_CASES = + ResourceLoader.message("common-platform-hearing-no-cases") + } diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json new file mode 100644 index 0000000000..4ad08dbe7d --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json @@ -0,0 +1,29 @@ +{ + "Type": "Notification", + "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", + "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", + "Message": "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[]}}", + "Timestamp": "2022-07-27T14:22:08.509Z", + "SignatureVersion": "1", + "Signature": "EXAMPLE", + "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", + "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", + "MessageAttributes": { + "tracestate": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + }, + "eventType": { + "Type": "String", + "Value": "COMMON_PLATFORM_HEARING" + }, + "hearingEventType": { + "Type": "String", + "Value": "ConfirmedOrUpdated" + }, + "traceparent": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + } + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 94002e9446..dd01ae027b 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -35,6 +35,10 @@ class Handler( override fun handle(notification: Notification) { telemetryService.notificationReceived(notification) + val defendant = notification.message.hearing.prosecutionCases.firstOrNull()?.defendants?.firstOrNull() + ?: throw IllegalArgumentException("No prosecution cases found") + val courtCode = notification.message.hearing.courtCentre.code.toDeliusCourtCode() + val dateOfBirth = notification.message.hearing.prosecutionCases .firstOrNull()?.defendants?.firstOrNull() ?.personDefendant?.personDetails?.dateOfBirth @@ -48,10 +52,6 @@ class Handler( } } - val defendant = notification.message.hearing.prosecutionCases.firstOrNull()?.defendants?.firstOrNull() - ?: throw IllegalArgumentException("No prosecution cases found") - val courtCode = notification.message.hearing.courtCentre.code.toDeliusCourtCode() - val matchRequest = notification.message.toProbationMatchRequest() val matchedPersonResponse = probationSearchClient.match(matchRequest) diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 448ff172e6..0a8c1b5056 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -1,14 +1,21 @@ package uk.gov.justice.digital.hmpps.messaging import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows 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.any import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator +import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator +import uk.gov.justice.digital.hmpps.integrations.client.* +import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.ReferenceDataRepository import uk.gov.justice.digital.hmpps.message.Notification +import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -20,13 +27,43 @@ internal class HandlerTest { @Mock lateinit var converter: NotificationConverter + @Mock + lateinit var personService: PersonService + + @Mock + lateinit var referenceDataRepository: ReferenceDataRepository + + @Mock + lateinit var probationSearchClient: ProbationSearchClient + @InjectMocks lateinit var handler: Handler @Test fun `message is logged to telemetry`() { + whenever(probationSearchClient.match(any())).thenReturn(ProbationMatchResponse(matches = emptyList(), matchedBy = "NONE")) + whenever(personService.generateCrn()).thenReturn("A000001") + whenever(referenceDataRepository.findByCode("M")).thenReturn(ReferenceDataGenerator.GENDER_MALE) val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) handler.handle(notification) verify(telemetryService).notificationReceived(notification) } + + @Test + fun `exception thrown when age is under 10 years old`() { + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_VALIDATION_ERROR) + val exception = assertThrows { + handler.handle(notification) + } + assert(exception.message!!.contains("Date of birth would indicate person is under ten years old")) + } + + @Test + fun `exception thrown prosecution cases is empty`() { + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_CASES) + val exception = assertThrows { + handler.handle(notification) + } + assert(exception.message!!.contains("No prosecution cases found")) + } } From 8cffa22c7a38e5616f38a34043f9df0ba0de2c98 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 12:35:49 +0000 Subject: [PATCH 04/17] Formatting changes --- .../digital/hmpps/data/generator/MessageGenerator.kt | 1 - .../uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt index 56a7c48749..3da2c8634c 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt @@ -9,5 +9,4 @@ object MessageGenerator { ResourceLoader.message("common-platform-hearing-validation-error") val COMMON_PLATFORM_EVENT_NO_CASES = ResourceLoader.message("common-platform-hearing-no-cases") - } diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 0a8c1b5056..db3538fa50 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -41,7 +41,12 @@ internal class HandlerTest { @Test fun `message is logged to telemetry`() { - whenever(probationSearchClient.match(any())).thenReturn(ProbationMatchResponse(matches = emptyList(), matchedBy = "NONE")) + whenever(probationSearchClient.match(any())).thenReturn( + ProbationMatchResponse( + matches = emptyList(), + matchedBy = "NONE" + ) + ) whenever(personService.generateCrn()).thenReturn("A000001") whenever(referenceDataRepository.findByCode("M")).thenReturn(ReferenceDataGenerator.GENDER_MALE) val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) From 3ff62c6a0627c5a4f1c7ea57e2e903f5a1f03729 Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Wed, 16 Oct 2024 22:58:31 +0100 Subject: [PATCH 05/17] PI-2575 - Test Fixes + changed court code lookup to use nationalCourtCode db column on COURT table --- .../justice/digital/hmpps/data/DataLoader.kt | 15 ++++++--- .../generator/BusinessInteractionGenerator.kt | 13 ++++++++ .../data/generator/ReferenceDataGenerator.kt | 13 ++++++-- .../justice/digital/hmpps/IntegrationTest.kt | 33 ++++++++----------- .../delius/entity/ReferenceData.kt | 9 +++-- .../repository/ReferenceDataRepository.kt | 2 +- .../digital/hmpps/messaging/Handler.kt | 7 ++-- .../digital/hmpps/service/PersonService.kt | 3 +- .../digital/hmpps/service/ServiceTest.kt | 2 +- 9 files changed, 56 insertions(+), 41 deletions(-) create mode 100644 projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index c17997c905..f0c935eb9f 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -7,10 +7,7 @@ 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.CourtGenerator -import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator -import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator -import uk.gov.justice.digital.hmpps.data.generator.UserGenerator +import uk.gov.justice.digital.hmpps.data.generator.* import uk.gov.justice.digital.hmpps.user.AuditUserRepository @Component @@ -28,9 +25,17 @@ class DataLoader( @Transactional override fun onApplicationEvent(are: ApplicationReadyEvent) { entityManager.run { - persist(ProviderGenerator.DEFAULT) + persist(BusinessInteractionGenerator.INSERT_PERSON) + persist(DatasetGenerator.GENDER) + persist(DatasetGenerator.OM_ALLOCATION_REASON) persist(ReferenceDataGenerator.GENDER_MALE) persist(ReferenceDataGenerator.GENDER_FEMALE) + persist(ReferenceDataGenerator.INITIAL_ALLOCATION) + persist(ProviderGenerator.DEFAULT) + persist(TeamGenerator.ALLOCATED) + persist(TeamGenerator.UNALLOCATED) + persist(StaffGenerator.UNALLOCATED) + persist(StaffGenerator.ALLOCATED) persist(CourtGenerator.UNKNOWN_COURT_N07_PROVIDER) } } diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt new file mode 100644 index 0000000000..cd3f821af9 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt @@ -0,0 +1,13 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.audit.BusinessInteraction +import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode +import java.time.ZonedDateTime + +object BusinessInteractionGenerator { + val INSERT_PERSON = BusinessInteraction( + IdGenerator.getAndIncrement(), + BusinessInteractionCode.INSERT_PERSON.code, + ZonedDateTime.now().minusMonths(6) + ) +} diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt index a7b47c0c71..6dada114a3 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt @@ -22,11 +22,10 @@ object DatasetGenerator { val ALL_DATASETS = DatasetCode.entries.map { Dataset(IdGenerator.getAndIncrement(), it) }.associateBy { it.code } val GENDER = ALL_DATASETS[DatasetCode.GENDER]!! val OM_ALLOCATION_REASON = ALL_DATASETS[DatasetCode.OM_ALLOCATION_REASON]!! - fun all() = ALL_DATASETS.values } object CourtGenerator { - val UNKNOWN_COURT_N07_PROVIDER = generate(code = "UNKNCT") + val UNKNOWN_COURT_N07_PROVIDER = generate(code = "UNKNCT", nationalCourtCode = "A00AA00") fun generate( id: Long = IdGenerator.getAndIncrement(), @@ -34,5 +33,13 @@ object CourtGenerator { selectable: Boolean = true, courtName: String = "Court not known", provider: Provider = ProviderGenerator.DEFAULT, - ) = Court(id = id, code = code, selectable = selectable, courtName = courtName, probationArea = provider) + nationalCourtCode: String? = null, + ) = Court( + id = id, + code = code, + selectable = selectable, + courtName = courtName, + probationArea = provider, + nationalCourtCode = nationalCourtCode + ) } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index a75123b587..e0ba519da8 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -4,9 +4,8 @@ import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.* import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.atLeastOnce import org.mockito.kotlin.* @@ -16,13 +15,12 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.boot.test.mock.mockito.SpyBean +import uk.gov.justice.digital.hmpps.audit.entity.AuditedInteraction import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person -import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.CourtRepository import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.PersonRepository -import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.ReferenceDataRepository import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager import uk.gov.justice.digital.hmpps.service.PersonService @@ -41,17 +39,11 @@ internal class IntegrationTest { @Autowired lateinit var wireMockServer: WireMockServer - @Mock - lateinit var auditedInteractionService: AuditedInteractionService - @MockBean lateinit var telemetryService: TelemetryService - @MockBean - lateinit var referenceDataRepository: ReferenceDataRepository - - @MockBean - lateinit var courtRepository: CourtRepository + @SpyBean + lateinit var auditedInteractionService: AuditedInteractionService @SpyBean lateinit var personRepository: PersonRepository @@ -59,6 +51,11 @@ internal class IntegrationTest { @SpyBean lateinit var personService: PersonService + @BeforeEach + fun setup() { + doReturn("A000001").whenever(personService).generateCrn() + } + @Test fun `Message is logged to telemetry`() { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) @@ -92,7 +89,7 @@ internal class IntegrationTest { } @Test - fun `When a person is 10 years old or under a person is not inserted`() { + fun `When a message with no prosecution cases is found no insert is performed`() { wireMockServer.stubFor( post(urlPathEqualTo("/probation-search/match")) .willReturn( @@ -103,12 +100,9 @@ internal class IntegrationTest { ) ) - val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_VALIDATION_ERROR) - val exception = assertThrows { - channelManager.getChannel(queueName).publishAndWait(notification) - } + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_CASES) - assert(exception.message!!.contains("Date of birth would indicate person is under ten years old")) + channelManager.getChannel(queueName).publishAndWait(notification) verify(personService, never()).insertPerson(any(), any()) verify(personRepository, never()).save(any()) @@ -137,10 +131,11 @@ internal class IntegrationTest { assertThat(it.forename, Matchers.equalTo("Example First Name")) assertThat(it.surname, Matchers.equalTo("Example Last Name")) }) + verify(auditedInteractionService).createAuditedInteraction( eq(BusinessInteractionCode.INSERT_PERSON), any(), - any(), + eq(AuditedInteraction.Outcome.SUCCESS), any(), anyOrNull() ) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt index 2c2c167075..e024daefd5 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt @@ -106,8 +106,7 @@ class Court( @ManyToOne @JoinColumn(name = "probation_area_id") val probationArea: Provider, -) { - enum class CourtCode(val commonPlatformValue: String, val deliusValue: String) { - TEST("A00AA00", "UNKNCT") - } -} + + @Column(name = "national_court_code") + val nationalCourtCode: String? +) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt index 8fbd8d8bf7..6b5e376992 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt @@ -25,5 +25,5 @@ fun ReferenceDataRepository.initialAllocationReason() = ?: throw NotFoundException("Allocation Reason", "code", ReferenceData.AllocationCode.INITIAL_ALLOCATION.code) interface CourtRepository : JpaRepository { - fun findByCode(code: String): Court + fun findByNationalCourtCode(nationalCourtCode: String): Court } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index dd01ae027b..12842e538a 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -10,7 +10,6 @@ import org.springframework.stereotype.Component import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchRequest import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Court import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.ReferenceDataRepository @@ -37,7 +36,8 @@ class Handler( val defendant = notification.message.hearing.prosecutionCases.firstOrNull()?.defendants?.firstOrNull() ?: throw IllegalArgumentException("No prosecution cases found") - val courtCode = notification.message.hearing.courtCentre.code.toDeliusCourtCode() + + val courtCode = notification.message.hearing.courtCentre.code val dateOfBirth = notification.message.hearing.prosecutionCases .firstOrNull()?.defendants?.firstOrNull() @@ -99,9 +99,6 @@ class Handler( fun String.toDeliusGender() = ReferenceData.GenderCode.entries.find { it.commonPlatformValue == this }?.deliusValue ?: throw IllegalStateException("Gender not found: $this") - - fun String.toDeliusCourtCode() = Court.CourtCode.entries.find { it.commonPlatformValue == this }?.deliusValue - ?: throw IllegalStateException("Court not found: $this") } diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index c748248fe0..73a40eb76b 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -41,7 +41,7 @@ class PersonService( // Person record val savedPerson = personRepository.save(person) - val courtLinkedProvider = courtRepository.findByCode(courtCode).probationArea + val courtLinkedProvider = courtRepository.findByNationalCourtCode(courtCode).probationArea val initialAllocation = referenceDataRepository.initialAllocationReason() val unallocatedTeam = teamRepository.findByCode(courtLinkedProvider.code + "UAT") val unallocatedStaff = staffRepository.findByCode(unallocatedTeam.code + "U") @@ -72,7 +72,6 @@ class PersonService( equalityRepository.save(equality) audit["offenderId"] = savedPerson.id - true } fun generateCrn(): String { diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt index 36d8d7de03..2eb11a35e4 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt @@ -63,7 +63,7 @@ class PersonServiceTest { val initialAllocation = ReferenceDataGenerator.INITIAL_ALLOCATION whenever(personRepository.save(person)).thenReturn(savedPerson) - whenever(courtRepository.findByCode(anyString())).thenReturn(court) + whenever(courtRepository.findByNationalCourtCode(anyString())).thenReturn(court) whenever(referenceDataRepository.findByCodeAndDatasetCode(anyString(), any())).thenReturn(initialAllocation) whenever(teamRepository.findByCode(anyString())).thenReturn(unallocatedTeam) whenever(staffRepository.findByCode(anyString())).thenReturn(unallocatedStaff) From e1483b74ba7e71caca71bccf5260f11dcc6afb5c Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Fri, 18 Oct 2024 17:15:29 +0100 Subject: [PATCH 06/17] PI-2575 - Insert address logic implemented --- .../deploy/database/access.yml | 1 + .../justice/digital/hmpps/data/DataLoader.kt | 5 + .../hmpps/data/generator/AddressGenerator.kt | 24 ++++ .../generator/BusinessInteractionGenerator.kt | 5 + .../hmpps/data/generator/MessageGenerator.kt | 2 + .../data/generator/ReferenceDataGenerator.kt | 12 +- .../src/dev/resources/db/oracle.sql | 13 ++ ...common-platform-hearing-blank-address.json | 29 +++++ .../messages/common-platform-hearing.json | 2 +- .../justice/digital/hmpps/IntegrationTest.kt | 112 +++++++++++++++++- .../delius/audit/BusinessInteractionCode.kt | 3 +- .../integrations/delius/entity/Equality.kt | 3 + .../integrations/delius/entity/Person.kt | 20 +++- .../delius/entity/PersonAddress.kt | 111 +++++++++++++++++ .../delius/entity/PersonManager.kt | 13 +- .../delius/entity/ReferenceData.kt | 38 +++++- .../entity/repository/EqualityRepository.kt | 6 - .../repository/PersonManagerRepository.kt | 16 --- .../entity/repository/PersonRepository.kt | 7 -- .../repository/ReferenceDataRepository.kt | 29 ----- .../hmpps/messaging/CommonPlatformHearing.kt | 10 +- .../digital/hmpps/messaging/Handler.kt | 60 ++++++++-- .../digital/hmpps/service/AddressService.kt | 23 ++++ .../digital/hmpps/service/PersonService.kt | 8 +- .../digital/hmpps/messaging/HandlerTest.kt | 23 +++- .../hmpps/service/AddressServiceTest.kt | 42 +++++++ .../{ServiceTest.kt => PersonServiceTest.kt} | 7 +- 27 files changed, 528 insertions(+), 96 deletions(-) create mode 100644 projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt create mode 100644 projects/common-platform-and-delius/src/dev/resources/db/oracle.sql create mode 100644 projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt delete mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt delete mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt delete mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt delete mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt create mode 100644 projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt rename projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/{ServiceTest.kt => PersonServiceTest.kt} (91%) diff --git a/projects/common-platform-and-delius/deploy/database/access.yml b/projects/common-platform-and-delius/deploy/database/access.yml index 1813a0db8d..e5b1ee6307 100644 --- a/projects/common-platform-and-delius/deploy/database/access.yml +++ b/projects/common-platform-and-delius/deploy/database/access.yml @@ -8,6 +8,7 @@ database: - offender_manager - equality - audited_interaction + - address packages: - offender_support_api # for generating crn diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index f0c935eb9f..0434e94531 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -26,11 +26,16 @@ class DataLoader( override fun onApplicationEvent(are: ApplicationReadyEvent) { entityManager.run { persist(BusinessInteractionGenerator.INSERT_PERSON) + persist(BusinessInteractionGenerator.INSERT_ADDRESS) persist(DatasetGenerator.GENDER) persist(DatasetGenerator.OM_ALLOCATION_REASON) + persist(DatasetGenerator.ADDRESS_STATUS) + persist(DatasetGenerator.ADDRESS_TYPE) persist(ReferenceDataGenerator.GENDER_MALE) persist(ReferenceDataGenerator.GENDER_FEMALE) persist(ReferenceDataGenerator.INITIAL_ALLOCATION) + persist(ReferenceDataGenerator.MAIN_ADDRESS_STATUS) + persist(ReferenceDataGenerator.AWAITING_ASSESSMENT) persist(ProviderGenerator.DEFAULT) persist(TeamGenerator.ALLOCATED) persist(TeamGenerator.UNALLOCATED) diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt new file mode 100644 index 0000000000..566fadcaec --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt @@ -0,0 +1,24 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress +import java.time.LocalDate + +object AddressGenerator { + val MAIN_ADDRESS = generate(person = PersonGenerator.DEFAULT) + + fun generate( + id: Long? = IdGenerator.getAndIncrement(), + person: Person, + notes: String? = null, + postcode: String? = null, + ) = PersonAddress( + id = id, + start = LocalDate.now(), + status = ReferenceDataGenerator.MAIN_ADDRESS_STATUS, + personId = person.id!!, + notes = notes, + postcode = postcode, + type = ReferenceDataGenerator.AWAITING_ASSESSMENT + ) +} diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt index cd3f821af9..c6d09dcbaf 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/BusinessInteractionGenerator.kt @@ -10,4 +10,9 @@ object BusinessInteractionGenerator { BusinessInteractionCode.INSERT_PERSON.code, ZonedDateTime.now().minusMonths(6) ) + val INSERT_ADDRESS = BusinessInteraction( + IdGenerator.getAndIncrement(), + BusinessInteractionCode.INSERT_ADDRESS.code, + ZonedDateTime.now().minusMonths(6) + ) } diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt index 3da2c8634c..21c1aec18c 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt @@ -9,4 +9,6 @@ object MessageGenerator { ResourceLoader.message("common-platform-hearing-validation-error") val COMMON_PLATFORM_EVENT_NO_CASES = ResourceLoader.message("common-platform-hearing-no-cases") + val COMMON_PLATFORM_EVENT_BLANK_ADDRESS = + ResourceLoader.message("common-platform-hearing-blank-address") } diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt index 6dada114a3..b1946ea95b 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt @@ -1,14 +1,18 @@ package uk.gov.justice.digital.hmpps.data.generator +import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator.ADDRESS_STATUS +import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator.ADDRESS_TYPE import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator.GENDER import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator.OM_ALLOCATION_REASON import uk.gov.justice.digital.hmpps.integrations.delius.entity.* object ReferenceDataGenerator { - val GENDER_FEMALE = generate("F", GENDER.id, "Female") - val GENDER_MALE = generate("M", GENDER.id, "Male") - val INITIAL_ALLOCATION = generate("IN1", OM_ALLOCATION_REASON.id, "Initial Allocation") + val GENDER_FEMALE = generate(ReferenceData.GenderCode.FEMALE.deliusValue, GENDER.id, "Female") + val GENDER_MALE = generate(ReferenceData.GenderCode.MALE.deliusValue, GENDER.id, "Male") + val INITIAL_ALLOCATION = generate(ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, OM_ALLOCATION_REASON.id, "Initial Allocation") + val MAIN_ADDRESS_STATUS = generate(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, ADDRESS_STATUS.id, "Main") + val AWAITING_ASSESSMENT = generate(ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, ADDRESS_TYPE.id, "Awaiting Assessment") fun generate( code: String, @@ -22,6 +26,8 @@ object DatasetGenerator { val ALL_DATASETS = DatasetCode.entries.map { Dataset(IdGenerator.getAndIncrement(), it) }.associateBy { it.code } val GENDER = ALL_DATASETS[DatasetCode.GENDER]!! val OM_ALLOCATION_REASON = ALL_DATASETS[DatasetCode.OM_ALLOCATION_REASON]!! + val ADDRESS_TYPE = ALL_DATASETS[DatasetCode.ADDRESS_TYPE]!! + val ADDRESS_STATUS = ALL_DATASETS[DatasetCode.ADDRESS_STATUS]!! } object CourtGenerator { diff --git a/projects/common-platform-and-delius/src/dev/resources/db/oracle.sql b/projects/common-platform-and-delius/src/dev/resources/db/oracle.sql new file mode 100644 index 0000000000..a7ab3f64c6 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/db/oracle.sql @@ -0,0 +1,13 @@ +CREATE OR REPLACE PACKAGE offender_support_api IS + FUNCTION getNextCRN RETURN VARCHAR2; +END offender_support_api; + +GRANT EXECUTE ON offender_support_api TO delius_app_schema; + +CREATE OR REPLACE PACKAGE BODY offender_support_api IS + FUNCTION getNextCRN RETURN VARCHAR2 IS + BEGIN + RETURN 'A111111'; + END getNextCRN; +END offender_support_api; +/ \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json new file mode 100644 index 0000000000..6e9219f3a1 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json @@ -0,0 +1,29 @@ +{ + "Type": "Notification", + "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", + "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", + "Message": "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":null,\"address2\":null,\"address3\":null,\"address4\":null,\"address5\":null,\"postcode\":null},\"contact\":{\"home\":null,\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", + "Timestamp": "2022-07-27T14:22:08.509Z", + "SignatureVersion": "1", + "Signature": "EXAMPLE", + "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", + "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", + "MessageAttributes": { + "tracestate": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + }, + "eventType": { + "Type": "String", + "Value": "COMMON_PLATFORM_HEARING" + }, + "hearingEventType": { + "Type": "String", + "Value": "ConfirmedOrUpdated" + }, + "traceparent": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + } + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json index d4aa789163..73bb2c8f3e 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json @@ -2,7 +2,7 @@ "Type": "Notification", "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", - "Message" : "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":null,\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", + "Message" : "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":\"01234567890\",\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", "Timestamp": "2022-07-27T14:22:08.509Z", "SignatureVersion": "1", "Signature": "EXAMPLE", diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index e0ba519da8..109f7eadfc 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -4,6 +4,8 @@ import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.* import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mockito @@ -20,12 +22,17 @@ import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person -import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.PersonRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager +import uk.gov.justice.digital.hmpps.service.AddressService import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService +import java.time.LocalDate @AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -48,9 +55,15 @@ internal class IntegrationTest { @SpyBean lateinit var personRepository: PersonRepository + @SpyBean + lateinit var addressRepository: PersonAddressRepository + @SpyBean lateinit var personService: PersonService + @SpyBean + lateinit var addressService: AddressService + @BeforeEach fun setup() { doReturn("A000001").whenever(personService).generateCrn() @@ -64,7 +77,7 @@ internal class IntegrationTest { } @Test - fun `When a probation search match is detected then a person is not inserted`() { + fun `When a probation search match is detected no insert is performed`() { wireMockServer.stubFor( post(urlPathEqualTo("/probation-search/match")) .willReturn( @@ -79,6 +92,8 @@ internal class IntegrationTest { channelManager.getChannel(queueName).publishAndWait(notification) verify(personService, never()).insertPerson(any(), any()) verify(personRepository, never()).save(any()) + verify(addressService, never()).insertAddress(any()) + verify(addressRepository, never()).save(any()) verify(auditedInteractionService, Mockito.never()).createAuditedInteraction( any(), any(), @@ -105,11 +120,37 @@ internal class IntegrationTest { channelManager.getChannel(queueName).publishAndWait(notification) verify(personService, never()).insertPerson(any(), any()) + verify(addressService, never()).insertAddress(any()) + verify(addressRepository, never()).save(any()) verify(personRepository, never()).save(any()) verify(auditedInteractionService, Mockito.never()) .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) } + @Test + fun `When a person under 10 years old is found no insert is performed`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-no-results.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_VALIDATION_ERROR) + + channelManager.getChannel(queueName).publishAndWait(notification) + + verify(personService, never()).insertPerson(any(), any()) + verify(personRepository, never()).save(any()) + verify(addressService, never()).insertAddress(any()) + verify(addressRepository, never()).save(any()) + verify(auditedInteractionService, Mockito.never()) + .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) + } + @Test fun `When a probation search match is not detected then a person is inserted`() { wireMockServer.stubFor( @@ -130,6 +171,8 @@ internal class IntegrationTest { verify(personRepository).save(check { assertThat(it.forename, Matchers.equalTo("Example First Name")) assertThat(it.surname, Matchers.equalTo("Example Last Name")) + assertThat(it.mobileNumber, Matchers.equalTo("07000000000")) + assertThat(it.telephoneNumber, Matchers.equalTo("01234567890")) }) verify(auditedInteractionService).createAuditedInteraction( @@ -140,4 +183,69 @@ internal class IntegrationTest { anyOrNull() ) } + + @Test + fun `When a hearing with an address is received then an address record is inserted`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-no-results.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) + channelManager.getChannel(queueName).publishAndWait(notification) + + verify(addressService).insertAddress(any()) + + verify(addressRepository).save(check { + assertThat(it.start, Matchers.equalTo(LocalDate.now())) + assertNull(it.endDate) + assertNotNull(it.notes) + assertThat(it.softDeleted, Matchers.equalTo(false)) + assertThat(it.status.code, Matchers.equalTo(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code)) + assertThat(it.noFixedAbode, Matchers.equalTo(false)) + assertThat(it.type.code, Matchers.equalTo(ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code)) + assertThat(it.typeVerified, Matchers.equalTo(false)) + }) + + verify(auditedInteractionService).createAuditedInteraction( + eq(BusinessInteractionCode.INSERT_ADDRESS), + any(), + eq(AuditedInteraction.Outcome.SUCCESS), + any(), + anyOrNull() + ) + } + + @Test + fun `When a hearing with an empty address is received then an address record is not inserted`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-no-results.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_BLANK_ADDRESS) + channelManager.getChannel(queueName).publishAndWait(notification) + + verify(addressService, never()).insertAddress(any()) + + verify(addressRepository, never()).save(any()) + + verify(auditedInteractionService, never()).createAuditedInteraction( + eq(BusinessInteractionCode.INSERT_ADDRESS), + any(), + eq(AuditedInteraction.Outcome.SUCCESS), + any(), + anyOrNull() + ) + } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt index a4ea180eac..f2b5feeea2 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/audit/BusinessInteractionCode.kt @@ -3,5 +3,6 @@ package uk.gov.justice.digital.hmpps.integrations.delius.audit import uk.gov.justice.digital.hmpps.audit.InteractionCode enum class BusinessInteractionCode(override val code: String) : InteractionCode { - INSERT_PERSON("OIBI025") + INSERT_PERSON("OIBI025"), + INSERT_ADDRESS("OIBI029") } diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt index 04a4929bb3..bccf55ba36 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt @@ -5,6 +5,7 @@ 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.repository.JpaRepository import java.time.ZonedDateTime @Entity @@ -38,3 +39,5 @@ class Equality( @Version val rowVersion: Long = 0L ) + +interface EqualityRepository : JpaRepository \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt index 508b67bfe6..194f233d2b 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt @@ -7,6 +7,7 @@ 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 java.time.LocalDate import java.time.ZonedDateTime @@ -46,9 +47,24 @@ class Person( @JoinColumn(name = "gender_id") val gender: ReferenceData, + @Column(name = "telephone_number") + val telephoneNumber: String? = null, + + @Column(name = "mobile_number") + val mobileNumber: String? = null, + @Column(columnDefinition = "number") val softDeleted: Boolean = false, + @Column(name="current_disposal", columnDefinition = "number") + val currentDisposal: Boolean = false, + + @Column(name="current_restriction", columnDefinition = "number") + val currentRestriction: Boolean = false, + + @Column(name="pending_transfer", columnDefinition = "number") + val pendingTransfer: Boolean = false, + @Column @Version val rowVersion: Long = 0L, @@ -64,4 +80,6 @@ class Person( @LastModifiedBy var lastUpdatedUserId: Long = 0, -) \ No newline at end of file +) + +interface PersonRepository : JpaRepository \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt new file mode 100644 index 0000000000..13b1c09bf4 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt @@ -0,0 +1,111 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.person.entity + +import jakarta.persistence.* +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 uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData +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? = null, + + @Column(name = "start_date") + val start: LocalDate? = null, + + @Column(name = "end_date") + val endDate: LocalDate? = null, + + @Column(name = "partition_area_id", nullable = false) + val partitionAreaId: Long = 0, + + @Column(name = "soft_deleted", updatable = false, columnDefinition = "NUMBER") + val softDeleted: Boolean = false, + + @Column(name = "row_version") + @Version + val rowVersion: Long = 0L, + + @ManyToOne + @JoinColumn(name = "address_status_id") + var status: ReferenceData, + + @Convert(converter = YesNoConverter::class) + @Column(name = "no_fixed_abode") + val noFixedAbode: Boolean? = false, + + @Column(name = "offender_id") + val personId: Long, + + @Column(name = "notes", columnDefinition = "clob") + val notes: String? = null, + + @Column(name = "address_number") + val addressNumber: String? = null, + + @Column(name = "street_name") + var streetName: String? = null, + + @Column(name = "district") + var district: String? = null, + + @Column(name = "town_city") + var town: String? = null, + + @CreatedDate + @Column(nullable = false) + var createdDatetime: ZonedDateTime = ZonedDateTime.now(), + + @Column(name = "county") + var county: String? = null, + + @Column(nullable = false) + @LastModifiedDate + var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now(), + + @Column(name = "building_name") + var buildingName: String? = null, + + @Column(name = "postcode") + var postcode: String? = null, + + @Column(nullable = false) + @CreatedBy + var createdByUserId: Long = 0, + + @Column(name = "telephone_number") + val telephoneNumber: String? = null, + + @Column(nullable = false) + @LastModifiedBy + var lastUpdatedUserId: Long = 0, + + @Column(name = "awaiting_assessment", columnDefinition = "NUMBER", nullable = false) + val awaitingAssessment: Boolean = false, + + @ManyToOne + @JoinColumn(name = "address_type_id") + val type: ReferenceData, + + @Column(name = "type_verified") + @Convert(converter = YesNoConverter::class) + val typeVerified: Boolean? = false, + + @Column(name = "approved_premises_residence_id") + val approvedPremisesResidenceId: Long? = null, + ) + + +interface PersonAddressRepository : JpaRepository \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt index ab719be0a5..3a7aaa951a 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt @@ -7,6 +7,7 @@ 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.repository.JpaRepository import java.time.LocalDate import java.time.LocalDateTime import java.time.ZonedDateTime @@ -101,4 +102,14 @@ class Team( @Column val description: String, -) \ No newline at end of file +) + +interface PersonManagerRepository : JpaRepository + +interface TeamRepository : JpaRepository { + fun findByCode(code: String): Team +} + +interface StaffRepository : JpaRepository { + fun findByCode(code: String): Staff +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt index e024daefd5..4a27747ae0 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt @@ -3,6 +3,9 @@ package uk.gov.justice.digital.hmpps.integrations.delius.entity import jakarta.persistence.* import org.hibernate.annotations.Immutable import org.hibernate.type.YesNoConverter +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import uk.gov.justice.digital.hmpps.exception.NotFoundException import java.time.LocalDate @Entity @@ -29,8 +32,10 @@ class ReferenceData( NOT_KNOWN("NOT KNOWN", "N") } - enum class AllocationCode(val code: String) { - INITIAL_ALLOCATION("IN1") + enum class StandardRefDataCode(val code: String) { + INITIAL_ALLOCATION("IN1"), + ADDRESS_MAIN_STATUS("M"), + AWAITING_ASSESSMENT("A16") } } @@ -49,6 +54,8 @@ class Dataset( enum class DatasetCode(val value: String) { OM_ALLOCATION_REASON("OM ALLOCATION REASON"), + ADDRESS_STATUS("ADDRESS STATUS"), + ADDRESS_TYPE("ADDRESS TYPE"), GENDER("GENDER"); companion object { @@ -110,3 +117,30 @@ class Court( @Column(name = "national_court_code") val nationalCourtCode: String? ) + +interface ReferenceDataRepository : JpaRepository { + @Query( + """ + select rd from ReferenceData rd + join Dataset ds on rd.datasetId = ds.id + where ds.code = :datasetCode and rd.code = :code + """ + ) + fun findByCodeAndDatasetCode(code: String, datasetCode: DatasetCode): ReferenceData? +} + +fun ReferenceDataRepository.initialAllocationReason() = + findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, DatasetCode.OM_ALLOCATION_REASON) + ?: throw NotFoundException("Allocation Reason", "code", ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code) + +fun ReferenceDataRepository.mainAddressStatus() = + findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, DatasetCode.ADDRESS_STATUS) + ?: throw NotFoundException("Address Status", "code", ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code) + +fun ReferenceDataRepository.awaitingAssessmentAddressType() = + findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, DatasetCode.ADDRESS_TYPE) + ?: throw NotFoundException("Address Type", "code", ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code) + +interface CourtRepository : JpaRepository { + fun findByNationalCourtCode(nationalCourtCode: String): Court +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt deleted file mode 100644 index c8c263cb26..0000000000 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/EqualityRepository.kt +++ /dev/null @@ -1,6 +0,0 @@ -package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository - -import org.springframework.data.jpa.repository.JpaRepository -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality - -interface EqualityRepository : JpaRepository \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt deleted file mode 100644 index fe0df47a88..0000000000 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonManagerRepository.kt +++ /dev/null @@ -1,16 +0,0 @@ -package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository - -import org.springframework.data.jpa.repository.JpaRepository -import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManager -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Staff -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Team - -interface PersonManagerRepository : JpaRepository - -interface TeamRepository : JpaRepository { - fun findByCode(code: String): Team -} - -interface StaffRepository : JpaRepository { - fun findByCode(code: String): Staff -} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt deleted file mode 100644 index 2551bba051..0000000000 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/PersonRepository.kt +++ /dev/null @@ -1,7 +0,0 @@ -package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository - -import org.springframework.data.jpa.repository.JpaRepository -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person - -interface PersonRepository : JpaRepository - diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt deleted file mode 100644 index 6b5e376992..0000000000 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/repository/ReferenceDataRepository.kt +++ /dev/null @@ -1,29 +0,0 @@ -package uk.gov.justice.digital.hmpps.integrations.delius.entity.repository - -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.data.jpa.repository.Query -import uk.gov.justice.digital.hmpps.exception.NotFoundException -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Court -import uk.gov.justice.digital.hmpps.integrations.delius.entity.DatasetCode -import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData - -interface ReferenceDataRepository : JpaRepository { - fun findByCode(code: String): ReferenceData - - @Query( - """ - select rd from ReferenceData rd - join Dataset ds on rd.datasetId = ds.id - where ds.code = :datasetCode and rd.code = :code - """ - ) - fun findByCodeAndDatasetCode(code: String, datasetCode: DatasetCode): ReferenceData? -} - -fun ReferenceDataRepository.initialAllocationReason() = - findByCodeAndDatasetCode(ReferenceData.AllocationCode.INITIAL_ALLOCATION.code, DatasetCode.OM_ALLOCATION_REASON) - ?: throw NotFoundException("Allocation Reason", "code", ReferenceData.AllocationCode.INITIAL_ALLOCATION.code) - -interface CourtRepository : JpaRepository { - fun findByNationalCourtCode(nationalCourtCode: String): Court -} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt index 05dc305ccf..176780f88e 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt @@ -68,17 +68,17 @@ data class PersonDetails( val firstName: String, val dateOfBirth: LocalDate, val address: Address, - val contact: Contact, + val contact: Contact?, val ethnicity: Ethnicity ) data class Address( - val address1: String, - val address2: String, - val address3: String, + val address1: String? = null, + val address2: String? = null, + val address3: String? = null, val address4: String? = null, val address5: String? = null, - val postcode: String + val postcode: String? = null ) data class Contact( diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 12842e538a..1bf0322248 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -10,10 +10,10 @@ import org.springframework.stereotype.Component import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchRequest import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person -import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData -import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.ReferenceDataRepository +import uk.gov.justice.digital.hmpps.integrations.delius.entity.* +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress import uk.gov.justice.digital.hmpps.message.Notification +import uk.gov.justice.digital.hmpps.service.AddressService import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -26,6 +26,7 @@ class Handler( override val converter: NotificationConverter, private val telemetryService: TelemetryService, private val personService: PersonService, + private val addressService: AddressService, private val referenceDataRepository: ReferenceDataRepository, private val probationSearchClient: ProbationSearchClient ) : NotificationHandler { @@ -34,8 +35,9 @@ class Handler( override fun handle(notification: Notification) { telemetryService.notificationReceived(notification) - val defendant = notification.message.hearing.prosecutionCases.firstOrNull()?.defendants?.firstOrNull() - ?: throw IllegalArgumentException("No prosecution cases found") + val defendants = notification.message.hearing.prosecutionCases + .flatMap { it.defendants } + .ifEmpty { throw IllegalArgumentException("No defendants found") } val courtCode = notification.message.hearing.courtCentre.code @@ -59,7 +61,31 @@ class Handler( log.debug("Matching offender(s) found for: {}", matchRequest) return } - personService.insertPerson(defendant.toPerson(), courtCode) + + defendants.forEach { defendant -> + // Insert each defendant as a person record + val savedPerson = personService.insertPerson(defendant.toPerson(), courtCode) + + val address = defendant.personDefendant?.personDetails?.address + + // Insert each defendant's address record + val savedAddress = if (address.containsInformation()) { + addressService.insertAddress( + PersonAddress( + id = null, + start = LocalDate.now(), + status = referenceDataRepository.mainAddressStatus(), + personId = savedPerson.id!!, + notes = address?.buildNotes(), + postcode = address?.postcode, + type = referenceDataRepository.awaitingAssessmentAddressType() + ) + ) + } else { + log.debug("No address found for defendant with pncId: {}", defendant.pncId) + null + } + } } companion object { @@ -77,9 +103,11 @@ class Handler( pncNumber = this.pncId, forename = personDetails.firstName, secondName = personDetails.middleName, + telephoneNumber = personDetails.contact?.home, + mobileNumber = personDetails.contact?.mobile, surname = personDetails.lastName, dateOfBirth = personDetails.dateOfBirth, - gender = referenceDataRepository.findByCode(genderCode), + gender = referenceDataRepository.findByCodeAndDatasetCode(genderCode, DatasetCode.GENDER)!!, softDeleted = false ) } @@ -99,6 +127,24 @@ class Handler( fun String.toDeliusGender() = ReferenceData.GenderCode.entries.find { it.commonPlatformValue == this }?.deliusValue ?: throw IllegalStateException("Gender not found: $this") + + fun Address?.containsInformation(): Boolean { + return this != null && listOf( + this.address1, this.address2, this.address3, + this.address4, this.address5, this.postcode + ).any { !it.isNullOrBlank() } + } + + fun Address.buildNotes(): String { + return listOf( + "Address record automatically created by common-platform-delius-service with the following information:", + "Address1: ${this.address1 ?: "N/A"}", + "Address2: ${this.address2 ?: "N/A"}", + "Address3: ${this.address3 ?: "N/A"}", + "Address4: ${this.address4 ?: "N/A"}", + "Postcode: ${this.postcode ?: "N/A"}" + ).joinToString("\n") + } } diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt new file mode 100644 index 0000000000..3cab13df31 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt @@ -0,0 +1,23 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import uk.gov.justice.digital.hmpps.audit.service.AuditableService +import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService +import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository + +@Service +class AddressService( + auditedInteractionService: AuditedInteractionService, + private val personAddressRepository: PersonAddressRepository +) : AuditableService(auditedInteractionService) { + + @Transactional + fun insertAddress(address: PersonAddress): PersonAddress = audit(BusinessInteractionCode.INSERT_ADDRESS) { audit -> + val savedAddress = personAddressRepository.save(address) + audit["offenderId"] = address.personId + savedAddress + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index 73a40eb76b..a1e45df056 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -8,10 +8,7 @@ import org.springframework.transaction.annotation.Transactional import uk.gov.justice.digital.hmpps.audit.service.AuditableService import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person -import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManager -import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.* +import uk.gov.justice.digital.hmpps.integrations.delius.entity.* import java.sql.Types import java.time.LocalDateTime @@ -37,7 +34,7 @@ class PersonService( ) @Transactional - fun insertPerson(person: Person, courtCode: String) = audit(BusinessInteractionCode.INSERT_PERSON) { audit -> + fun insertPerson(person: Person, courtCode: String): Person = audit(BusinessInteractionCode.INSERT_PERSON) { audit -> // Person record val savedPerson = personRepository.save(person) @@ -72,6 +69,7 @@ class PersonService( equalityRepository.save(equality) audit["offenderId"] = savedPerson.id + savedPerson } fun generateCrn(): String { diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index db3538fa50..65b192cdc1 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -1,5 +1,6 @@ package uk.gov.justice.digital.hmpps.messaging +import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith @@ -11,10 +12,15 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator -import uk.gov.justice.digital.hmpps.integrations.client.* -import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.ReferenceDataRepository +import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchResponse +import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient +import uk.gov.justice.digital.hmpps.integrations.delius.entity.DatasetCode +import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData +import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceDataRepository import uk.gov.justice.digital.hmpps.message.Notification +import uk.gov.justice.digital.hmpps.service.AddressService import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -30,6 +36,9 @@ internal class HandlerTest { @Mock lateinit var personService: PersonService + @Mock + lateinit var addressService: AddressService + @Mock lateinit var referenceDataRepository: ReferenceDataRepository @@ -48,7 +57,11 @@ internal class HandlerTest { ) ) whenever(personService.generateCrn()).thenReturn("A000001") - whenever(referenceDataRepository.findByCode("M")).thenReturn(ReferenceDataGenerator.GENDER_MALE) + whenever(personService.insertPerson(any(), any())).thenReturn(PersonGenerator.DEFAULT) + whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.GenderCode.MALE.deliusValue, DatasetCode.GENDER)).thenReturn(ReferenceDataGenerator.GENDER_MALE) + whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, DatasetCode.ADDRESS_STATUS)).thenReturn(ReferenceDataGenerator.MAIN_ADDRESS_STATUS) + whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, DatasetCode.ADDRESS_TYPE)).thenReturn(ReferenceDataGenerator.AWAITING_ASSESSMENT) + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) handler.handle(notification) verify(telemetryService).notificationReceived(notification) @@ -64,11 +77,11 @@ internal class HandlerTest { } @Test - fun `exception thrown prosecution cases is empty`() { + fun `exception thrown when prosecution cases is empty`() { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_CASES) val exception = assertThrows { handler.handle(notification) } - assert(exception.message!!.contains("No prosecution cases found")) + assert(exception.message!!.contains("No defendants found")) } } diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt new file mode 100644 index 0000000000..c3ce313ce3 --- /dev/null +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt @@ -0,0 +1,42 @@ +package uk.gov.justice.digital.hmpps.service + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.check +import org.mockito.kotlin.whenever +import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService +import uk.gov.justice.digital.hmpps.data.generator.AddressGenerator +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository + +@ExtendWith(MockitoExtension::class) +class AddressServiceTest { + @Mock + lateinit var auditedInteractionService: AuditedInteractionService + + @Mock + private lateinit var addressRepository: PersonAddressRepository + + @InjectMocks + private lateinit var addressService: AddressService + + @Test + fun `successfully inserts address record`() { + val mainAddress = AddressGenerator.MAIN_ADDRESS + whenever(addressRepository.save(mainAddress)).thenReturn(mainAddress) + + addressService.insertAddress(mainAddress) + + verify(addressRepository).save(check { + assertThat(it.personId, equalTo(mainAddress.personId)) + assertThat(it.start, equalTo(mainAddress.start)) + assertThat(it.status, equalTo(mainAddress.status)) + assertThat(it.type, equalTo(mainAddress.type)) + }) + } +} diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt similarity index 91% rename from projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt rename to projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt index 2eb11a35e4..487387e571 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ServiceTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt @@ -15,10 +15,7 @@ import org.mockito.kotlin.whenever import org.springframework.jdbc.core.JdbcTemplate import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.data.generator.* -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality -import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person -import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManager -import uk.gov.justice.digital.hmpps.integrations.delius.entity.repository.* +import uk.gov.justice.digital.hmpps.integrations.delius.entity.* import java.time.LocalDateTime @ExtendWith(MockitoExtension::class) @@ -64,7 +61,7 @@ class PersonServiceTest { whenever(personRepository.save(person)).thenReturn(savedPerson) whenever(courtRepository.findByNationalCourtCode(anyString())).thenReturn(court) - whenever(referenceDataRepository.findByCodeAndDatasetCode(anyString(), any())).thenReturn(initialAllocation) + whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, DatasetCode.OM_ALLOCATION_REASON)).thenReturn(initialAllocation) whenever(teamRepository.findByCode(anyString())).thenReturn(unallocatedTeam) whenever(staffRepository.findByCode(anyString())).thenReturn(unallocatedStaff) From f378f0d6a818953c49ed41ce366f2c874932febb Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:17:43 +0000 Subject: [PATCH 07/17] Formatting changes --- .../data/generator/ReferenceDataGenerator.kt | 12 +++- .../integrations/delius/entity/Person.kt | 6 +- .../delius/entity/PersonAddress.kt | 3 +- .../delius/entity/ReferenceData.kt | 11 +++- .../digital/hmpps/service/PersonService.kt | 63 ++++++++++--------- .../digital/hmpps/messaging/HandlerTest.kt | 21 ++++++- .../hmpps/service/PersonServiceTest.kt | 7 ++- 7 files changed, 78 insertions(+), 45 deletions(-) diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt index b1946ea95b..d702df66b4 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt @@ -10,9 +10,15 @@ object ReferenceDataGenerator { val GENDER_FEMALE = generate(ReferenceData.GenderCode.FEMALE.deliusValue, GENDER.id, "Female") val GENDER_MALE = generate(ReferenceData.GenderCode.MALE.deliusValue, GENDER.id, "Male") - val INITIAL_ALLOCATION = generate(ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, OM_ALLOCATION_REASON.id, "Initial Allocation") - val MAIN_ADDRESS_STATUS = generate(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, ADDRESS_STATUS.id, "Main") - val AWAITING_ASSESSMENT = generate(ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, ADDRESS_TYPE.id, "Awaiting Assessment") + val INITIAL_ALLOCATION = generate( + ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, + OM_ALLOCATION_REASON.id, + "Initial Allocation" + ) + val MAIN_ADDRESS_STATUS = + generate(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, ADDRESS_STATUS.id, "Main") + val AWAITING_ASSESSMENT = + generate(ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, ADDRESS_TYPE.id, "Awaiting Assessment") fun generate( code: String, diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt index 194f233d2b..8d1f89732e 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt @@ -56,13 +56,13 @@ class Person( @Column(columnDefinition = "number") val softDeleted: Boolean = false, - @Column(name="current_disposal", columnDefinition = "number") + @Column(name = "current_disposal", columnDefinition = "number") val currentDisposal: Boolean = false, - @Column(name="current_restriction", columnDefinition = "number") + @Column(name = "current_restriction", columnDefinition = "number") val currentRestriction: Boolean = false, - @Column(name="pending_transfer", columnDefinition = "number") + @Column(name = "pending_transfer", columnDefinition = "number") val pendingTransfer: Boolean = false, @Column diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt index 13b1c09bf4..c020a4b728 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt @@ -105,7 +105,6 @@ class PersonAddress( @Column(name = "approved_premises_residence_id") val approvedPremisesResidenceId: Long? = null, - ) - +) interface PersonAddressRepository : JpaRepository \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt index 4a27747ae0..913ad87a41 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt @@ -130,8 +130,15 @@ interface ReferenceDataRepository : JpaRepository { } fun ReferenceDataRepository.initialAllocationReason() = - findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, DatasetCode.OM_ALLOCATION_REASON) - ?: throw NotFoundException("Allocation Reason", "code", ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code) + findByCodeAndDatasetCode( + ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, + DatasetCode.OM_ALLOCATION_REASON + ) + ?: throw NotFoundException( + "Allocation Reason", + "code", + ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code + ) fun ReferenceDataRepository.mainAddressStatus() = findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, DatasetCode.ADDRESS_STATUS) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index a1e45df056..fefb382ead 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -34,43 +34,44 @@ class PersonService( ) @Transactional - fun insertPerson(person: Person, courtCode: String): Person = audit(BusinessInteractionCode.INSERT_PERSON) { audit -> - // Person record - val savedPerson = personRepository.save(person) + fun insertPerson(person: Person, courtCode: String): Person = + audit(BusinessInteractionCode.INSERT_PERSON) { audit -> + // Person record + val savedPerson = personRepository.save(person) - val courtLinkedProvider = courtRepository.findByNationalCourtCode(courtCode).probationArea - val initialAllocation = referenceDataRepository.initialAllocationReason() - val unallocatedTeam = teamRepository.findByCode(courtLinkedProvider.code + "UAT") - val unallocatedStaff = staffRepository.findByCode(unallocatedTeam.code + "U") + val courtLinkedProvider = courtRepository.findByNationalCourtCode(courtCode).probationArea + val initialAllocation = referenceDataRepository.initialAllocationReason() + val unallocatedTeam = teamRepository.findByCode(courtLinkedProvider.code + "UAT") + val unallocatedStaff = staffRepository.findByCode(unallocatedTeam.code + "U") - // Person manager record - val manager = PersonManager( - person = savedPerson, - staff = unallocatedStaff, - team = unallocatedTeam, - provider = courtLinkedProvider, - softDeleted = false, - active = true, - allocationReason = initialAllocation, - staffEmployeeID = unallocatedStaff.id, - trustProviderTeamId = unallocatedTeam.id, - allocationDate = LocalDateTime.of(1900, 1, 1, 0, 0) + // Person manager record + val manager = PersonManager( + person = savedPerson, + staff = unallocatedStaff, + team = unallocatedTeam, + provider = courtLinkedProvider, + softDeleted = false, + active = true, + allocationReason = initialAllocation, + staffEmployeeID = unallocatedStaff.id, + trustProviderTeamId = unallocatedTeam.id, + allocationDate = LocalDateTime.of(1900, 1, 1, 0, 0) - ) - personManagerRepository.save(manager) + ) + personManagerRepository.save(manager) - // Equality record - val equality = Equality( - id = null, - personId = savedPerson.id!!, - softDeleted = false, - ) + // Equality record + val equality = Equality( + id = null, + personId = savedPerson.id!!, + softDeleted = false, + ) - equalityRepository.save(equality) + equalityRepository.save(equality) - audit["offenderId"] = savedPerson.id - savedPerson - } + audit["offenderId"] = savedPerson.id + savedPerson + } fun generateCrn(): String { return generateCrn.execute()["CRN"] as String diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 65b192cdc1..0aa8fb0d94 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -58,9 +58,24 @@ internal class HandlerTest { ) whenever(personService.generateCrn()).thenReturn("A000001") whenever(personService.insertPerson(any(), any())).thenReturn(PersonGenerator.DEFAULT) - whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.GenderCode.MALE.deliusValue, DatasetCode.GENDER)).thenReturn(ReferenceDataGenerator.GENDER_MALE) - whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, DatasetCode.ADDRESS_STATUS)).thenReturn(ReferenceDataGenerator.MAIN_ADDRESS_STATUS) - whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, DatasetCode.ADDRESS_TYPE)).thenReturn(ReferenceDataGenerator.AWAITING_ASSESSMENT) + whenever( + referenceDataRepository.findByCodeAndDatasetCode( + ReferenceData.GenderCode.MALE.deliusValue, + DatasetCode.GENDER + ) + ).thenReturn(ReferenceDataGenerator.GENDER_MALE) + whenever( + referenceDataRepository.findByCodeAndDatasetCode( + ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, + DatasetCode.ADDRESS_STATUS + ) + ).thenReturn(ReferenceDataGenerator.MAIN_ADDRESS_STATUS) + whenever( + referenceDataRepository.findByCodeAndDatasetCode( + ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, + DatasetCode.ADDRESS_TYPE + ) + ).thenReturn(ReferenceDataGenerator.AWAITING_ASSESSMENT) val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) handler.handle(notification) diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt index 487387e571..c4163ab49b 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt @@ -61,7 +61,12 @@ class PersonServiceTest { whenever(personRepository.save(person)).thenReturn(savedPerson) whenever(courtRepository.findByNationalCourtCode(anyString())).thenReturn(court) - whenever(referenceDataRepository.findByCodeAndDatasetCode(ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, DatasetCode.OM_ALLOCATION_REASON)).thenReturn(initialAllocation) + whenever( + referenceDataRepository.findByCodeAndDatasetCode( + ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, + DatasetCode.OM_ALLOCATION_REASON + ) + ).thenReturn(initialAllocation) whenever(teamRepository.findByCode(anyString())).thenReturn(unallocatedTeam) whenever(staffRepository.findByCode(anyString())).thenReturn(unallocatedStaff) From b838293c020ade60ce0aa9a4dd4ecdd239ffb91b Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Mon, 21 Oct 2024 16:23:08 +0100 Subject: [PATCH 08/17] PI-2575 - Added notifier to publish sns messages (probation-case.engagement.created) when insert person is performed --- .../deploy/values.yaml | 2 + .../justice/digital/hmpps/IntegrationTest.kt | 48 +++++++++++++++++-- .../digital/hmpps/messaging/Notifier.kt | 40 ++++++++++++++++ .../digital/hmpps/service/PersonService.kt | 6 ++- .../src/main/resources/application.yml | 2 + .../digital/hmpps/messaging/HandlerTest.kt | 3 +- .../digital/hmpps/messaging/NotifierTest.kt | 35 ++++++++++++++ .../hmpps/service/PersonServiceTest.kt | 6 ++- 8 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt create mode 100644 projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt diff --git a/projects/common-platform-and-delius/deploy/values.yaml b/projects/common-platform-and-delius/deploy/values.yaml index 456c964b0f..74b48d27df 100644 --- a/projects/common-platform-and-delius/deploy/values.yaml +++ b/projects/common-platform-and-delius/deploy/values.yaml @@ -23,6 +23,8 @@ generic-service: SENTRY_DSN: SENTRY_DSN common-platform-and-delius-queue: MESSAGING_CONSUMER_QUEUE: QUEUE_NAME + hmpps-domain-events-topic: + MESSAGING_PRODUCER_TOPIC: topic_arn generic-prometheus-alerts: targetApplication: common-platform-and-delius diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 109f7eadfc..8ddd10bc57 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -4,8 +4,7 @@ import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.* import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mockito @@ -26,6 +25,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonRepository import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository +import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager import uk.gov.justice.digital.hmpps.service.AddressService @@ -40,9 +40,15 @@ internal class IntegrationTest { @Value("\${messaging.consumer.queue}") lateinit var queueName: String + @Value("\${messaging.producer.topic}") + lateinit var topicName: String + @Autowired lateinit var channelManager: HmppsChannelManager + @Autowired + lateinit var hmppsChannelManager: HmppsChannelManager + @Autowired lateinit var wireMockServer: WireMockServer @@ -66,7 +72,7 @@ internal class IntegrationTest { @BeforeEach fun setup() { - doReturn("A000001").whenever(personService).generateCrn() + doReturn("A111111").whenever(personService).generateCrn() } @Test @@ -248,4 +254,40 @@ internal class IntegrationTest { anyOrNull() ) } + + @Test + fun `engagement created message is published on insert person`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-no-results.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) + channelManager.getChannel(queueName).publishAndWait(notification) + + verify(personService).insertPerson(any(), any()) + + verify(personRepository).save(check { + assertThat(it.forename, Matchers.equalTo("Example First Name")) + assertThat(it.surname, Matchers.equalTo("Example Last Name")) + assertThat(it.mobileNumber, Matchers.equalTo("07000000000")) + assertThat(it.telephoneNumber, Matchers.equalTo("01234567890")) + }) + + val topic = hmppsChannelManager.getChannel(topicName) + val messages = topic.pollFor(1) + + val engagementCreated = messages.first { it.eventType == "probation-case.engagement.created" }.message as HmppsDomainEvent + + assertEquals("probation-case.engagement.created", engagementCreated.eventType) + assertEquals(1, engagementCreated.version) + assertEquals("A probation case record for a person has been created in Delius", engagementCreated.description) + assertEquals("A111111", engagementCreated.personReference.findCrn()!!) + assertNull(engagementCreated.detailUrl) + } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt new file mode 100644 index 0000000000..18aaed2e56 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt @@ -0,0 +1,40 @@ +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.integrations.delius.entity.Person +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.engagement.created", payload = Schema(HmppsDomainEvent::class)) + ] + ) + fun caseCreated(person: Person) { + topicPublisher.publish( + Notification( + message = HmppsDomainEvent( + version = 1, + eventType = "probation-case.engagement.created", + description = "A probation case record for a person has been created in Delius", + personReference = PersonReference( + identifiers = listOf( + PersonIdentifier("CRN", person.crn), + ), + ), + ), + attributes = MessageAttributes("probation-case.engagement.created") + ) + ) + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index fefb382ead..7455ef7e18 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -9,6 +9,7 @@ import uk.gov.justice.digital.hmpps.audit.service.AuditableService import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode import uk.gov.justice.digital.hmpps.integrations.delius.entity.* +import uk.gov.justice.digital.hmpps.messaging.Notifier import java.sql.Types import java.time.LocalDateTime @@ -16,13 +17,14 @@ import java.time.LocalDateTime class PersonService( jdbcTemplate: JdbcTemplate, auditedInteractionService: AuditedInteractionService, + private val notifier: Notifier, private val personRepository: PersonRepository, private val courtRepository: CourtRepository, private val equalityRepository: EqualityRepository, private val personManagerRepository: PersonManagerRepository, private val teamRepository: TeamRepository, private val staffRepository: StaffRepository, - private val referenceDataRepository: ReferenceDataRepository, + private val referenceDataRepository: ReferenceDataRepository ) : AuditableService(auditedInteractionService) { private val generateCrn = SimpleJdbcCall(jdbcTemplate) @@ -44,6 +46,8 @@ class PersonService( val unallocatedTeam = teamRepository.findByCode(courtLinkedProvider.code + "UAT") val unallocatedStaff = staffRepository.findByCode(unallocatedTeam.code + "U") + notifier.caseCreated(savedPerson) + // Person manager record val manager = PersonManager( person = savedPerson, diff --git a/projects/common-platform-and-delius/src/main/resources/application.yml b/projects/common-platform-and-delius/src/main/resources/application.yml index 9d57424855..52522fea63 100644 --- a/projects/common-platform-and-delius/src/main/resources/application.yml +++ b/projects/common-platform-and-delius/src/main/resources/application.yml @@ -51,6 +51,8 @@ spring: jpa: hibernate.ddl-auto: create-drop +messaging.producer.topic: domain-events + seed.database: true wiremock.enabled: true context.initializer.classes: uk.gov.justice.digital.hmpps.wiremock.WireMockInitialiser diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 0aa8fb0d94..be7b3df781 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -1,6 +1,5 @@ package uk.gov.justice.digital.hmpps.messaging -import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith @@ -56,7 +55,7 @@ internal class HandlerTest { matchedBy = "NONE" ) ) - whenever(personService.generateCrn()).thenReturn("A000001") + whenever(personService.generateCrn()).thenReturn("A111111") whenever(personService.insertPerson(any(), any())).thenReturn(PersonGenerator.DEFAULT) whenever( referenceDataRepository.findByCodeAndDatasetCode( diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt new file mode 100644 index 0000000000..07efc335b0 --- /dev/null +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt @@ -0,0 +1,35 @@ +package uk.gov.justice.digital.hmpps.messaging + +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.* +import org.springframework.boot.test.system.CapturedOutput +import org.springframework.boot.test.system.OutputCaptureExtension +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator +import uk.gov.justice.digital.hmpps.message.Notification +import uk.gov.justice.digital.hmpps.publisher.NotificationPublisher + +@ExtendWith(MockitoExtension::class) +@ExtendWith(OutputCaptureExtension::class) +class NotifierTest { + @Mock + lateinit var topicPublisher: NotificationPublisher + + lateinit var notifier: Notifier + + @BeforeEach + fun setUp() { + notifier = Notifier(topicPublisher) + } + + @Test + fun `test notification`(output: CapturedOutput) { + doNothing().whenever(topicPublisher).publish(any>()) + notifier.caseCreated(PersonGenerator.DEFAULT) + verify(topicPublisher, times(1)).publish(any>()) + verifyNoMoreInteractions(topicPublisher) + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt index c4163ab49b..4bb05c1c2a 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt @@ -16,6 +16,7 @@ import org.springframework.jdbc.core.JdbcTemplate import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.data.generator.* import uk.gov.justice.digital.hmpps.integrations.delius.entity.* +import uk.gov.justice.digital.hmpps.messaging.Notifier import java.time.LocalDateTime @ExtendWith(MockitoExtension::class) @@ -44,6 +45,9 @@ class PersonServiceTest { @Mock private lateinit var referenceDataRepository: ReferenceDataRepository + @Mock + lateinit var notifier: Notifier + @Mock private lateinit var jdbcTemplate: JdbcTemplate @@ -71,7 +75,7 @@ class PersonServiceTest { whenever(staffRepository.findByCode(anyString())).thenReturn(unallocatedStaff) personService.insertPerson(person, court.code) - + verify(notifier).caseCreated(any()) verify(personRepository).save(person) verify(personManagerRepository).save(any()) verify(equalityRepository).save(any()) From bbd9e9f190c6ccc42b9c578a8304ebfd03753955 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:24:58 +0000 Subject: [PATCH 09/17] Formatting changes --- .../kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 8ddd10bc57..cc86f17379 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -282,7 +282,8 @@ internal class IntegrationTest { val topic = hmppsChannelManager.getChannel(topicName) val messages = topic.pollFor(1) - val engagementCreated = messages.first { it.eventType == "probation-case.engagement.created" }.message as HmppsDomainEvent + val engagementCreated = + messages.first { it.eventType == "probation-case.engagement.created" }.message as HmppsDomainEvent assertEquals("probation-case.engagement.created", engagementCreated.eventType) assertEquals(1, engagementCreated.version) From f98faf3ebaaf5351e873bdc8508b430015333374 Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Wed, 23 Oct 2024 16:45:03 +0100 Subject: [PATCH 10/17] PI-2575 - Entity changes to match delius database - Removed oracle profile from application.yml --- .../hmpps/data/generator/PersonGenerator.kt | 5 +- .../data/generator/ReferenceDataGenerator.kt | 10 +- .../src/dev/resources/db/oracle.sql | 4 +- .../justice/digital/hmpps/IntegrationTest.kt | 14 +-- .../integrations/delius/entity/Equality.kt | 2 + .../integrations/delius/entity/Person.kt | 26 ++++- .../delius/entity/PersonManager.kt | 5 + .../delius/entity/ReferenceData.kt | 18 +-- .../digital/hmpps/messaging/Handler.kt | 82 ++------------ .../digital/hmpps/service/AddressService.kt | 23 ---- .../digital/hmpps/service/PersonService.kt | 89 +++++++++++++-- .../src/main/resources/application.yml | 4 - .../digital/hmpps/messaging/HandlerTest.kt | 30 ----- .../hmpps/service/AddressServiceTest.kt | 42 ------- .../hmpps/service/PersonServiceTest.kt | 105 ------------------ 15 files changed, 141 insertions(+), 318 deletions(-) delete mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt delete mode 100644 projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt delete mode 100644 projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt index 778db68c86..9054d5584f 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -18,7 +18,10 @@ object PersonGenerator { forename = UUID.randomUUID().toString().substring(0, 15), surname = UUID.randomUUID().toString().substring(0, 15), dateOfBirth = LocalDate.now().minusYears(Random.nextInt(16, 76).toLong()), - gender = if (Random.nextBoolean()) ReferenceDataGenerator.GENDER_MALE else ReferenceDataGenerator.GENDER_FEMALE + gender = if (Random.nextBoolean()) ReferenceDataGenerator.GENDER_MALE else ReferenceDataGenerator.GENDER_FEMALE, + surnameSoundex = "surnameSoundex", + firstNameSoundex = "firstNameSoundex", + middleNameSoundex = null ) } diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt index d702df66b4..82d5722d6f 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferenceDataGenerator.kt @@ -37,7 +37,7 @@ object DatasetGenerator { } object CourtGenerator { - val UNKNOWN_COURT_N07_PROVIDER = generate(code = "UNKNCT", nationalCourtCode = "A00AA00") + val UNKNOWN_COURT_N07_PROVIDER = generate(code = "UNKNCT", ouCode = "A00AA00") fun generate( id: Long = IdGenerator.getAndIncrement(), @@ -45,13 +45,13 @@ object CourtGenerator { selectable: Boolean = true, courtName: String = "Court not known", provider: Provider = ProviderGenerator.DEFAULT, - nationalCourtCode: String? = null, + ouCode: String? = null, ) = Court( id = id, code = code, selectable = selectable, - courtName = courtName, - probationArea = provider, - nationalCourtCode = nationalCourtCode + name = courtName, + provider = provider, + ouCode = ouCode ) } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/db/oracle.sql b/projects/common-platform-and-delius/src/dev/resources/db/oracle.sql index a7ab3f64c6..5f651dd9cc 100644 --- a/projects/common-platform-and-delius/src/dev/resources/db/oracle.sql +++ b/projects/common-platform-and-delius/src/dev/resources/db/oracle.sql @@ -1,10 +1,10 @@ -CREATE OR REPLACE PACKAGE offender_support_api IS +CREATE OR REPLACE PACKAGE offender_support_api AS FUNCTION getNextCRN RETURN VARCHAR2; END offender_support_api; GRANT EXECUTE ON offender_support_api TO delius_app_schema; -CREATE OR REPLACE PACKAGE BODY offender_support_api IS +CREATE OR REPLACE PACKAGE BODY offender_support_api AS FUNCTION getNextCRN RETURN VARCHAR2 IS BEGIN RETURN 'A111111'; diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index cc86f17379..1d5a2a9084 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -28,7 +28,6 @@ import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddr import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager -import uk.gov.justice.digital.hmpps.service.AddressService import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -67,9 +66,6 @@ internal class IntegrationTest { @SpyBean lateinit var personService: PersonService - @SpyBean - lateinit var addressService: AddressService - @BeforeEach fun setup() { doReturn("A111111").whenever(personService).generateCrn() @@ -97,8 +93,8 @@ internal class IntegrationTest { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) channelManager.getChannel(queueName).publishAndWait(notification) verify(personService, never()).insertPerson(any(), any()) + verify(personService, never()).insertAddress(any()) verify(personRepository, never()).save(any()) - verify(addressService, never()).insertAddress(any()) verify(addressRepository, never()).save(any()) verify(auditedInteractionService, Mockito.never()).createAuditedInteraction( any(), @@ -126,7 +122,7 @@ internal class IntegrationTest { channelManager.getChannel(queueName).publishAndWait(notification) verify(personService, never()).insertPerson(any(), any()) - verify(addressService, never()).insertAddress(any()) + verify(personService, never()).insertAddress(any()) verify(addressRepository, never()).save(any()) verify(personRepository, never()).save(any()) verify(auditedInteractionService, Mockito.never()) @@ -150,8 +146,8 @@ internal class IntegrationTest { channelManager.getChannel(queueName).publishAndWait(notification) verify(personService, never()).insertPerson(any(), any()) + verify(personService, never()).insertAddress(any()) verify(personRepository, never()).save(any()) - verify(addressService, never()).insertAddress(any()) verify(addressRepository, never()).save(any()) verify(auditedInteractionService, Mockito.never()) .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) @@ -205,7 +201,7 @@ internal class IntegrationTest { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) channelManager.getChannel(queueName).publishAndWait(notification) - verify(addressService).insertAddress(any()) + verify(personService).insertAddress(any()) verify(addressRepository).save(check { assertThat(it.start, Matchers.equalTo(LocalDate.now())) @@ -242,7 +238,7 @@ internal class IntegrationTest { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_BLANK_ADDRESS) channelManager.getChannel(queueName).publishAndWait(notification) - verify(addressService, never()).insertAddress(any()) + verify(personService, never()).insertAddress(any()) verify(addressRepository, never()).save(any()) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt index bccf55ba36..d648334960 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Equality.kt @@ -5,12 +5,14 @@ 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 java.time.ZonedDateTime @Entity @Table(name = "equality") @SequenceGenerator(name = "equality_id_seq", sequenceName = "equality_id_seq", allocationSize = 1) +@EntityListeners(AuditingEntityListener::class) class Equality( @Id @Column(name = "equality_id") diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt index 8d1f89732e..cceab59eee 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt @@ -8,6 +8,7 @@ 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 @@ -34,6 +35,15 @@ class Person( @Column(name = "first_name", length = 35) val forename: String, + @Column + val surnameSoundex: String, + + @Column + val firstNameSoundex: String, + + @Column + val middleNameSoundex: String?, + @Column(name = "second_name", length = 35) val secondName: String? = null, @@ -75,11 +85,23 @@ class Person( @LastModifiedDate var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now(), + @LastModifiedDate + var lastUpdatedDatetimeDiversit: ZonedDateTime = ZonedDateTime.now(), + + @LastModifiedBy + var lastUpdatedUserIdDiversity: Long = 0, + @CreatedBy var createdByUserId: Long = 0, @LastModifiedBy var lastUpdatedUserId: Long = 0, -) -interface PersonRepository : JpaRepository \ No newline at end of file + @Column + val partitionAreaId: Long = 0L + ) + +interface PersonRepository : JpaRepository{ + @Query("SELECT SOUNDEX(:name) FROM DUAL", nativeQuery = true) + fun getSoundex(name: String): String +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt index 3a7aaa951a..36ace96365 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonManager.kt @@ -7,6 +7,7 @@ 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 java.time.LocalDate import java.time.LocalDateTime @@ -16,6 +17,7 @@ import java.time.ZonedDateTime @Table(name = "offender_manager") @SQLRestriction("soft_deleted = 0 and active_flag = 1") @SequenceGenerator(name = "offender_manager_id_seq", sequenceName = "offender_manager_id_seq", allocationSize = 1) +@EntityListeners(AuditingEntityListener::class) class PersonManager( @Id @Column(name = "offender_manager_id") @@ -75,6 +77,9 @@ class PersonManager( @LastModifiedBy var lastUpdatedUserId: Long = 0, + + @Column + val partitionAreaId: Long = 0L ) @Immutable diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt index 913ad87a41..9b47cfb158 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt @@ -101,21 +101,21 @@ class Court( @Column(name = "court_id", nullable = false) val id: Long, - @Column(name = "code", length = 6, nullable = false) + @Column(columnDefinition = "char(6)", nullable = false) val code: String, @Convert(converter = YesNoConverter::class) val selectable: Boolean = true, - @Column(name = "code_description", length = 80) - val courtName: String, + @Column(name = "court_name", length = 80) + val name: String, @ManyToOne @JoinColumn(name = "probation_area_id") - val probationArea: Provider, + val provider: Provider, - @Column(name = "national_court_code") - val nationalCourtCode: String? + @Column(name = "court_ou_code") + val ouCode: String? ) interface ReferenceDataRepository : JpaRepository { @@ -149,5 +149,7 @@ fun ReferenceDataRepository.awaitingAssessmentAddressType() = ?: throw NotFoundException("Address Type", "code", ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code) interface CourtRepository : JpaRepository { - fun findByNationalCourtCode(nationalCourtCode: String): Court -} \ No newline at end of file + fun findByOuCode(ouCode: String): Court? +} +fun CourtRepository.getByOuCode(ouCode: String) = + findByOuCode(ouCode) ?: throw NotFoundException("Court", "ouCode", ouCode) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 1bf0322248..d4ecc80e51 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -4,16 +4,11 @@ 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.Publish -import org.slf4j.Logger -import org.slf4j.LoggerFactory import org.springframework.stereotype.Component import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchRequest import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient -import uk.gov.justice.digital.hmpps.integrations.delius.entity.* -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress import uk.gov.justice.digital.hmpps.message.Notification -import uk.gov.justice.digital.hmpps.service.AddressService import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -26,8 +21,6 @@ class Handler( override val converter: NotificationConverter, private val telemetryService: TelemetryService, private val personService: PersonService, - private val addressService: AddressService, - private val referenceDataRepository: ReferenceDataRepository, private val probationSearchClient: ProbationSearchClient ) : NotificationHandler { @@ -58,58 +51,18 @@ class Handler( val matchedPersonResponse = probationSearchClient.match(matchRequest) if (matchedPersonResponse.matches.isNotEmpty()) { - log.debug("Matching offender(s) found for: {}", matchRequest) return } - defendants.forEach { defendant -> // Insert each defendant as a person record - val savedPerson = personService.insertPerson(defendant.toPerson(), courtCode) - - val address = defendant.personDefendant?.personDetails?.address - - // Insert each defendant's address record - val savedAddress = if (address.containsInformation()) { - addressService.insertAddress( - PersonAddress( - id = null, - start = LocalDate.now(), - status = referenceDataRepository.mainAddressStatus(), - personId = savedPerson.id!!, - notes = address?.buildNotes(), - postcode = address?.postcode, - type = referenceDataRepository.awaitingAssessmentAddressType() - ) - ) - } else { - log.debug("No address found for defendant with pncId: {}", defendant.pncId) - null - } - } - } + val savedPerson = personService.insertPerson(defendant, courtCode) - companion object { - val log: Logger = LoggerFactory.getLogger(this::class.java) - } - - fun Defendant.toPerson(): Person { - val personDetails = personDefendant?.personDetails ?: throw IllegalArgumentException("No person found") - val genderCode = personDetails.gender.toDeliusGender() - - return Person( - id = null, - crn = personService.generateCrn(), - croNumber = this.croNumber, - pncNumber = this.pncId, - forename = personDetails.firstName, - secondName = personDetails.middleName, - telephoneNumber = personDetails.contact?.home, - mobileNumber = personDetails.contact?.mobile, - surname = personDetails.lastName, - dateOfBirth = personDetails.dateOfBirth, - gender = referenceDataRepository.findByCodeAndDatasetCode(genderCode, DatasetCode.GENDER)!!, - softDeleted = false - ) + telemetryService.trackEvent("PersonCreated", mapOf( + "CRN" to savedPerson.crn, + "personId" to savedPerson.id.toString(), + "hearingId" to notification.message.hearing.id) + ) + } } fun CommonPlatformHearing.toProbationMatchRequest(): ProbationMatchRequest { @@ -124,27 +77,6 @@ class Handler( croNumber = defendant.croNumber ) } - - fun String.toDeliusGender() = ReferenceData.GenderCode.entries.find { it.commonPlatformValue == this }?.deliusValue - ?: throw IllegalStateException("Gender not found: $this") - - fun Address?.containsInformation(): Boolean { - return this != null && listOf( - this.address1, this.address2, this.address3, - this.address4, this.address5, this.postcode - ).any { !it.isNullOrBlank() } - } - - fun Address.buildNotes(): String { - return listOf( - "Address record automatically created by common-platform-delius-service with the following information:", - "Address1: ${this.address1 ?: "N/A"}", - "Address2: ${this.address2 ?: "N/A"}", - "Address3: ${this.address3 ?: "N/A"}", - "Address4: ${this.address4 ?: "N/A"}", - "Postcode: ${this.postcode ?: "N/A"}" - ).joinToString("\n") - } } diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt deleted file mode 100644 index 3cab13df31..0000000000 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt +++ /dev/null @@ -1,23 +0,0 @@ -package uk.gov.justice.digital.hmpps.service - -import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional -import uk.gov.justice.digital.hmpps.audit.service.AuditableService -import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService -import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository - -@Service -class AddressService( - auditedInteractionService: AuditedInteractionService, - private val personAddressRepository: PersonAddressRepository -) : AuditableService(auditedInteractionService) { - - @Transactional - fun insertAddress(address: PersonAddress): PersonAddress = audit(BusinessInteractionCode.INSERT_ADDRESS) { audit -> - val savedAddress = personAddressRepository.save(address) - audit["offenderId"] = address.personId - savedAddress - } -} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index 7455ef7e18..7bb1900a02 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -1,7 +1,6 @@ package uk.gov.justice.digital.hmpps.service import org.springframework.jdbc.core.JdbcTemplate -import org.springframework.jdbc.core.SqlOutParameter import org.springframework.jdbc.core.simple.SimpleJdbcCall import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -9,8 +8,12 @@ import uk.gov.justice.digital.hmpps.audit.service.AuditableService import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode import uk.gov.justice.digital.hmpps.integrations.delius.entity.* +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository +import uk.gov.justice.digital.hmpps.messaging.Address +import uk.gov.justice.digital.hmpps.messaging.Defendant import uk.gov.justice.digital.hmpps.messaging.Notifier -import java.sql.Types +import java.time.LocalDate import java.time.LocalDateTime @Service @@ -24,24 +27,21 @@ class PersonService( private val personManagerRepository: PersonManagerRepository, private val teamRepository: TeamRepository, private val staffRepository: StaffRepository, - private val referenceDataRepository: ReferenceDataRepository + private val referenceDataRepository: ReferenceDataRepository, + private val personAddressRepository: PersonAddressRepository ) : AuditableService(auditedInteractionService) { private val generateCrn = SimpleJdbcCall(jdbcTemplate) .withCatalogName("offender_support_api") - .withProcedureName("getNextCRN") - .withoutProcedureColumnMetaDataAccess() - .declareParameters( - SqlOutParameter("CRN", Types.VARCHAR) - ) + .withFunctionName("getNextCRN") @Transactional - fun insertPerson(person: Person, courtCode: String): Person = + fun insertPerson(defendant: Defendant, courtCode: String): Person = audit(BusinessInteractionCode.INSERT_PERSON) { audit -> // Person record - val savedPerson = personRepository.save(person) + val savedPerson = personRepository.save(defendant.toPerson()) - val courtLinkedProvider = courtRepository.findByNationalCourtCode(courtCode).probationArea + val courtLinkedProvider = courtRepository.getByOuCode(courtCode).provider val initialAllocation = referenceDataRepository.initialAllocationReason() val unallocatedTeam = teamRepository.findByCode(courtLinkedProvider.code + "UAT") val unallocatedStaff = staffRepository.findByCode(unallocatedTeam.code + "U") @@ -73,11 +73,76 @@ class PersonService( equalityRepository.save(equality) + val address = defendant.personDefendant?.personDetails?.address + if (address.containsInformation()) { + insertAddress( + PersonAddress( + id = null, + start = LocalDate.now(), + status = referenceDataRepository.mainAddressStatus(), + personId = savedPerson.id, + notes = address?.buildNotes(), + postcode = address?.postcode, + type = referenceDataRepository.awaitingAssessmentAddressType() + ) + ) + } audit["offenderId"] = savedPerson.id savedPerson } + @Transactional + fun insertAddress(address: PersonAddress): PersonAddress = audit(BusinessInteractionCode.INSERT_ADDRESS) { audit -> + val savedAddress = personAddressRepository.save(address) + audit["addressId"] = address.id!! + savedAddress + } + fun generateCrn(): String { - return generateCrn.execute()["CRN"] as String + return generateCrn.executeFunction(String::class.java) + } + + fun String.toDeliusGender() = ReferenceData.GenderCode.entries.find { it.commonPlatformValue == this }?.deliusValue + ?: throw IllegalStateException("Gender not found: $this") + + fun Defendant.toPerson(): Person { + val personDetails = personDefendant?.personDetails ?: throw IllegalArgumentException("No person found") + val genderCode = personDetails.gender.toDeliusGender() + + return Person( + id = null, + crn = generateCrn(), + croNumber = this.croNumber, + pncNumber = this.pncId, + forename = personDetails.firstName, + secondName = personDetails.middleName, + telephoneNumber = personDetails.contact?.home, + mobileNumber = personDetails.contact?.mobile, + surname = personDetails.lastName, + dateOfBirth = personDetails.dateOfBirth, + gender = referenceDataRepository.findByCodeAndDatasetCode(genderCode, DatasetCode.GENDER)!!, + softDeleted = false, + surnameSoundex = personRepository.getSoundex(personDetails.lastName), + middleNameSoundex = personDetails.middleName?.let { personRepository.getSoundex(it) }, + firstNameSoundex = personRepository.getSoundex(personDetails.firstName), + ) + } + + fun Address?.containsInformation(): Boolean { + return this != null && listOf( + this.address1, this.address2, this.address3, + this.address4, this.address5, this.postcode + ).any { !it.isNullOrBlank() } + } + + fun Address.buildNotes(): String { + return listOf( + "Address record automatically created by common-platform-delius-service with the following information:", + "Address1: ${this.address1 ?: "N/A"}", + "Address2: ${this.address2 ?: "N/A"}", + "Address3: ${this.address3 ?: "N/A"}", + "Address4: ${this.address4 ?: "N/A"}", + "Postcode: ${this.postcode ?: "N/A"}" + ).joinToString("\n") } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/resources/application.yml b/projects/common-platform-and-delius/src/main/resources/application.yml index 52522fea63..d3c0873bb6 100644 --- a/projects/common-platform-and-delius/src/main/resources/application.yml +++ b/projects/common-platform-and-delius/src/main/resources/application.yml @@ -75,10 +75,6 @@ logging.level: spring.config.activate.on-profile: integration-test spring.datasource.url: jdbc:h2:mem:./test;MODE=Oracle;DEFAULT_NULL_ORDERING=HIGH ---- -spring.config.activate.on-profile: oracle -spring.datasource.url: 'jdbc:tc:oracle:slim-faststart:///XEPDB1' - --- spring.config.activate.on-profile: delius-db spring: diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index be7b3df781..abbc0d86fd 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -12,14 +12,9 @@ import org.mockito.kotlin.whenever import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator -import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchResponse import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient -import uk.gov.justice.digital.hmpps.integrations.delius.entity.DatasetCode -import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData -import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceDataRepository import uk.gov.justice.digital.hmpps.message.Notification -import uk.gov.justice.digital.hmpps.service.AddressService import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -35,12 +30,6 @@ internal class HandlerTest { @Mock lateinit var personService: PersonService - @Mock - lateinit var addressService: AddressService - - @Mock - lateinit var referenceDataRepository: ReferenceDataRepository - @Mock lateinit var probationSearchClient: ProbationSearchClient @@ -55,26 +44,7 @@ internal class HandlerTest { matchedBy = "NONE" ) ) - whenever(personService.generateCrn()).thenReturn("A111111") whenever(personService.insertPerson(any(), any())).thenReturn(PersonGenerator.DEFAULT) - whenever( - referenceDataRepository.findByCodeAndDatasetCode( - ReferenceData.GenderCode.MALE.deliusValue, - DatasetCode.GENDER - ) - ).thenReturn(ReferenceDataGenerator.GENDER_MALE) - whenever( - referenceDataRepository.findByCodeAndDatasetCode( - ReferenceData.StandardRefDataCode.ADDRESS_MAIN_STATUS.code, - DatasetCode.ADDRESS_STATUS - ) - ).thenReturn(ReferenceDataGenerator.MAIN_ADDRESS_STATUS) - whenever( - referenceDataRepository.findByCodeAndDatasetCode( - ReferenceData.StandardRefDataCode.AWAITING_ASSESSMENT.code, - DatasetCode.ADDRESS_TYPE - ) - ).thenReturn(ReferenceDataGenerator.AWAITING_ASSESSMENT) val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) handler.handle(notification) diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt deleted file mode 100644 index c3ce313ce3..0000000000 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/AddressServiceTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -package uk.gov.justice.digital.hmpps.service - -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Mockito.verify -import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.check -import org.mockito.kotlin.whenever -import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService -import uk.gov.justice.digital.hmpps.data.generator.AddressGenerator -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository - -@ExtendWith(MockitoExtension::class) -class AddressServiceTest { - @Mock - lateinit var auditedInteractionService: AuditedInteractionService - - @Mock - private lateinit var addressRepository: PersonAddressRepository - - @InjectMocks - private lateinit var addressService: AddressService - - @Test - fun `successfully inserts address record`() { - val mainAddress = AddressGenerator.MAIN_ADDRESS - whenever(addressRepository.save(mainAddress)).thenReturn(mainAddress) - - addressService.insertAddress(mainAddress) - - verify(addressRepository).save(check { - assertThat(it.personId, equalTo(mainAddress.personId)) - assertThat(it.start, equalTo(mainAddress.start)) - assertThat(it.status, equalTo(mainAddress.status)) - assertThat(it.type, equalTo(mainAddress.type)) - }) - } -} diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt deleted file mode 100644 index 4bb05c1c2a..0000000000 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonServiceTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -package uk.gov.justice.digital.hmpps.service - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Mockito.anyString -import org.mockito.Mockito.verify -import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.any -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.whenever -import org.springframework.jdbc.core.JdbcTemplate -import uk.gov.justice.digital.hmpps.audit.service.AuditedInteractionService -import uk.gov.justice.digital.hmpps.data.generator.* -import uk.gov.justice.digital.hmpps.integrations.delius.entity.* -import uk.gov.justice.digital.hmpps.messaging.Notifier -import java.time.LocalDateTime - -@ExtendWith(MockitoExtension::class) -class PersonServiceTest { - @Mock - lateinit var auditedInteractionService: AuditedInteractionService - - @Mock - private lateinit var personRepository: PersonRepository - - @Mock - private lateinit var courtRepository: CourtRepository - - @Mock - private lateinit var equalityRepository: EqualityRepository - - @Mock - private lateinit var personManagerRepository: PersonManagerRepository - - @Mock - private lateinit var teamRepository: TeamRepository - - @Mock - private lateinit var staffRepository: StaffRepository - - @Mock - private lateinit var referenceDataRepository: ReferenceDataRepository - - @Mock - lateinit var notifier: Notifier - - @Mock - private lateinit var jdbcTemplate: JdbcTemplate - - @InjectMocks - private lateinit var personService: PersonService - - @Test - fun `insert person successfully inserts person, person manager and equality records`() { - val person = PersonGenerator.DEFAULT - val savedPerson = PersonGenerator.generate("A000002") - val court = CourtGenerator.UNKNOWN_COURT_N07_PROVIDER - val unallocatedTeam = TeamGenerator.UNALLOCATED - val unallocatedStaff = StaffGenerator.UNALLOCATED - val initialAllocation = ReferenceDataGenerator.INITIAL_ALLOCATION - - whenever(personRepository.save(person)).thenReturn(savedPerson) - whenever(courtRepository.findByNationalCourtCode(anyString())).thenReturn(court) - whenever( - referenceDataRepository.findByCodeAndDatasetCode( - ReferenceData.StandardRefDataCode.INITIAL_ALLOCATION.code, - DatasetCode.OM_ALLOCATION_REASON - ) - ).thenReturn(initialAllocation) - whenever(teamRepository.findByCode(anyString())).thenReturn(unallocatedTeam) - whenever(staffRepository.findByCode(anyString())).thenReturn(unallocatedStaff) - - personService.insertPerson(person, court.code) - verify(notifier).caseCreated(any()) - verify(personRepository).save(person) - verify(personManagerRepository).save(any()) - verify(equalityRepository).save(any()) - - // Verify person record is saved successfully - val personCaptor = argumentCaptor() - verify(personRepository).save(personCaptor.capture()) - assertEquals(person.forename, personCaptor.firstValue.forename) - assertEquals(person.surname, personCaptor.firstValue.surname) - assertEquals(person.gender, personCaptor.firstValue.gender) - - // Verify manager record is saved successfully - val managerCaptor = argumentCaptor() - verify(personManagerRepository).save(managerCaptor.capture()) - assertEquals(savedPerson, managerCaptor.firstValue.person) - assertEquals(unallocatedStaff, managerCaptor.firstValue.staff) - assertEquals(unallocatedTeam, managerCaptor.firstValue.team) - assertEquals(court.probationArea, managerCaptor.firstValue.provider) - assertEquals(LocalDateTime.of(1900, 1, 1, 0, 0), managerCaptor.firstValue.allocationDate) - - // Verify equality is created successfully - val equalityCaptor = argumentCaptor() - verify(equalityRepository).save(equalityCaptor.capture()) - assertEquals(savedPerson.id, equalityCaptor.firstValue.personId) - assertFalse(equalityCaptor.firstValue.softDeleted) - } -} From 740aee24d8fa346c35e70ab7706af2e6fb88d425 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:47:25 +0000 Subject: [PATCH 11/17] Formatting changes --- .../digital/hmpps/integrations/delius/entity/Person.kt | 4 ++-- .../hmpps/integrations/delius/entity/ReferenceData.kt | 1 + .../uk/gov/justice/digital/hmpps/messaging/Handler.kt | 10 ++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt index cceab59eee..a67d7cb702 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt @@ -99,9 +99,9 @@ class Person( @Column val partitionAreaId: Long = 0L - ) +) -interface PersonRepository : JpaRepository{ +interface PersonRepository : JpaRepository { @Query("SELECT SOUNDEX(:name) FROM DUAL", nativeQuery = true) fun getSoundex(name: String): String } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt index 9b47cfb158..86098cab07 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/ReferenceData.kt @@ -151,5 +151,6 @@ fun ReferenceDataRepository.awaitingAssessmentAddressType() = interface CourtRepository : JpaRepository { fun findByOuCode(ouCode: String): Court? } + fun CourtRepository.getByOuCode(ouCode: String) = findByOuCode(ouCode) ?: throw NotFoundException("Court", "ouCode", ouCode) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index d4ecc80e51..c4ba9205f5 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -57,10 +57,12 @@ class Handler( // Insert each defendant as a person record val savedPerson = personService.insertPerson(defendant, courtCode) - telemetryService.trackEvent("PersonCreated", mapOf( - "CRN" to savedPerson.crn, - "personId" to savedPerson.id.toString(), - "hearingId" to notification.message.hearing.id) + telemetryService.trackEvent( + "PersonCreated", mapOf( + "CRN" to savedPerson.crn, + "personId" to savedPerson.id.toString(), + "hearingId" to notification.message.hearing.id + ) ) } } From 21804f432f0a28133d1e5db9f18479cb8b8f3812 Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Fri, 25 Oct 2024 12:43:35 +0100 Subject: [PATCH 12/17] PI-2575 - Added Address sns created notification - Filter hearing message to cases containing judicial results with label Remanded in custody --- .../hmpps/data/generator/AddressGenerator.kt | 2 +- .../hmpps/data/generator/MessageGenerator.kt | 6 +- .../common-platform-hearing-dob-error.json | 29 +++++ ...=> common-platform-hearing-no-remand.json} | 3 +- .../messages/common-platform-hearing.json | 2 +- .../justice/digital/hmpps/IntegrationTest.kt | 111 ++++++++++++------ .../delius/entity/PersonAddress.kt | 6 +- .../hmpps/messaging/CommonPlatformHearing.kt | 27 ++++- .../digital/hmpps/messaging/Handler.kt | 16 ++- .../digital/hmpps/messaging/Notifier.kt | 23 ++++ .../digital/hmpps/service/PersonService.kt | 3 +- .../digital/hmpps/messaging/HandlerTest.kt | 4 +- .../digital/hmpps/messaging/NotifierTest.kt | 11 +- .../integrations/delius/entity/Person.kt | 15 +-- 14 files changed, 192 insertions(+), 66 deletions(-) create mode 100644 projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json rename projects/common-platform-and-delius/src/dev/resources/messages/{common-platform-hearing-validation-error.json => common-platform-hearing-no-remand.json} (83%) diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt index 566fadcaec..80f76a7518 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt @@ -16,7 +16,7 @@ object AddressGenerator { id = id, start = LocalDate.now(), status = ReferenceDataGenerator.MAIN_ADDRESS_STATUS, - personId = person.id!!, + person = person, notes = notes, postcode = postcode, type = ReferenceDataGenerator.AWAITING_ASSESSMENT diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt index 21c1aec18c..6b34942680 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/MessageGenerator.kt @@ -5,10 +5,12 @@ import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader object MessageGenerator { val COMMON_PLATFORM_EVENT = ResourceLoader.message("common-platform-hearing") - val COMMON_PLATFORM_EVENT_VALIDATION_ERROR = - ResourceLoader.message("common-platform-hearing-validation-error") + val COMMON_PLATFORM_EVENT_DOB_ERROR = + ResourceLoader.message("common-platform-hearing-dob-error") val COMMON_PLATFORM_EVENT_NO_CASES = ResourceLoader.message("common-platform-hearing-no-cases") val COMMON_PLATFORM_EVENT_BLANK_ADDRESS = ResourceLoader.message("common-platform-hearing-blank-address") + val COMMON_PLATFORM_EVENT_NO_REMAND = + ResourceLoader.message("common-platform-hearing-no-remand") } diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json new file mode 100644 index 0000000000..9fa9635423 --- /dev/null +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json @@ -0,0 +1,29 @@ +{ + "Type": "Notification", + "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", + "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", + "Message": "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[{\"isConvictedResult\":true,\"label\":\"Remanded in custody\",\"judicialResultTypeId\":\"00000000-0000-0000-0000-000000000000\",\"resultText\":\"RI - Remanded in custody\"}],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2020-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":\"01234567890\",\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", + "Timestamp": "2022-07-27T14:22:08.509Z", + "SignatureVersion": "1", + "Signature": "EXAMPLE", + "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", + "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", + "MessageAttributes": { + "tracestate": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + }, + "eventType": { + "Type": "String", + "Value": "COMMON_PLATFORM_HEARING" + }, + "hearingEventType": { + "Type": "String", + "Value": "ConfirmedOrUpdated" + }, + "traceparent": { + "Type": "String", + "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" + } + } +} \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-validation-error.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-remand.json similarity index 83% rename from projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-validation-error.json rename to projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-remand.json index 42b65e18c1..bf41743b9e 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-validation-error.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-remand.json @@ -2,8 +2,7 @@ "Type": "Notification", "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", - "Message" : "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2015-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":null,\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", - "Timestamp": "2022-07-27T14:22:08.509Z", + "Message" : "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":\"01234567890\",\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", "Timestamp": "2022-07-27T14:22:08.509Z", "SignatureVersion": "1", "Signature": "EXAMPLE", "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json index 73bb2c8f3e..8c082bb0bd 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json @@ -2,7 +2,7 @@ "Type": "Notification", "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", - "Message" : "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":\"01234567890\",\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", + "Message": "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[{\"isConvictedResult\":true,\"label\":\"Remanded in custody\",\"judicialResultTypeId\":\"00000000-0000-0000-0000-000000000000\",\"resultText\":\"RI - Remanded in custody\"}],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":\"Example Address Line 1\",\"address2\":\"Example Address Line 2\",\"address3\":\"Example Address Line 3\",\"address4\":null,\"address5\":null,\"postcode\":\"AA1 1AA\"},\"contact\":{\"home\":\"01234567890\",\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", "Timestamp": "2022-07-27T14:22:08.509Z", "SignatureVersion": "1", "Signature": "EXAMPLE", diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 1d5a2a9084..84b4d30d3a 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -4,9 +4,8 @@ import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.* import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers +import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test import org.mockito.Mockito import org.mockito.Mockito.atLeastOnce import org.mockito.kotlin.* @@ -33,6 +32,7 @@ import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notif import uk.gov.justice.digital.hmpps.telemetry.TelemetryService import java.time.LocalDate +@TestMethodOrder(MethodOrderer.OrderAnnotation::class) @AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) internal class IntegrationTest { @@ -92,17 +92,7 @@ internal class IntegrationTest { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) channelManager.getChannel(queueName).publishAndWait(notification) - verify(personService, never()).insertPerson(any(), any()) - verify(personService, never()).insertAddress(any()) - verify(personRepository, never()).save(any()) - verify(addressRepository, never()).save(any()) - verify(auditedInteractionService, Mockito.never()).createAuditedInteraction( - any(), - any(), - any(), - any(), - anyOrNull() - ) + thenNoRecordsAreInserted() } @Test @@ -118,15 +108,25 @@ internal class IntegrationTest { ) val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_CASES) - channelManager.getChannel(queueName).publishAndWait(notification) + thenNoRecordsAreInserted() + } - verify(personService, never()).insertPerson(any(), any()) - verify(personService, never()).insertAddress(any()) - verify(addressRepository, never()).save(any()) - verify(personRepository, never()).save(any()) - verify(auditedInteractionService, Mockito.never()) - .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) + @Test + fun `When a message without a judicial result of remanded in custody is found`() { + wireMockServer.stubFor( + post(urlPathEqualTo("/probation-search/match")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBodyFile("probation-search-no-results.json") + ) + ) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_REMAND) + channelManager.getChannel(queueName).publishAndWait(notification) + thenNoRecordsAreInserted() } @Test @@ -141,16 +141,9 @@ internal class IntegrationTest { ) ) - val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_VALIDATION_ERROR) - + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_DOB_ERROR) channelManager.getChannel(queueName).publishAndWait(notification) - - verify(personService, never()).insertPerson(any(), any()) - verify(personService, never()).insertAddress(any()) - verify(personRepository, never()).save(any()) - verify(addressRepository, never()).save(any()) - verify(auditedInteractionService, Mockito.never()) - .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) + thenNoRecordsAreInserted() } @Test @@ -251,8 +244,9 @@ internal class IntegrationTest { ) } + @Order(1) @Test - fun `engagement created message is published on insert person`() { + fun `engagement created and address created sns messages are published on insert person`() { wireMockServer.stubFor( post(urlPathEqualTo("/probation-search/match")) .willReturn( @@ -276,15 +270,56 @@ internal class IntegrationTest { }) val topic = hmppsChannelManager.getChannel(topicName) - val messages = topic.pollFor(1) + val messages = topic.pollFor(2) + val messageTypes = messages.mapNotNull { it.eventType } + + assertThat( + messageTypes.sorted(), + Matchers.equalTo( + listOf( + "probation-case.address.created", + "probation-case.engagement.created" + ) + ) + ) - val engagementCreated = - messages.first { it.eventType == "probation-case.engagement.created" }.message as HmppsDomainEvent + messages.forEach { message -> + val event = message.message as HmppsDomainEvent + + when (event.eventType) { + "probation-case.engagement.created" -> { + assertEquals(1, event.version) + assertEquals("probation-case.engagement.created", event.eventType) + assertEquals("A probation case record for a person has been created in Delius", event.description) + assertNotNull(event.personReference.findCrn()) + assertNull(event.detailUrl) + assertTrue(event.additionalInformation.isEmpty()) + } + + "probation-case.address.created" -> { + assertEquals(1, event.version) + assertEquals("probation-case.address.created", event.eventType) + assertEquals("A new address has been created on the probation case", event.description) + assertNotNull(event.personReference.findCrn()) + assertNull(event.detailUrl) + + with(event.additionalInformation) { + assertTrue(containsKey("addressStatus")) + assertTrue(containsKey("addressId")) + } + } + else -> fail("Unexpected event type: ${event.eventType}") + } + } + } - assertEquals("probation-case.engagement.created", engagementCreated.eventType) - assertEquals(1, engagementCreated.version) - assertEquals("A probation case record for a person has been created in Delius", engagementCreated.description) - assertEquals("A111111", engagementCreated.personReference.findCrn()!!) - assertNull(engagementCreated.detailUrl) + private fun thenNoRecordsAreInserted() + { + verify(personService, never()).insertPerson(any(), any()) + verify(personService, never()).insertAddress(any()) + verify(addressRepository, never()).save(any()) + verify(personRepository, never()).save(any()) + verify(auditedInteractionService, Mockito.never()) + .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt index c020a4b728..9e5801b83e 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt @@ -8,6 +8,7 @@ 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.integrations.delius.entity.Person import uk.gov.justice.digital.hmpps.integrations.delius.entity.ReferenceData import java.time.LocalDate import java.time.ZonedDateTime @@ -46,8 +47,9 @@ class PersonAddress( @Column(name = "no_fixed_abode") val noFixedAbode: Boolean? = false, - @Column(name = "offender_id") - val personId: Long, + @ManyToOne + @JoinColumn(name = "offender_id") + val person: Person, @Column(name = "notes", columnDefinition = "clob") val notes: String? = null, diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt index 176780f88e..692732d26d 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/CommonPlatformHearing.kt @@ -52,9 +52,30 @@ data class Offence( val wording: String, val offenceLegislation: String, val listingNumber: Int, - val judicialResults: List = emptyList(), - val plea: Any? = null, - val verdict: Any? = null + val judicialResults: List, + val plea: Plea? = null, + val verdict: Verdict? = null +) + +data class JudicialResult( + val isConvictedResult: Boolean?, + val label: String?, + val judicialResultTypeId: String?, + val resultText: String? +) + +data class Plea( + val pleaValue: String?, + val pleaDate: LocalDate +) + +data class Verdict( + val verdictDate: ZonedDateTime?, + val verdictType: VerdictType +) + +data class VerdictType( + val description: String?, ) data class PersonDefendant( diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index c4ba9205f5..54c01e156b 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -28,9 +28,18 @@ class Handler( override fun handle(notification: Notification) { telemetryService.notificationReceived(notification) + // Filter hearing message for defendants with a convicted judicial result of Remanded in custody val defendants = notification.message.hearing.prosecutionCases .flatMap { it.defendants } - .ifEmpty { throw IllegalArgumentException("No defendants found") } + .filter { defendant -> + defendant.offences.any { offence -> + offence.judicialResults.any { judicialResult -> + judicialResult.isConvictedResult == true && judicialResult.label == "Remanded in custody" + } + } + } + .ifEmpty { throw IllegalArgumentException("No valid defendants found") } + val courtCode = notification.message.hearing.courtCentre.code @@ -80,8 +89,3 @@ class Handler( ) } } - - - - - diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt index 18aaed2e56..36a6a52e30 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt @@ -7,6 +7,7 @@ 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.integrations.delius.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress import uk.gov.justice.digital.hmpps.message.* import uk.gov.justice.digital.hmpps.publisher.NotificationPublisher @@ -37,4 +38,26 @@ class Notifier( ) ) } + + fun addressCreated(personAddress: PersonAddress) { + 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", personAddress.person.crn), + ), + ), + additionalInformation = mapOf( + "addressStatus" to personAddress.status.description, + "addressId" to personAddress.id.toString() + ) + ), + attributes = MessageAttributes("probation-case.address.created") + ) + ) + } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index 7bb1900a02..2c01a34f16 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -80,7 +80,7 @@ class PersonService( id = null, start = LocalDate.now(), status = referenceDataRepository.mainAddressStatus(), - personId = savedPerson.id, + person = savedPerson, notes = address?.buildNotes(), postcode = address?.postcode, type = referenceDataRepository.awaitingAssessmentAddressType() @@ -94,6 +94,7 @@ class PersonService( @Transactional fun insertAddress(address: PersonAddress): PersonAddress = audit(BusinessInteractionCode.INSERT_ADDRESS) { audit -> val savedAddress = personAddressRepository.save(address) + notifier.addressCreated(savedAddress) audit["addressId"] = address.id!! savedAddress } diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index abbc0d86fd..490aa3c97a 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -53,7 +53,7 @@ internal class HandlerTest { @Test fun `exception thrown when age is under 10 years old`() { - val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_VALIDATION_ERROR) + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_DOB_ERROR) val exception = assertThrows { handler.handle(notification) } @@ -66,6 +66,6 @@ internal class HandlerTest { val exception = assertThrows { handler.handle(notification) } - assert(exception.message!!.contains("No defendants found")) + assert(exception.message!!.contains("No valid defendants found")) } } diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt index 07efc335b0..0d0b50f81a 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt @@ -8,6 +8,7 @@ import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.* import org.springframework.boot.test.system.CapturedOutput import org.springframework.boot.test.system.OutputCaptureExtension +import uk.gov.justice.digital.hmpps.data.generator.AddressGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.publisher.NotificationPublisher @@ -26,10 +27,18 @@ class NotifierTest { } @Test - fun `test notification`(output: CapturedOutput) { + fun `test person created notification`(output: CapturedOutput) { doNothing().whenever(topicPublisher).publish(any>()) notifier.caseCreated(PersonGenerator.DEFAULT) verify(topicPublisher, times(1)).publish(any>()) verifyNoMoreInteractions(topicPublisher) } + + @Test + fun `test address created notification`(output: CapturedOutput) { + doNothing().whenever(topicPublisher).publish(any>()) + notifier.addressCreated(AddressGenerator.MAIN_ADDRESS) + verify(topicPublisher, times(1)).publish(any>()) + verifyNoMoreInteractions(topicPublisher) + } } \ No newline at end of file diff --git a/projects/risk-assessment-scores-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt b/projects/risk-assessment-scores-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt index dd50faf1db..a13e52467e 100644 --- a/projects/risk-assessment-scores-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt +++ b/projects/risk-assessment-scores-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/Person.kt @@ -1,11 +1,6 @@ package uk.gov.justice.digital.hmpps.integrations.delius.entity -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.Id -import jakarta.persistence.JoinColumn -import jakarta.persistence.ManyToOne -import jakarta.persistence.Table +import jakarta.persistence.* import org.hibernate.annotations.Immutable import org.springframework.data.jpa.repository.JpaRepository import uk.gov.justice.digital.hmpps.exception.NotFoundException @@ -49,7 +44,13 @@ class Person( val dateOfBirth: LocalDate, @Column(updatable = false, columnDefinition = "number") - val softDeleted: Boolean = false + val softDeleted: Boolean = false, + + @Column + val exclusionMessage: String? = "You are excluded from viewing this record. Please contact a system administrator", + + @Column + val restrictionMessage: String? = "This is a restricted record. Please contact a system administrator" ) interface PersonRepository : JpaRepository { From 3589669c3dc6b15f38083d2c241419275ef1d999 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 11:45:29 +0000 Subject: [PATCH 13/17] Formatting changes --- .../kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt | 4 ++-- .../kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 84b4d30d3a..f912588f47 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -308,13 +308,13 @@ internal class IntegrationTest { assertTrue(containsKey("addressId")) } } + else -> fail("Unexpected event type: ${event.eventType}") } } } - private fun thenNoRecordsAreInserted() - { + private fun thenNoRecordsAreInserted() { verify(personService, never()).insertPerson(any(), any()) verify(personService, never()).insertAddress(any()) verify(addressRepository, never()).save(any()) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 54c01e156b..92a05920fe 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -40,7 +40,6 @@ class Handler( } .ifEmpty { throw IllegalArgumentException("No valid defendants found") } - val courtCode = notification.message.hearing.courtCentre.code val dateOfBirth = notification.message.hearing.prosecutionCases From 7cb2068d5a0c6a1e76bc2e3db299331b593c0947 Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Fri, 25 Oct 2024 15:28:08 +0100 Subject: [PATCH 14/17] PI-2575 - PR Review Feedback --- ...Generator.kt => PersonAddressGenerator.kt} | 2 +- ...common-platform-hearing-blank-address.json | 2 +- .../justice/digital/hmpps/IntegrationTest.kt | 3 +- .../digital/hmpps/messaging/Handler.kt | 49 +++++++---------- .../digital/hmpps/messaging/Notifier.kt | 3 +- .../hmpps/service/InsertPersonResult.kt | 13 +++++ .../digital/hmpps/service/PersonService.kt | 54 +++++++++++-------- .../digital/hmpps/messaging/HandlerTest.kt | 25 +++++---- .../digital/hmpps/messaging/NotifierTest.kt | 4 +- 9 files changed, 86 insertions(+), 69 deletions(-) rename projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/{AddressGenerator.kt => PersonAddressGenerator.kt} (95%) create mode 100644 projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/InsertPersonResult.kt diff --git a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonAddressGenerator.kt similarity index 95% rename from projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt rename to projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonAddressGenerator.kt index 80f76a7518..fa2b186162 100644 --- a/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt +++ b/projects/common-platform-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonAddressGenerator.kt @@ -4,7 +4,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress import java.time.LocalDate -object AddressGenerator { +object PersonAddressGenerator { val MAIN_ADDRESS = generate(person = PersonGenerator.DEFAULT) fun generate( diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json index 6e9219f3a1..9019f25707 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json @@ -2,7 +2,7 @@ "Type": "Notification", "MessageId": "aa2c2828-167f-529b-8e19-73735a2fb85c", "TopicArn": "arn:aws:sns:eu-west-2:000000000000:example", - "Message": "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":null,\"address2\":null,\"address3\":null,\"address4\":null,\"address5\":null,\"postcode\":null},\"contact\":{\"home\":null,\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", + "Message": "{\"hearing\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"courtCentre\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"code\":\"A00AA00\",\"roomId\":\"00000000-0000-0000-0000-000000000000\",\"roomName\":\"Courtroom 01\"},\"type\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"description\":\"First hearing\",\"welshDescription\":null},\"jurisdictionType\":\"MAGISTRATES\",\"hearingDays\":[{\"sittingDay\":\"2024-01-01T12:00:00\",\"listedDurationMinutes\":30,\"listingSequence\":1}],\"prosecutionCases\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"initiationCode\":\"A\",\"prosecutionCaseIdentifier\":{\"prosecutionAuthorityCode\":\"AAAAA\",\"prosecutionAuthorityId\":\"00000000-0000-0000-0000-000000000000\",\"caseURN\":\"00AA000000\"},\"defendants\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offences\":[{\"id\":\"00000000-0000-0000-0000-000000000000\",\"offenceDefinitionId\":\"00000000-0000-0000-0000-000000000000\",\"offenceCode\":\"AA00000\",\"offenceTitle\":\"Example Offense Title\",\"wording\":\"Example of the offense committed\",\"offenceLegislation\":\"Example legislation\",\"listingNumber\":1,\"judicialResults\":[{\"isConvictedResult\":true,\"label\":\"Remanded in custody\",\"judicialResultTypeId\":\"00000000-0000-0000-0000-000000000000\",\"resultText\":\"RI - Remanded in custody\"}],\"plea\":null,\"verdict\":null}],\"prosecutionCaseId\":\"00000000-0000-0000-0000-000000000000\",\"personDefendant\":{\"personDetails\":{\"gender\":\"MALE\",\"lastName\":\"Example Last Name\",\"middleName\":null,\"firstName\":\"Example First Name\",\"dateOfBirth\":\"2000-01-01\",\"address\":{\"address1\":null,\"address2\":null,\"address3\":null,\"address4\":null,\"address5\":null,\"postcode\":null},\"contact\":{\"home\":null,\"mobile\":\"07000000000\",\"work\":null},\"ethnicity\":{\"observedEthnicityDescription\":\"White\",\"selfDefinedEthnicityDescription\":\"British\"}}},\"legalEntityDefendant\":null,\"masterDefendantId\":\"00000000-0000-0000-0000-000000000000\",\"pncId\":\"00000000000A\",\"croNumber\":\"000000/00A\"}],\"caseStatus\":\"ACTIVE\",\"caseMarkers\":[]}]}}", "Timestamp": "2022-07-27T14:22:08.509Z", "SignatureVersion": "1", "Signature": "EXAMPLE", diff --git a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index f912588f47..266a378bb2 100644 --- a/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/common-platform-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -315,11 +315,10 @@ internal class IntegrationTest { } private fun thenNoRecordsAreInserted() { - verify(personService, never()).insertPerson(any(), any()) verify(personService, never()).insertAddress(any()) verify(addressRepository, never()).save(any()) verify(personRepository, never()).save(any()) verify(auditedInteractionService, Mockito.never()) - .createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) + .createAuditedInteraction(any(), any(), eq(AuditedInteraction.Outcome.SUCCESS), any(), anyOrNull()) } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 92a05920fe..c4fe0bf6d7 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -12,13 +12,12 @@ import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService -import java.time.LocalDate -import java.time.Period @Component @Channel("common-platform-and-delius-queue") class Handler( override val converter: NotificationConverter, + private val notifier: Notifier, private val telemetryService: TelemetryService, private val personService: PersonService, private val probationSearchClient: ProbationSearchClient @@ -42,49 +41,41 @@ class Handler( val courtCode = notification.message.hearing.courtCentre.code - val dateOfBirth = notification.message.hearing.prosecutionCases - .firstOrNull()?.defendants?.firstOrNull() - ?.personDefendant?.personDetails?.dateOfBirth - ?: throw IllegalArgumentException("Date of birth not found in message") + defendants.forEach { defendant -> + val matchRequest = defendant.toProbationMatchRequest() + val matchedPersonResponse = probationSearchClient.match(matchRequest) - // Under 10 years old validation - dateOfBirth.let { - val age = Period.between(it, LocalDate.now()).years - require(age > 10) { - "Date of birth would indicate person is under ten years old: $it" + if (matchedPersonResponse.matches.isNotEmpty()) { + return } - } - - val matchRequest = notification.message.toProbationMatchRequest() - val matchedPersonResponse = probationSearchClient.match(matchRequest) - if (matchedPersonResponse.matches.isNotEmpty()) { - return - } - defendants.forEach { defendant -> // Insert each defendant as a person record - val savedPerson = personService.insertPerson(defendant, courtCode) + val savedEntities = personService.insertPerson(defendant, courtCode) + + notifier.caseCreated(savedEntities.person) + savedEntities.address?.let { notifier.addressCreated(it) } telemetryService.trackEvent( "PersonCreated", mapOf( - "CRN" to savedPerson.crn, - "personId" to savedPerson.id.toString(), - "hearingId" to notification.message.hearing.id + "hearingId" to notification.message.hearing.id, + "CRN" to savedEntities.person.crn, + "personId" to savedEntities.person.id.toString(), + "personManagerId" to savedEntities.personManager.id.toString(), + "equalityId" to savedEntities.equality.id.toString(), + "addressId" to savedEntities.address?.id.toString() ) ) } } - fun CommonPlatformHearing.toProbationMatchRequest(): ProbationMatchRequest { - val defendant = this.hearing.prosecutionCases.firstOrNull()?.defendants?.firstOrNull() - val personDetails = - defendant?.personDefendant?.personDetails ?: throw IllegalArgumentException("Person details are required") + fun Defendant.toProbationMatchRequest(): ProbationMatchRequest { + val personDetails = this.personDefendant?.personDetails ?: throw IllegalArgumentException("Person details are required") return ProbationMatchRequest( firstName = personDetails.firstName, surname = personDetails.lastName, dateOfBirth = personDetails.dateOfBirth, - pncNumber = defendant.pncId, - croNumber = defendant.croNumber + pncNumber = this.pncId, + croNumber = this.croNumber ) } } diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt index 36a6a52e30..5f4a393905 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Notifier.kt @@ -18,7 +18,8 @@ class Notifier( ) { @Subscribe( messages = [ - Message(title = "probation-case.engagement.created", payload = Schema(HmppsDomainEvent::class)) + Message(title = "probation-case.engagement.created", payload = Schema(HmppsDomainEvent::class)), + Message(title = "probation-case.address.created", payload = Schema(HmppsDomainEvent::class)) ] ) fun caseCreated(person: Person) { diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/InsertPersonResult.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/InsertPersonResult.kt new file mode 100644 index 0000000000..ab2dfb41d5 --- /dev/null +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/InsertPersonResult.kt @@ -0,0 +1,13 @@ +package uk.gov.justice.digital.hmpps.service + +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.entity.PersonManager +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress + +data class InsertPersonResult( + val person: Person, + val personManager: PersonManager, + val equality: Equality, + var address: PersonAddress? +) \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index 2c01a34f16..f6e7406df8 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -12,15 +12,14 @@ import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddr import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository import uk.gov.justice.digital.hmpps.messaging.Address import uk.gov.justice.digital.hmpps.messaging.Defendant -import uk.gov.justice.digital.hmpps.messaging.Notifier import java.time.LocalDate import java.time.LocalDateTime +import java.time.Period @Service class PersonService( jdbcTemplate: JdbcTemplate, auditedInteractionService: AuditedInteractionService, - private val notifier: Notifier, private val personRepository: PersonRepository, private val courtRepository: CourtRepository, private val equalityRepository: EqualityRepository, @@ -36,8 +35,20 @@ class PersonService( .withFunctionName("getNextCRN") @Transactional - fun insertPerson(defendant: Defendant, courtCode: String): Person = + fun insertPerson(defendant: Defendant, courtCode: String): InsertPersonResult = audit(BusinessInteractionCode.INSERT_PERSON) { audit -> + + val dateOfBirth = defendant.personDefendant?.personDetails?.dateOfBirth + ?: throw IllegalArgumentException("Date of birth not found in message") + + // Under 10 years old validation + dateOfBirth.let { + val age = Period.between(it, LocalDate.now()).years + require(age > 10) { + "Date of birth would indicate person is under ten years old: $it" + } + } + // Person record val savedPerson = personRepository.save(defendant.toPerson()) @@ -46,8 +57,6 @@ class PersonService( val unallocatedTeam = teamRepository.findByCode(courtLinkedProvider.code + "UAT") val unallocatedStaff = staffRepository.findByCode(unallocatedTeam.code + "U") - notifier.caseCreated(savedPerson) - // Person manager record val manager = PersonManager( person = savedPerson, @@ -62,7 +71,7 @@ class PersonService( allocationDate = LocalDateTime.of(1900, 1, 1, 0, 0) ) - personManagerRepository.save(manager) + val savedManager = personManagerRepository.save(manager) // Equality record val equality = Equality( @@ -71,30 +80,29 @@ class PersonService( softDeleted = false, ) - equalityRepository.save(equality) - - val address = defendant.personDefendant?.personDetails?.address - if (address.containsInformation()) { - insertAddress( - PersonAddress( - id = null, - start = LocalDate.now(), - status = referenceDataRepository.mainAddressStatus(), - person = savedPerson, - notes = address?.buildNotes(), - postcode = address?.postcode, - type = referenceDataRepository.awaitingAssessmentAddressType() + val savedEquality = equalityRepository.save(equality) + + val savedAddress = + defendant.personDefendant.personDetails.address.takeIf { it.containsInformation() }?.let { + insertAddress( + PersonAddress( + id = null, + start = LocalDate.now(), + status = referenceDataRepository.mainAddressStatus(), + person = savedPerson, + notes = it.buildNotes(), + postcode = it.postcode, + type = referenceDataRepository.awaitingAssessmentAddressType() + ) ) - ) - } + } audit["offenderId"] = savedPerson.id - savedPerson + InsertPersonResult(savedPerson, savedManager, savedEquality, savedAddress) } @Transactional fun insertAddress(address: PersonAddress): PersonAddress = audit(BusinessInteractionCode.INSERT_ADDRESS) { audit -> val savedAddress = personAddressRepository.save(address) - notifier.addressCreated(savedAddress) audit["addressId"] = address.id!! savedAddress } diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 490aa3c97a..97f3b6ab68 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -11,10 +11,14 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator +import uk.gov.justice.digital.hmpps.data.generator.PersonAddressGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator +import uk.gov.justice.digital.hmpps.data.generator.PersonManagerGenerator import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchResponse import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient +import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality import uk.gov.justice.digital.hmpps.message.Notification +import uk.gov.justice.digital.hmpps.service.InsertPersonResult import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -33,6 +37,9 @@ internal class HandlerTest { @Mock lateinit var probationSearchClient: ProbationSearchClient + @Mock + lateinit var notifier: Notifier + @InjectMocks lateinit var handler: Handler @@ -44,22 +51,20 @@ internal class HandlerTest { matchedBy = "NONE" ) ) - whenever(personService.insertPerson(any(), any())).thenReturn(PersonGenerator.DEFAULT) + whenever(personService.insertPerson(any(), any())).thenReturn( + InsertPersonResult( + person = PersonGenerator.DEFAULT, + personManager = PersonManagerGenerator.DEFAULT, + equality = Equality(id = 1L, personId = 1L, softDeleted = false), + address = PersonAddressGenerator.MAIN_ADDRESS, + ) + ) val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) handler.handle(notification) verify(telemetryService).notificationReceived(notification) } - @Test - fun `exception thrown when age is under 10 years old`() { - val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_DOB_ERROR) - val exception = assertThrows { - handler.handle(notification) - } - assert(exception.message!!.contains("Date of birth would indicate person is under ten years old")) - } - @Test fun `exception thrown when prosecution cases is empty`() { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_CASES) diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt index 0d0b50f81a..4972813672 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/NotifierTest.kt @@ -8,7 +8,7 @@ import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.* import org.springframework.boot.test.system.CapturedOutput import org.springframework.boot.test.system.OutputCaptureExtension -import uk.gov.justice.digital.hmpps.data.generator.AddressGenerator +import uk.gov.justice.digital.hmpps.data.generator.PersonAddressGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.publisher.NotificationPublisher @@ -37,7 +37,7 @@ class NotifierTest { @Test fun `test address created notification`(output: CapturedOutput) { doNothing().whenever(topicPublisher).publish(any>()) - notifier.addressCreated(AddressGenerator.MAIN_ADDRESS) + notifier.addressCreated(PersonAddressGenerator.MAIN_ADDRESS) verify(topicPublisher, times(1)).publish(any>()) verifyNoMoreInteractions(topicPublisher) } From 113891772a935f18e29e295545d6ff17189860a9 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:30:51 +0000 Subject: [PATCH 15/17] Formatting changes --- .../kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index c4fe0bf6d7..2bd4f1738e 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -69,7 +69,8 @@ class Handler( } fun Defendant.toProbationMatchRequest(): ProbationMatchRequest { - val personDetails = this.personDefendant?.personDetails ?: throw IllegalArgumentException("Person details are required") + val personDetails = + this.personDefendant?.personDetails ?: throw IllegalArgumentException("Person details are required") return ProbationMatchRequest( firstName = personDetails.firstName, surname = personDetails.lastName, From c983a7a6a035ffbb4f176d499e52f7e83ee5e6d3 Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Mon, 28 Oct 2024 10:14:18 +0000 Subject: [PATCH 16/17] PI-2575 - PR Review Feedback --- .../common-platform-and-delius/deploy/values-dev.yml | 2 -- .../deploy/values-preprod.yml | 2 -- .../common-platform-hearing-blank-address.json | 10 +--------- .../messages/common-platform-hearing-dob-error.json | 10 +--------- .../messages/common-platform-hearing-no-cases.json | 10 +--------- .../messages/common-platform-hearing-no-remand.json | 10 +--------- .../resources/messages/common-platform-hearing.json | 10 +--------- 7 files changed, 5 insertions(+), 49 deletions(-) diff --git a/projects/common-platform-and-delius/deploy/values-dev.yml b/projects/common-platform-and-delius/deploy/values-dev.yml index 2da8364e6f..a8c31413d2 100644 --- a/projects/common-platform-and-delius/deploy/values-dev.yml +++ b/projects/common-platform-and-delius/deploy/values-dev.yml @@ -1,5 +1,3 @@ -enabled: false - generic-service: ingress: host: common-platform-and-delius-dev.hmpps.service.justice.gov.uk diff --git a/projects/common-platform-and-delius/deploy/values-preprod.yml b/projects/common-platform-and-delius/deploy/values-preprod.yml index 3aa1c2df9d..a46cf293f4 100644 --- a/projects/common-platform-and-delius/deploy/values-preprod.yml +++ b/projects/common-platform-and-delius/deploy/values-preprod.yml @@ -1,5 +1,3 @@ -enabled: false - generic-service: ingress: host: common-platform-and-delius-preprod.hmpps.service.justice.gov.uk diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json index 9019f25707..75e68cf81b 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-blank-address.json @@ -9,21 +9,13 @@ "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", "MessageAttributes": { - "tracestate": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" - }, - "eventType": { + "messageType": { "Type": "String", "Value": "COMMON_PLATFORM_HEARING" }, "hearingEventType": { "Type": "String", "Value": "ConfirmedOrUpdated" - }, - "traceparent": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" } } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json index 9fa9635423..f1d063a494 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-dob-error.json @@ -9,21 +9,13 @@ "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", "MessageAttributes": { - "tracestate": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" - }, - "eventType": { + "messageType": { "Type": "String", "Value": "COMMON_PLATFORM_HEARING" }, "hearingEventType": { "Type": "String", "Value": "ConfirmedOrUpdated" - }, - "traceparent": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" } } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json index 4ad08dbe7d..fc5ac34f87 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-cases.json @@ -9,21 +9,13 @@ "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", "MessageAttributes": { - "tracestate": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" - }, - "eventType": { + "messageType": { "Type": "String", "Value": "COMMON_PLATFORM_HEARING" }, "hearingEventType": { "Type": "String", "Value": "ConfirmedOrUpdated" - }, - "traceparent": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" } } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-remand.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-remand.json index bf41743b9e..f88a497a1f 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-remand.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing-no-remand.json @@ -8,21 +8,13 @@ "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", "MessageAttributes": { - "tracestate": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" - }, - "eventType": { + "messageType": { "Type": "String", "Value": "COMMON_PLATFORM_HEARING" }, "hearingEventType": { "Type": "String", "Value": "ConfirmedOrUpdated" - }, - "traceparent": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" } } } \ No newline at end of file diff --git a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json index 8c082bb0bd..8e61a1e5cd 100644 --- a/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json +++ b/projects/common-platform-and-delius/src/dev/resources/messages/common-platform-hearing.json @@ -9,21 +9,13 @@ "SigningCertURL": "https://sns.eu-west-2.amazonaws.com/EXAMPLE.pem", "UnsubscribeURL": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=EXAMPLE", "MessageAttributes": { - "tracestate": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" - }, - "eventType": { + "messageType": { "Type": "String", "Value": "COMMON_PLATFORM_HEARING" }, "hearingEventType": { "Type": "String", "Value": "ConfirmedOrUpdated" - }, - "traceparent": { - "Type": "String", - "Value": "00-01a234b56c7de8f9g01h234i56789j0k-1l234m567n8o9p01-01" } } } \ No newline at end of file From 2e7b96d05faaa2352f5fe639ee8cfb6b9d9672e1 Mon Sep 17 00:00:00 2001 From: "Joseph.Dundon" Date: Mon, 28 Oct 2024 15:09:18 +0000 Subject: [PATCH 17/17] PI-2575 - PR Review Feedback --- .../delius/entity/PersonAddress.kt | 14 ++--- .../digital/hmpps/messaging/Handler.kt | 4 +- .../digital/hmpps/messaging/HandlerTest.kt | 53 +++++++++++++++---- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt index 9e5801b83e..ba29020bce 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/entity/PersonAddress.kt @@ -41,7 +41,7 @@ class PersonAddress( @ManyToOne @JoinColumn(name = "address_status_id") - var status: ReferenceData, + val status: ReferenceData, @Convert(converter = YesNoConverter::class) @Column(name = "no_fixed_abode") @@ -58,30 +58,30 @@ class PersonAddress( val addressNumber: String? = null, @Column(name = "street_name") - var streetName: String? = null, + val streetName: String? = null, @Column(name = "district") - var district: String? = null, + val district: String? = null, @Column(name = "town_city") - var town: String? = null, + val town: String? = null, @CreatedDate @Column(nullable = false) var createdDatetime: ZonedDateTime = ZonedDateTime.now(), @Column(name = "county") - var county: String? = null, + val county: String? = null, @Column(nullable = false) @LastModifiedDate var lastUpdatedDatetime: ZonedDateTime = ZonedDateTime.now(), @Column(name = "building_name") - var buildingName: String? = null, + val buildingName: String? = null, @Column(name = "postcode") - var postcode: String? = null, + val postcode: String? = null, @Column(nullable = false) @CreatedBy diff --git a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 2bd4f1738e..a27d0f6308 100644 --- a/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/common-platform-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -37,7 +37,9 @@ class Handler( } } } - .ifEmpty { throw IllegalArgumentException("No valid defendants found") } + if (defendants.isEmpty()) { + return + } val courtCode = notification.message.hearing.courtCentre.code diff --git a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 97f3b6ab68..b4ebaf9bdd 100644 --- a/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/common-platform-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -1,12 +1,12 @@ package uk.gov.justice.digital.hmpps.messaging import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows 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.any +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import uk.gov.justice.digital.hmpps.converter.NotificationConverter @@ -14,14 +14,14 @@ import uk.gov.justice.digital.hmpps.data.generator.MessageGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonAddressGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonManagerGenerator -import uk.gov.justice.digital.hmpps.integrations.client.ProbationMatchResponse -import uk.gov.justice.digital.hmpps.integrations.client.ProbationSearchClient +import uk.gov.justice.digital.hmpps.integrations.client.* import uk.gov.justice.digital.hmpps.integrations.delius.entity.Equality import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.service.InsertPersonResult import uk.gov.justice.digital.hmpps.service.PersonService import uk.gov.justice.digital.hmpps.telemetry.TelemetryMessagingExtensions.notificationReceived import uk.gov.justice.digital.hmpps.telemetry.TelemetryService +import java.time.LocalDate @ExtendWith(MockitoExtension::class) internal class HandlerTest { @@ -44,7 +44,7 @@ internal class HandlerTest { lateinit var handler: Handler @Test - fun `message is logged to telemetry`() { + fun `inserts records when probation search match is not found`() { whenever(probationSearchClient.match(any())).thenReturn( ProbationMatchResponse( matches = emptyList(), @@ -63,14 +63,47 @@ internal class HandlerTest { val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) handler.handle(notification) verify(telemetryService).notificationReceived(notification) + verify(personService).insertPerson(any(), any()) + verify(notifier).caseCreated(any()) + verify(notifier).addressCreated(any()) } @Test - fun `exception thrown when prosecution cases is empty`() { - val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_CASES) - val exception = assertThrows { - handler.handle(notification) - } - assert(exception.message!!.contains("No valid defendants found")) + fun `does not insert person or address when match is found`() { + val fakeMatchResponse = ProbationMatchResponse( + matches = listOf( + OffenderMatch( + offender = OffenderDetail( + otherIds = IDs(crn = "X123456", pncNumber = "00000000000Z"), + firstName = "Name", + surname = "Name", + dateOfBirth = LocalDate.of(1980, 1, 1) + ) + ) + ), + matchedBy = "PNC" + ) + + whenever(probationSearchClient.match(any())).thenReturn(fakeMatchResponse) + + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT) + handler.handle(notification) + + verify(telemetryService).notificationReceived(notification) + verify(personService, never()).insertPerson(any(), any()) + verify(notifier, never()).caseCreated(any()) + verify(notifier, never()).addressCreated(any()) + } + + @Test + fun `When defendants with remanded in custody are not found then no inserts occur`() { + val notification = Notification(message = MessageGenerator.COMMON_PLATFORM_EVENT_NO_REMAND) + + handler.handle(notification) + + verify(telemetryService).notificationReceived(notification) + verify(personService, never()).insertPerson(any(), any()) + verify(notifier, never()).caseCreated(any()) + verify(notifier, never()).addressCreated(any()) } }