diff --git a/results-event/results-event-processor/src/main/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessor.java b/results-event/results-event-processor/src/main/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessor.java index 2b38545ac..d12982dcd 100644 --- a/results-event/results-event-processor/src/main/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessor.java +++ b/results-event/results-event-processor/src/main/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessor.java @@ -10,8 +10,6 @@ import static java.util.UUID.fromString; import static java.util.UUID.randomUUID; import static java.util.stream.Collectors.toList; -import static uk.gov.justice.services.messaging.JsonObjects.createArrayBuilder; -import static uk.gov.justice.services.messaging.JsonObjects.createObjectBuilder; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.apache.commons.lang3.StringUtils.isNotEmpty; @@ -19,6 +17,8 @@ import static uk.gov.justice.services.core.enveloper.Enveloper.envelop; import static uk.gov.justice.services.messaging.Envelope.envelopeFrom; import static uk.gov.justice.services.messaging.Envelope.metadataFrom; +import static uk.gov.justice.services.messaging.JsonObjects.createArrayBuilder; +import static uk.gov.justice.services.messaging.JsonObjects.createObjectBuilder; import static uk.gov.moj.cpp.results.event.service.TemplateIdentifier.POLICE_NOTIFICATION_HEARING_RESULTS_TEMPLATE; import uk.gov.justice.core.courts.CaseDefendant; @@ -29,7 +29,6 @@ import uk.gov.justice.core.courts.DocumentCategory; import uk.gov.justice.core.courts.Hearing; import uk.gov.justice.core.courts.HearingDay; -import uk.gov.justice.core.courts.IndividualDefendant; import uk.gov.justice.core.courts.JudicialResult; import uk.gov.justice.core.courts.Material; import uk.gov.justice.services.common.converter.JsonObjectToObjectConverter; @@ -149,6 +148,7 @@ public class ResultsEventProcessor { private static final String NOTIFICATION_ID = "notificationId"; private static final String EMAIL_TEMPLATE_ID = "emailTemplateId"; private static final String SEND_TO_ADDRESS = "sendToAddress"; + private static final String BAIL_CONDITIONS_CANCELLED= "Bail Conditions Cancelled"; public static final String HEARING_DAY = "hearingDay"; public static final String PUBLIC_RESULTS_POLICE_RESULT_GENERATED = "public.results.police-result-generated"; @@ -729,13 +729,14 @@ protected String getCaseSubject(final List caseDefendants) { .filter(judicialResult -> { String policeSubjectLineTitle = judicialResult.getPoliceSubjectLineTitle(); String resultText = judicialResult.getResultText(); - return !(policeSubjectLineTitle != null && policeSubjectLineTitle.equals("Bail Conditions Cancelled") - && (resultText != null && (resultText.contains("Domestic Violence case") || resultText.contains("Vulnerable or Intimidated Victim")))); + return !(policeSubjectLineTitle != null && policeSubjectLineTitle.equals(BAIL_CONDITIONS_CANCELLED) + && (resultText != null && !resultText.toLowerCase().contains(BAIL_CONDITIONS_CANCELLED.toLowerCase()))); }) .map(JudicialResult::getPoliceSubjectLineTitle) .filter(StringUtils::isNotEmpty) .distinct() .collect(Collectors.joining(DELIMITER)); + return caseSubject.isEmpty() ? "" : caseSubject; } diff --git a/results-event/results-event-processor/src/test/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessorTest.java b/results-event/results-event-processor/src/test/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessorTest.java index b084f1cbf..c73a4df05 100644 --- a/results-event/results-event-processor/src/test/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessorTest.java +++ b/results-event/results-event-processor/src/test/java/uk/gov/moj/cpp/results/event/processor/ResultsEventProcessorTest.java @@ -82,14 +82,14 @@ import uk.gov.moj.cpp.results.event.service.DocumentGeneratorService; import uk.gov.moj.cpp.results.event.service.EmailNotification; import uk.gov.moj.cpp.results.event.service.EventGridService; -import uk.gov.moj.cpp.results.event.service.FileService; import uk.gov.moj.cpp.results.event.service.FileParams; +import uk.gov.moj.cpp.results.event.service.FileService; import uk.gov.moj.cpp.results.event.service.NotificationNotifyService; import uk.gov.moj.cpp.results.event.service.ProgressionService; import uk.gov.moj.cpp.results.event.service.ReferenceDataService; +import uk.gov.moj.cpp.results.event.service.SjpService; import uk.gov.moj.cpp.results.event.service.SystemDocGenerator; import uk.gov.moj.cpp.results.test.TestTemplates; -import uk.gov.moj.cpp.results.event.service.SjpService; import java.io.StringReader; import java.nio.charset.Charset; @@ -917,7 +917,7 @@ public void shouldIncludePoliceSubjectLineTitleWhenTitleIsBCC() { ArgumentCaptor documentGenerationRequestArgumentCaptor = ArgumentCaptor.forClass(DocumentGenerationRequest.class); ArgumentCaptor fileJsonObjectArgumentCaptor = ArgumentCaptor.forClass(JsonObject.class); final List policeSubjectLineTitle = asList("Bail Conditions Cancelled", null); - final List resultText = asList("Remanded on conditional bail.", null); + final List resultText = asList("URGENT - Urgent\nUrgent result: Bail Conditions cancelled.", null); final List caseDefendants = getDefendantsWithJudicialResults(policeSubjectLineTitle, resultText); @@ -1012,6 +1012,124 @@ public void shouldIncludePoliceSubjectLineTitleWhenResultTextIsBCCAnd() { } + @Test + public void shouldShowBailConditionsCancelledINSubjectWhenResultTextContainsBCCAndDomesticViolenceCase() { + final String policeEmail = "MO10Mailbox-.CommonPlatform@met.police.uk"; + final String urn = "01ZD1205724"; + final String caseId = "10158815-bef7-47ae-9e86-f3f53917a805"; + final String courtCentre = "Croydon Crown Court"; + final String dateOfHearing = "2026-06-10"; + final String dvResultText = "URGENT - Urgent\nUrgent result: Bail Conditions cancelled, Domestic Violence case."; + + // Offence 1 judicial results + JudicialResult discharged1 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("f7080f37-ce1a-48c1-aec8-93454346b025")) + .withIsNewAmendment(true) + .withPoliceSubjectLineTitle("Final Sentence") + .withResultText("DISCH - Discharged") + .build(); + JudicialResult emEnd1 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("cb3b792d-90d9-4714-8ec8-62040f5fd3d9")) + .withIsNewAmendment(true) + .withResultText("EMONE - Electronic Monitoring End - notify contractor") + .build(); + JudicialResult bccDv1 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("c5971d29-5701-4e67-bfad-ec1b51715dbe")) + .withIsNewAmendment(true) + .withPoliceSubjectLineTitle("Bail Conditions Cancelled") + .withResultText(dvResultText) + .build(); + + // Offence 2 judicial results + JudicialResult discharged2 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("681fad0e-6057-4c21-86c1-7105bb70c5a0")) + .withIsNewAmendment(true) + .withPoliceSubjectLineTitle("Final Sentence") + .withResultText("DISCH - Discharged") + .build(); + JudicialResult emEnd2 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("8b4cb167-f3b9-4502-a68e-30b9473b0ddd")) + .withIsNewAmendment(true) + .withResultText("EMONE - Electronic Monitoring End - notify contractor") + .build(); + JudicialResult bccDv2 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("e7d946f8-4b06-431b-a318-2247f42d0b7b")) + .withIsNewAmendment(true) + .withPoliceSubjectLineTitle("Bail Conditions Cancelled") + .withResultText(dvResultText) + .build(); + + // Offence 3 judicial results + JudicialResult emEnd3 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("b6f6eab8-126f-4315-83cb-1b892842484a")) + .withIsNewAmendment(true) + .withResultText("EMONE - Electronic Monitoring End - notify contractor") + .build(); + JudicialResult oni = JudicialResult.judicialResult() + .withJudicialResultId(fromString("c055456e-ed77-4af5-ae6f-42e324ed8513")) + .withIsNewAmendment(true) + .withResultText("ONI - Offence not on indictment") + .build(); + JudicialResult bccDv3 = JudicialResult.judicialResult() + .withJudicialResultId(fromString("7c2d37de-8e7e-4166-9631-884a63ce6ae9")) + .withIsNewAmendment(true) + .withPoliceSubjectLineTitle("Bail Conditions Cancelled") + .withResultText(dvResultText) + .build(); + + final CaseDefendant natalieGall = caseDefendant() + .withDefendantId(fromString("ba55ed01-9ae5-4397-bdf3-da1e6a0b7c89")) + .withProsecutorReference("2400000000000486216U") + .withOffences(asList( + OffenceDetails.offenceDetails() + .withJudicialResults(asList(discharged1, emEnd1, bccDv1)) + .build(), + OffenceDetails.offenceDetails() + .withJudicialResults(asList(discharged2, emEnd2, bccDv2)) + .build(), + OffenceDetails.offenceDetails() + .withJudicialResults(asList(emEnd3, oni, bccDv3)) + .build() + )) + .withIndividualDefendant(individualDefendant() + .withPerson(createPerson("Billal", "Ahemad", Gender.FEMALE, null, "Miss", null, null)) + .build()) + .build(); + + final PoliceNotificationRequestedV2 event = PoliceNotificationRequestedV2.policeNotificationRequestedV2() + .withNotificationId(randomUUID()) + .withCaseId(caseId) + .withPoliceEmailAddress(policeEmail) + .withAmendReshare("") + .withDateOfHearing(dateOfHearing) + .withUrn(urn) + .withCaseDefendants(asList(natalieGall)) + .withApplicationTypeForCase("") + .withCourtCentre(courtCentre) + .withCaseResultDetails(null) + .build(); + + final JsonEnvelope jsonEnvelope = envelopeFrom( + Envelope.metadataBuilder().withId(randomUUID()).withName("results.event.police-notification-requested-v2").build(), + objectToJsonObjectConverter.convert(event)); + + when(applicationParameters.getCommonPlatformUrl()).thenReturn(COMMON_PLATFORM_URL); + when(applicationParameters.getEmailTemplateId()).thenReturn(POLICE_EMAIL_HEARING_RESULTS_TEMPLATE_ID); + when(applicationParameters.getPoliceEmailHearingResultsTemplateId()).thenReturn(POLICE_EMAIL_HEARING_RESULTS_TEMPLATE_ID); + + resultsEventProcessor.handlePoliceNotificationRequestedV2(jsonEnvelope); + + verify(notificationNotifyService, times(1)).sendEmailNotification(eq(jsonEnvelope), jsonObjectArgumentCaptor.capture()); + verify(systemDocGenerator, times(0)).generateDocument(any(), any()); + + final JsonObject payload = jsonObjectArgumentCaptor.getValue(); + assertThat(payload.getString(FIELD_SEND_TO_ADDRESS), is(policeEmail)); + assertThat(payload.getJsonObject(FIELD_PERSONALISATION).getString(FIELD_URN), is(urn)); + assertThat(payload.getJsonObject(FIELD_PERSONALISATION).getString(FIELD_AMEND_RESHARE), is("no")); + assertThat(payload.getJsonObject(FIELD_PERSONALISATION).getString(FIELD_DEFENDANTS), is("Billal Ahemad")); + assertThat(payload.getJsonObject(FIELD_PERSONALISATION).getString(FILED_SUBJECT), is("01ZD1205724 10-06-2026 Final Sentence / Bail Conditions Cancelled")); + } + @Test public void shouldSendAppealUpdateNotification() { final UUID notificationId = randomUUID(); diff --git a/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/HearingResultedIT.java b/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/HearingResultedIT.java index 832b6ae4e..18d88465f 100644 --- a/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/HearingResultedIT.java +++ b/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/HearingResultedIT.java @@ -8,8 +8,6 @@ import static java.util.Objects.nonNull; import static java.util.UUID.fromString; import static java.util.UUID.randomUUID; -import static uk.gov.justice.services.messaging.JsonObjects.createObjectBuilder; -import static uk.gov.justice.services.messaging.JsonObjects.createReader; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.hamcrest.CoreMatchers.equalTo; @@ -27,6 +25,8 @@ import static uk.gov.justice.core.courts.ProsecutionCase.prosecutionCase; import static uk.gov.justice.core.courts.ProsecutionCaseIdentifier.prosecutionCaseIdentifier; import static uk.gov.justice.core.courts.external.ApiCourtCentre.apiCourtCentre; +import static uk.gov.justice.services.messaging.JsonObjects.createObjectBuilder; +import static uk.gov.justice.services.messaging.JsonObjects.createReader; import static uk.gov.justice.services.test.utils.core.random.RandomGenerator.FUTURE_LOCAL_DATE; import static uk.gov.justice.services.test.utils.core.random.RandomGenerator.STRING; import static uk.gov.moj.cpp.domains.results.shareresults.PublicHearingResulted.publicHearingResulted; @@ -51,6 +51,7 @@ import static uk.gov.moj.cpp.results.it.stub.DcsStub.setupDCSStub; import static uk.gov.moj.cpp.results.it.stub.DcsStub.verifyDCSRequestIsRaised; import static uk.gov.moj.cpp.results.it.stub.NotificationNotifyServiceStub.verifyEmailNotificationIsRaised; +import static uk.gov.moj.cpp.results.it.stub.NotificationNotifyServiceStub.verifyEmailSubjectDoesNotContain; import static uk.gov.moj.cpp.results.it.stub.ProgressionStub.stubGetProgressionCaseExistsByUrn; import static uk.gov.moj.cpp.results.it.stub.ProgressionStub.stubGetProgressionProsecutionCases; import static uk.gov.moj.cpp.results.it.utils.EventGridStub.stubEventGridEndpoint; @@ -76,6 +77,7 @@ import static uk.gov.moj.cpp.results.test.TestTemplates.basicShareResultsTemplateWithOneCaseOneDefendant; import static uk.gov.moj.cpp.results.test.TestTemplates.basicShareResultsV2Template; import static uk.gov.moj.cpp.results.test.TestTemplates.basicShareResultsV2TemplateForIndicatedPlea; +import static uk.gov.moj.cpp.results.test.TestTemplates.basicShareResultsV2TemplateWithBailConditionsCancelled; import static uk.gov.moj.cpp.results.test.TestTemplates.basicShareResultsV2TemplateWithHearingDay; import static uk.gov.moj.cpp.results.test.TestTemplates.basicShareResultsV2WithMagistratesAlongWithOffenceDateCodeTemplate; import static uk.gov.moj.cpp.results.test.TestTemplates.basicShareResultsV2WithVerdictTemplate; @@ -270,6 +272,42 @@ public void testCCForEmailNotificationSuccess() { verifyEmailNotificationIsRaised(List.of(policeEmailAddress)); } + @Test + void shouldIncludeBailConditionsCancelledInEmailSubjectWhenResultTextContainsBailConditionsCancelled() { + final String policeEmailAddress = randomAlphabetic(10) + "@gemail.com"; + final PublicHearingResulted resultsMessage = basicShareResultsV2TemplateWithBailConditionsCancelled(JurisdictionType.CROWN, "URGENT - Urgent\nUrgent result: Bail Conditions cancelled, Domestic Violence case."); + stubSpiOutFlag(true, true, policeEmailAddress); + setOuCodeAndProsecutorAuthority(resultsMessage); + + hearingResultsHaveBeenSharedV2(resultsMessage); + whenPrisonAdminTriesToViewResultsForThePerson(getUserId()); + + LocalDate startDate = resultsMessage.getHearing().getHearingDays().get(0).getSittingDay().toLocalDate(); + startDate = of(startDate.getYear(), startDate.getMonth(), startDate.getDayOfMonth() - 1); + + getSummariesByDate(startDate); + verifyEmailNotificationIsRaised(List.of(policeEmailAddress, "urn123 02-05-2018 Bail Conditions Cancelled")); + } + + @Test + void shouldNotIncludeBailConditionsCancelledInEmailSubjectWhenResultTextContainsUrgentButNotBailConditionsCancelled() { + final String policeEmailAddress = randomAlphabetic(11) + "@gemail.com"; + + final PublicHearingResulted resultsMessage = basicShareResultsV2TemplateWithBailConditionsCancelled(JurisdictionType.CROWN, "URGENT - Urgent\nUrgent result: Domestic Violence case, Vulnerable or Intimidated Victim/Witness"); + stubSpiOutFlag(true, true, policeEmailAddress); + setOuCodeAndProsecutorAuthority(resultsMessage); + + hearingResultsHaveBeenSharedV2(resultsMessage); + whenPrisonAdminTriesToViewResultsForThePerson(getUserId()); + + LocalDate startDate = resultsMessage.getHearing().getHearingDays().get(0).getSittingDay().toLocalDate(); + startDate = of(startDate.getYear(), startDate.getMonth(), startDate.getDayOfMonth() - 1); + + getSummariesByDate(startDate); + + verifyEmailSubjectDoesNotContain(policeEmailAddress, "Bail Conditions Cancelled"); + } + @Test public void testCCForSpiOutFalse() throws JMSException { stubSpiOutFlag(false, true); diff --git a/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/stub/NotificationNotifyServiceStub.java b/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/stub/NotificationNotifyServiceStub.java index bd0ffd126..4f990292d 100644 --- a/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/stub/NotificationNotifyServiceStub.java +++ b/results-integration-test/src/test/java/uk/gov/moj/cpp/results/it/stub/NotificationNotifyServiceStub.java @@ -3,6 +3,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.containing; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.findAll; import static com.github.tomakehurst.wiremock.client.WireMock.notMatching; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; @@ -13,6 +14,9 @@ import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; import static javax.ws.rs.core.Response.Status.ACCEPTED; import static org.awaitility.Awaitility.await; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static uk.gov.justice.services.common.http.HeaderConstants.ID; import java.util.List; @@ -20,6 +24,7 @@ import com.github.tomakehurst.wiremock.client.VerificationException; import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; +import com.github.tomakehurst.wiremock.verification.LoggedRequest; public class NotificationNotifyServiceStub { public static final String NOTIFICATION_NOTIFY_ENDPOINT = "/notificationnotify-service/command/api/rest/notificationnotify/notifications/.*"; @@ -68,4 +73,14 @@ public static void verifyEmailNotificationIsRaised(final List expectedVa }); } + public static void verifyEmailSubjectDoesNotContain(final String email, final String unexpectedValue) { + final RequestPatternBuilder requestPatternBuilder = postRequestedFor(urlPathMatching(NOTIFICATION_NOTIFY_ENDPOINT)) + .withRequestBody(containing(email)); + await().atMost(30, SECONDS).pollInterval(1, SECONDS).until(() -> !findAll(requestPatternBuilder).isEmpty()); + final List requests = findAll(requestPatternBuilder); + final String body = requests.get(0).getBodyAsString(); + assertThat("Email notification body sent to [" + email + "] should not contain [" + unexpectedValue + "]", + body, not(containsString(unexpectedValue))); + } + } diff --git a/test-utilities/src/main/java/uk/gov/moj/cpp/results/test/TestTemplates.java b/test-utilities/src/main/java/uk/gov/moj/cpp/results/test/TestTemplates.java index 34eb25af9..facf9e5df 100644 --- a/test-utilities/src/main/java/uk/gov/moj/cpp/results/test/TestTemplates.java +++ b/test-utilities/src/main/java/uk/gov/moj/cpp/results/test/TestTemplates.java @@ -75,8 +75,6 @@ import java.util.Optional; import java.util.UUID; -import com.google.common.collect.ImmutableList; - @SuppressWarnings({"java:S4738"}) public class TestTemplates { @@ -860,6 +858,48 @@ public static List buildJudicialResultList() { .build()); } + public static List buildBailConditionsCancelledJudicialResultList(final String resultText) { + return singletonList(judicialResult() + .withJudicialResultId(randomUUID()) + .withCategory(JudicialResultCategory.FINAL) + .withCjsCode(CJS_CODE) + .withIsAdjournmentResult(false) + .withIsAvailableForCourtExtract(false) + .withIsConvictedResult(false) + .withIsFinancialResult(false) + .withLabel(LABEL) + .withIsNewAmendment(true) + .withOrderedHearingId(ID) + .withOrderedDate(now()) + .withRank(BigDecimal.ZERO) + .withWelshLabel(LABEL) + .withResultText(resultText) + .withPoliceSubjectLineTitle("Bail Conditions Cancelled") + .withLifeDuration(false) + .withTerminatesOffenceProceedings(Boolean.FALSE) + .withPublishedAsAPrompt(false) + .withExcludedFromResults(false) + .withAlwaysPublished(false) + .withUrgent(false) + .withD20(false) + .withPublishedForNows(false) + .withRollUpPrompts(false) + .withJudicialResultTypeId(randomUUID()) + .withSentToCC(true) + .withCommittedToCC(true) + .build()); + } + + public static PublicHearingResulted basicShareResultsV2TemplateWithBailConditionsCancelled(final JurisdictionType jurisdictionType, final String resultText) { + final UUID hearingId = randomUUID(); + return PublicHearingResulted.publicHearingResulted() + .setHearing(basicShareHearingTemplate(hearingId, + asList(createCaseWithDefendantAndOffenceLevelJudicialResults(buildBailConditionsCancelledJudicialResultList(resultText))), jurisdictionType, false)) + .setIsReshare(Optional.of(false)) + .setHearingDay(Optional.of(LocalDate.of(2018, 5, 2))) + .setSharedTime(ZonedDateTime.now(ZoneId.of("UTC"))); + } + public static CourtApplicationType courtApplicationTypeTemplates() { return CourtApplicationType.courtApplicationType() .withId(randomUUID())