diff --git a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessor.java b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessor.java index 8fc4543937..37d1dc046e 100644 --- a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessor.java +++ b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessor.java @@ -61,7 +61,19 @@ public class CPSEmailNotificationProcessor { private static final String PROGRESSION_COMMAND_FOR_DEFENCE_ORGANISATION_DISASSOCIATED = "progression.command.handler.disassociate-defence-organisation"; + private static final String PROGRESSION_COMMAND_FOR_DEFENCE_ORGANISATION_DISASSOCIATED_FOR_APPLICATION = "progression.command.handler.disassociate-defence-organisation-for-application"; + private static final String PROSECUTION_CASE = "prosecutionCase"; + private static final String PROSECUTION_CASE_IDENTIFIER = "prosecutionCaseIdentifier"; + private static final String PROSECUTION_AUTHORITY_CODE = "prosecutionAuthorityCode"; + private static final String CPS_AUTHORITY_CODE_PREFIX = "CPS"; private static final String IS_LAA = "isLAA"; + private static final String IS_CIVIL = "isCivil"; + private static final String CASE_ID = "caseId"; + private static final String FIRST_INSTRUCTION = "firstInstruction"; + private static final String HEARINGS_AT_A_GLANCE = "hearingsAtAGlance"; + private static final String CPS_EMAIL_ADDRESS = "cpsEmailAddress"; + private static final String DEFENDANTS = "defendants"; + private static final String ID = "id"; public static final String LINKED_APPLICATIONS = "linkedApplications"; public static final String APPLICATION_ID = "applicationId"; public static final String DEFENDANT_ID = "defendantId"; @@ -92,7 +104,7 @@ public class CPSEmailNotificationProcessor { public void processDisassociatedEmailNotification(final JsonEnvelope jsonEnvelope) { final JsonObject requestJson = jsonEnvelope.payloadAsJsonObject(); final boolean isLAA = parseBoolean(requestJson.containsKey(IS_LAA) ? requestJson.get(IS_LAA).toString() : "false"); - final UUID caseId = fromString(requestJson.getString("caseId")); + final UUID caseId = fromString(requestJson.getString(CASE_ID)); if (!isLAA) { sendCommandDisassociateDefenceOrganisation(jsonEnvelope, requestJson); @@ -121,7 +133,7 @@ private void sendCommandDisassociateDefenceOrganisationForApplication(final Json .add(ORGANISATION_ID, requestJson.getString(ORGANISATION_ID)); sender.send( envelop(disassociateDefenceOrganisationForApplicationBuilder.build()) - .withName("progression.command.handler.disassociate-defence-organisation-for-application") + .withName(PROGRESSION_COMMAND_FOR_DEFENCE_ORGANISATION_DISASSOCIATED_FOR_APPLICATION) .withMetadataFrom(jsonEnvelope)); } }); @@ -131,18 +143,25 @@ private void sendCommandDisassociateDefenceOrganisationForApplication(final Json @Handles("public.defence.event.record-instruction-details") public void processInstructedEmailNotification(final JsonEnvelope jsonEnvelope) { final JsonObject requestJson = jsonEnvelope.payloadAsJsonObject(); - final boolean isFirstInstruction = parseBoolean(requestJson.get("firstInstruction").toString()); + final boolean isFirstInstruction = parseBoolean(requestJson.get(FIRST_INSTRUCTION).toString()); if (isFirstInstruction) { populateCPSNotification(jsonEnvelope, requestJson, EmailTemplateType.INSTRUCTION); } } private void populateCPSNotification(final JsonEnvelope jsonEnvelope, final JsonObject requestJson, final EmailTemplateType templateType) { - final String caseId = requestJson.getString("caseId"); + final String caseId = requestJson.getString(CASE_ID); final String defendantId = requestJson.getString(DEFENDANT_ID); final UUID organisationId = fromString(requestJson.getString(ORGANISATION_ID)); final Optional prosecutionCaseOptional = progressionService.getProsecutionCaseDetailById(jsonEnvelope, caseId); + + final boolean isCivil = isCivilCase(prosecutionCaseOptional); + if (isCivil && !isCpsProsecutor(prosecutionCaseOptional)) { + log.info("Skipping CPS notification: civil case {} is not a CPS prosecution", caseId); + return; + } + final Optional hearingVO = getHearingDetails(prosecutionCaseOptional); final boolean isHearingPresent = hearingVO.isPresent() && hearingVO.get().getHearingDate() != null; @@ -177,12 +196,32 @@ private void populateCPSNotificationAndSendEmail(final JsonEnvelope jsonEnvelope } } + private boolean isCivilCase(final Optional prosecutionCaseOptional) { + if (prosecutionCaseOptional.isEmpty()) { + return false; + } + return prosecutionCaseOptional.get().getJsonObject(PROSECUTION_CASE).getBoolean(IS_CIVIL, false); + } + + private boolean isCpsProsecutor(final Optional prosecutionCaseOptional) { + if (prosecutionCaseOptional.isEmpty()) { + return false; + } + final JsonObject prosecutionCaseJson = prosecutionCaseOptional.get().getJsonObject(PROSECUTION_CASE); + if (!prosecutionCaseJson.containsKey(PROSECUTION_CASE_IDENTIFIER)) { + return false; + } + final String prosecutionAuthorityCode = prosecutionCaseJson.getJsonObject(PROSECUTION_CASE_IDENTIFIER) + .getString(PROSECUTION_AUTHORITY_CODE, ""); + return prosecutionAuthorityCode.toUpperCase().startsWith(CPS_AUTHORITY_CODE_PREFIX); + } + private Optional getDefendantDetails(final String defendantId, final Optional prosecutionCaseOptional) { final Optional defendantVO = Optional.empty(); final JsonObject prosecutionCaseJson = prosecutionCaseOptional - .orElseThrow(() -> new RuntimeException("Prosecution Case not found")).getJsonObject("prosecutionCase"); + .orElseThrow(() -> new RuntimeException("Prosecution Case not found")).getJsonObject(PROSECUTION_CASE); final JsonObject defendantJson = getDefendantJson(prosecutionCaseJson, fromString(defendantId)); @@ -210,7 +249,7 @@ private Optional getDefendantDetails(final String defendantId, fina private Optional getCaseDetails(final Optional prosecutionCaseOptional) { final JsonObject prosecutionCaseJson = prosecutionCaseOptional - .orElseThrow(() -> new RuntimeException("Prosecution Case not found")).getJsonObject("prosecutionCase"); + .orElseThrow(() -> new RuntimeException("Prosecution Case not found")).getJsonObject(PROSECUTION_CASE); final ProsecutionCase prosecutionCase = jsonObjectToObjectConverter.convert(prosecutionCaseJson, ProsecutionCase.class); final String caseURN = prosecutionCase.getProsecutionCaseIdentifier().getCaseURN(); @@ -228,7 +267,7 @@ private Optional getHearingDetails(final Optional prosecu if (prosecutionCaseOptional.isPresent()) { - final JsonObject hearingAtAGlanceJsonObject = prosecutionCaseOptional.get().getJsonObject("hearingsAtAGlance"); + final JsonObject hearingAtAGlanceJsonObject = prosecutionCaseOptional.get().getJsonObject(HEARINGS_AT_A_GLANCE); final GetHearingsAtAGlance hearingAtAGlance = jsonObjectToObjectConverter.convert(hearingAtAGlanceJsonObject, GetHearingsAtAGlance.class); final List futureHearings = getFutureHearings(hearingAtAGlance); @@ -260,7 +299,7 @@ private List getFutureHearings(GetHearingsAtAGlance hearingsAtAGlance) private Optional getHearingVO(final String hearingDate, List futureHearings, final Optional> resultMap) { final List resultHearing = futureHearings.stream() .filter(hearing -> hearing.getId().equals(resultMap.get().getKey())) - .collect(Collectors.toList()); + .toList(); final Hearings hearing = resultHearing.get(0); final String courtName = hearing.getCourtCentre().getName(); @@ -298,7 +337,7 @@ private Optional getCPSEmail(final JsonEnvelope jsonEnvelope, final UUID .getOrganisationUnitById(courtCenterId, jsonEnvelope, requester); if (organisationUnitJsonOptional.isPresent()) { - cpsEmail = Optional.ofNullable(organisationUnitJsonOptional.get().getString("cpsEmailAddress", null)); + cpsEmail = Optional.ofNullable(organisationUnitJsonOptional.get().getString(CPS_EMAIL_ADDRESS, null)); if (cpsEmail.isPresent()) { log.info("Found CPS email: {}", cpsEmail); } @@ -316,8 +355,8 @@ private static ZonedDateTime getEarliestHearingDay(final List hearin } private JsonObject getDefendantJson(final JsonObject prosecutionCaseJson, final UUID defendantId) { - return prosecutionCaseJson.getJsonArray("defendants").getValuesAs(JsonObject.class).stream() - .filter(e -> defendantId.toString().equals(e.getString("id"))) + return prosecutionCaseJson.getJsonArray(DEFENDANTS).getValuesAs(JsonObject.class).stream() + .filter(e -> defendantId.toString().equals(e.getString(ID))) .findFirst() .orElseThrow(IllegalArgumentException::new); } diff --git a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessorTest.java b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessorTest.java index 47d4427fc0..2fdb71ff9b 100644 --- a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessorTest.java +++ b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/CPSEmailNotificationProcessorTest.java @@ -8,6 +8,7 @@ import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -401,6 +402,220 @@ void shouldCallDisassociationCommandForCaseAndApplicationWhenApplicationForCaseH } + @Test + public void shouldSendCPSNotificationForCivilCaseWhenProsecutionAuthorityIsCPS() { + final UUID caseId = randomUUID(); + final UUID defendantId = randomUUID(); + final UUID organisationId = randomUUID(); + final UUID hearingId = randomUUID(); + final UUID courtCentreId = randomUUID(); + + final JsonObject cpsProsecutionCaseResponse = createObjectBuilder() + .add("prosecutionCase", createObjectBuilder() + .add("id", caseId.toString()) + .add("isCivil", true) + .add("prosecutionCaseIdentifier", createObjectBuilder() + .add("prosecutionAuthorityReference", "CPS12345") + .add("prosecutionAuthorityCode", "CPS") + .build()) + .add("defendants", createArrayBuilder() + .add(createObjectBuilder() + .add("id", defendantId.toString()) + .add("personDefendant", createObjectBuilder() + .add("personDetails", createObjectBuilder() + .add("firstName", "Fred") + .add("lastName", "Smith") + .build()) + .build()) + .build()) + .build()) + .build()) + .add("hearingsAtAGlance", createObjectBuilder() + .add("hearings", createArrayBuilder() + .add(createObjectBuilder() + .add("id", hearingId.toString()) + .add("hearingListingStatus", "HEARING_INITIALISED") + .add("courtCentre", createObjectBuilder() + .add("id", courtCentreId.toString()) + .add("name", "Test Court") + .build()) + .add("hearingDays", createArrayBuilder() + .add(createObjectBuilder() + .add("sittingDay", "2099-12-31T09:00:00.000Z") + .build()) + .build()) + .build()) + .build()) + .build()) + .build(); + + final JsonObject instructionPayload = createObjectBuilder() + .add("firstInstruction", true) + .add("caseId", caseId.toString()) + .add("defendantId", defendantId.toString()) + .add("organisationId", organisationId.toString()) + .build(); + + final JsonEnvelope envelope = JsonEnvelope.envelopeFrom( + MetadataBuilderFactory.metadataWithRandomUUID("public.defence.event.record-instruction-details"), + instructionPayload); + + when(progressionService.getProsecutionCaseDetailById(any(), any())) + .thenReturn(Optional.of(cpsProsecutionCaseResponse)); + when(referenceDataService.getOrganisationUnitById(any(), any(), any())) + .thenReturn(Optional.of(createObjectBuilder().add("cpsEmailAddress", "cps@court.gov.uk").build())); + when(usersGroupService.getDefenceOrganisationDetails(any(), any())) + .thenReturn(buildDefenceOrganisationVO()); + + cpsEmailNotificationProcessor.processInstructedEmailNotification(envelope); + + verify(notificationService, times(1)).sendCPSNotification(any(), any()); + } + + @Test + public void shouldSkipCPSNotificationForCivilCaseWhenProsecutionAuthorityIsNotCPS() { + final UUID caseId = randomUUID(); + final UUID defendantId = randomUUID(); + final UUID organisationId = randomUUID(); + + final JsonObject tflProsecutionCaseResponse = createObjectBuilder() + .add("prosecutionCase", createObjectBuilder() + .add("id", caseId.toString()) + .add("isCivil", true) + .add("prosecutionCaseIdentifier", createObjectBuilder() + .add("prosecutionAuthorityReference", "TFL12345") + .add("prosecutionAuthorityCode", "TFL") + .build()) + .build()) + .build(); + + final JsonObject instructionPayload = createObjectBuilder() + .add("firstInstruction", true) + .add("caseId", caseId.toString()) + .add("defendantId", defendantId.toString()) + .add("organisationId", organisationId.toString()) + .build(); + + final JsonEnvelope envelope = JsonEnvelope.envelopeFrom( + MetadataBuilderFactory.metadataWithRandomUUID("public.defence.event.record-instruction-details"), + instructionPayload); + + when(progressionService.getProsecutionCaseDetailById(any(), any())) + .thenReturn(Optional.of(tflProsecutionCaseResponse)); + + cpsEmailNotificationProcessor.processInstructedEmailNotification(envelope); + + verify(notificationService, never()).sendCPSNotification(any(), any()); + } + + @Test + public void shouldNotifyCPSWhenLAADisassociationFromCPSCivilCase() { + final UUID caseId = randomUUID(); + final UUID defendantId = randomUUID(); + final UUID organisationId = randomUUID(); + final UUID hearingId = randomUUID(); + final UUID courtCentreId = randomUUID(); + + final JsonObject cpsCivilCaseResponse = createObjectBuilder() + .add("prosecutionCase", createObjectBuilder() + .add("id", caseId.toString()) + .add("isCivil", true) + .add("prosecutionCaseIdentifier", createObjectBuilder() + .add("prosecutionAuthorityReference", "CPS12345") + .add("prosecutionAuthorityCode", "CPS") + .build()) + .add("defendants", createArrayBuilder() + .add(createObjectBuilder() + .add("id", defendantId.toString()) + .add("personDefendant", createObjectBuilder() + .add("personDetails", createObjectBuilder() + .add("firstName", "Fred") + .add("lastName", "Smith") + .build()) + .build()) + .build()) + .build()) + .build()) + .add("hearingsAtAGlance", createObjectBuilder() + .add("hearings", createArrayBuilder() + .add(createObjectBuilder() + .add("id", hearingId.toString()) + .add("hearingListingStatus", "HEARING_INITIALISED") + .add("courtCentre", createObjectBuilder() + .add("id", courtCentreId.toString()) + .add("name", "Test Court") + .build()) + .add("hearingDays", createArrayBuilder() + .add(createObjectBuilder() + .add("sittingDay", "2099-12-31T09:00:00.000Z") + .build()) + .build()) + .build()) + .build()) + .build()) + .build(); + + final JsonObject disassociationPayload = createObjectBuilder() + .add("caseId", caseId.toString()) + .add("defendantId", defendantId.toString()) + .add("organisationId", organisationId.toString()) + .add("isLAA", true) + .build(); + + final JsonEnvelope envelope = JsonEnvelope.envelopeFrom( + MetadataBuilderFactory.metadataWithRandomUUID("public.defence.defence-organisation-disassociated"), + disassociationPayload); + + when(progressionService.getProsecutionCaseDetailById(any(), any())) + .thenReturn(Optional.of(cpsCivilCaseResponse)); + when(referenceDataService.getOrganisationUnitById(any(), any(), any())) + .thenReturn(Optional.of(createObjectBuilder().add("cpsEmailAddress", "cps@court.gov.uk").build())); + when(usersGroupService.getDefenceOrganisationDetails(any(), any())) + .thenReturn(buildDefenceOrganisationVO()); + + cpsEmailNotificationProcessor.processDisassociatedEmailNotification(envelope); + + verify(notificationService, times(1)).sendCPSNotification(any(), any()); + verify(sender, never()).send(any()); + } + + @Test + public void shouldNotNotifyCPSWhenLAADisassociationFromNonCPSCivilCase() { + final UUID caseId = randomUUID(); + final UUID defendantId = randomUUID(); + final UUID organisationId = randomUUID(); + + final JsonObject nonCpsCivilCaseResponse = createObjectBuilder() + .add("prosecutionCase", createObjectBuilder() + .add("id", caseId.toString()) + .add("isCivil", true) + .add("prosecutionCaseIdentifier", createObjectBuilder() + .add("prosecutionAuthorityReference", "TFL12345") + .add("prosecutionAuthorityCode", "TFL") + .build()) + .build()) + .build(); + + final JsonObject disassociationPayload = createObjectBuilder() + .add("caseId", caseId.toString()) + .add("defendantId", defendantId.toString()) + .add("organisationId", organisationId.toString()) + .add("isLAA", true) + .build(); + + final JsonEnvelope envelope = JsonEnvelope.envelopeFrom( + MetadataBuilderFactory.metadataWithRandomUUID("public.defence.defence-organisation-disassociated"), + disassociationPayload); + + when(progressionService.getProsecutionCaseDetailById(any(), any())) + .thenReturn(Optional.of(nonCpsCivilCaseResponse)); + + cpsEmailNotificationProcessor.processDisassociatedEmailNotification(envelope); + + verify(notificationService, never()).sendCPSNotification(any(), any()); + verify(sender, never()).send(any()); + } + private JsonObject getProsecutionCaseResponse(String sampleJson) { String response = null; try { diff --git a/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/CPSNotificationIT.java b/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/CPSNotificationIT.java index 4e05fdfec9..3f29475da1 100644 --- a/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/CPSNotificationIT.java +++ b/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/CPSNotificationIT.java @@ -19,17 +19,23 @@ import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static javax.json.Json.createObjectBuilder; import static uk.gov.justice.services.integrationtest.utils.jms.JmsMessageProducerClientProvider.newPublicJmsMessageProducerClientProvider; import static uk.gov.justice.services.messaging.JsonEnvelope.envelopeFrom; +import static uk.gov.moj.cpp.progression.helper.PreAndPostConditionHelper.addCPSProsecutionCaseToCrownCourt; +import static uk.gov.moj.cpp.progression.helper.PreAndPostConditionHelper.addCivilProsecutionCaseToCourt; import static uk.gov.moj.cpp.progression.helper.PreAndPostConditionHelper.addProsecutionCaseToCrownCourt; +import uk.gov.moj.cpp.progression.util.CaseProsecutorUpdateHelper; import static uk.gov.moj.cpp.progression.helper.PreAndPostConditionHelper.pollCaseAndGetHearingForDefendant; import static uk.gov.moj.cpp.progression.helper.PreAndPostConditionHelper.pollHearingWithStatusInitialised; import static uk.gov.moj.cpp.progression.helper.QueueUtil.buildMetadata; import static uk.gov.moj.cpp.progression.stub.NotificationServiceStub.verifyEmailNotificationIsRaisedWithoutAttachment; +import static uk.gov.moj.cpp.progression.stub.NotificationServiceStub.verifyNoEmailNotificationIsRaised; import static uk.gov.moj.cpp.progression.stub.UsersAndGroupsStub.stubGetOrganisationDetails; public class CPSNotificationIT extends AbstractIT { private static final String PUBLIC_DEFENCE_RECORD_INSTRUCTED = "public.defence.event.record-instruction-details"; + private static final String PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED = "public.defence.defence-organisation-disassociated"; private static final String PUBLIC_DEFENCE_RECORD_INSTRUCTED_FILE = "public.defence.event.record-instruction-details.json"; private static final String PUBLIC_LISTING_HEARING_CONFIRMED = "public.listing.hearing-confirmed"; private static final String PUBLIC_LISTING_HEARING_CONFIRMED_FILE = "public.listing.hearing-confirmed-cps-notification.json"; @@ -58,8 +64,8 @@ public void setUp() { } @Test - public void shouldNotifyCPS() throws Exception { - addProsecutionCaseToCrownCourt(caseId, defendantId); + public void shouldNotifyCPSWhenDefenceAssociatedWithCPSCriminalCase() throws Exception { + addCPSProsecutionCaseToCrownCourt(caseId, defendantId); hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, @@ -79,6 +85,149 @@ public void shouldNotifyCPS() throws Exception { verifyEmailNotificationIsRaisedWithoutAttachment(newArrayList(ORGANISATION_NAME)); } + @Test + public void shouldNotNotifyCPSWhenProsecutorIsNotCPS() throws Exception { + addProsecutionCaseToCrownCourt(caseId, defendantId); + hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); + + final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, + caseId, hearingId, defendantId, courtCentreId, courtCentreName)); + messageProducerClientPublic.sendMessage(PUBLIC_LISTING_HEARING_CONFIRMED, publicEventEnvelope); + + pollHearingWithStatusInitialised(hearingId); + + final JsonObject recordInstructedPublicEvent = + getInstructedJsonObject(PUBLIC_DEFENCE_RECORD_INSTRUCTED_FILE, caseId, hearingId, defendantId, courtCentreId, courtCentreName); + Thread.sleep(1000 * 5); + final JsonEnvelope publicEventInstructedEnvelope = envelopeFrom(buildMetadata(PUBLIC_DEFENCE_RECORD_INSTRUCTED, userId), recordInstructedPublicEvent); + messageProducerClientPublic.sendMessage(PUBLIC_DEFENCE_RECORD_INSTRUCTED, publicEventInstructedEnvelope); + + verifyNoEmailNotificationIsRaised(); + } + + @Test + public void shouldNotifyCPSWhenDefenceAssociatedWithCPSCivilCase() throws Exception { + addCivilProsecutionCaseToCourt(caseId, defendantId); + hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); + new CaseProsecutorUpdateHelper(caseId).updateCaseProsecutor(); + + final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, + caseId, hearingId, defendantId, courtCentreId, courtCentreName)); + messageProducerClientPublic.sendMessage(PUBLIC_LISTING_HEARING_CONFIRMED, publicEventEnvelope); + + pollHearingWithStatusInitialised(hearingId); + + final JsonObject recordInstructedPublicEvent = + getInstructedJsonObject(PUBLIC_DEFENCE_RECORD_INSTRUCTED_FILE, caseId, hearingId, defendantId, courtCentreId, courtCentreName); + Thread.sleep(1000 * 5); + final JsonEnvelope publicEventInstructedEnvelope = envelopeFrom(buildMetadata(PUBLIC_DEFENCE_RECORD_INSTRUCTED, userId), recordInstructedPublicEvent); + messageProducerClientPublic.sendMessage(PUBLIC_DEFENCE_RECORD_INSTRUCTED, publicEventInstructedEnvelope); + + verifyEmailNotificationIsRaisedWithoutAttachment(newArrayList(ORGANISATION_NAME)); + } + + @Test + public void shouldNotNotifyCPSWhenProsecutorIsNotCPSAndDefenceAssociatedWithCivilCase() throws Exception { + addCivilProsecutionCaseToCourt(caseId, defendantId); + hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); + + final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, + caseId, hearingId, defendantId, courtCentreId, courtCentreName)); + messageProducerClientPublic.sendMessage(PUBLIC_LISTING_HEARING_CONFIRMED, publicEventEnvelope); + + pollHearingWithStatusInitialised(hearingId); + + final JsonObject recordInstructedPublicEvent = + getInstructedJsonObject(PUBLIC_DEFENCE_RECORD_INSTRUCTED_FILE, caseId, hearingId, defendantId, courtCentreId, courtCentreName); + Thread.sleep(1000 * 5); + final JsonEnvelope publicEventInstructedEnvelope = envelopeFrom(buildMetadata(PUBLIC_DEFENCE_RECORD_INSTRUCTED, userId), recordInstructedPublicEvent); + messageProducerClientPublic.sendMessage(PUBLIC_DEFENCE_RECORD_INSTRUCTED, publicEventInstructedEnvelope); + + verifyNoEmailNotificationIsRaised(); + } + + @Test + public void shouldNotifyCPSWhenDefenceDisassociatedFromCPSCriminalCase() throws Exception { + addCPSProsecutionCaseToCrownCourt(caseId, defendantId); + hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); + + final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, + caseId, hearingId, defendantId, courtCentreId, courtCentreName)); + messageProducerClientPublic.sendMessage(PUBLIC_LISTING_HEARING_CONFIRMED, publicEventEnvelope); + + pollHearingWithStatusInitialised(hearingId); + + Thread.sleep(1000 * 5); + final JsonEnvelope disassociationEnvelope = envelopeFrom(buildMetadata(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, userId), buildDisassociationPayload()); + messageProducerClientPublic.sendMessage(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, disassociationEnvelope); + + verifyEmailNotificationIsRaisedWithoutAttachment(newArrayList(ORGANISATION_NAME)); + } + + @Test + public void shouldNotNotifyCPSWhenProsecutorIsNotCPSAndDefenceDisassociatedFromCriminalCase() throws Exception { + addProsecutionCaseToCrownCourt(caseId, defendantId); + hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); + + final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, + caseId, hearingId, defendantId, courtCentreId, courtCentreName)); + messageProducerClientPublic.sendMessage(PUBLIC_LISTING_HEARING_CONFIRMED, publicEventEnvelope); + + pollHearingWithStatusInitialised(hearingId); + + Thread.sleep(1000 * 5); + final JsonEnvelope disassociationEnvelope = envelopeFrom(buildMetadata(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, userId), buildDisassociationPayload()); + messageProducerClientPublic.sendMessage(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, disassociationEnvelope); + + verifyNoEmailNotificationIsRaised(); + } + + @Test + public void shouldNotifyCPSWhenDefenceDisassociatedFromCPSCivilCase() throws Exception { + addCivilProsecutionCaseToCourt(caseId, defendantId); + hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); + new CaseProsecutorUpdateHelper(caseId).updateCaseProsecutor(); + + final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, + caseId, hearingId, defendantId, courtCentreId, courtCentreName)); + messageProducerClientPublic.sendMessage(PUBLIC_LISTING_HEARING_CONFIRMED, publicEventEnvelope); + + pollHearingWithStatusInitialised(hearingId); + + Thread.sleep(1000 * 5); + final JsonEnvelope disassociationEnvelope = envelopeFrom(buildMetadata(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, userId), buildDisassociationPayload()); + messageProducerClientPublic.sendMessage(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, disassociationEnvelope); + + verifyEmailNotificationIsRaisedWithoutAttachment(newArrayList(ORGANISATION_NAME)); + } + + @Test + public void shouldNotNotifyCPSWhenProsecutorIsNotCPSAndDefenceDisassociatedFromCivilCase() throws Exception { + addCivilProsecutionCaseToCourt(caseId, defendantId); + hearingId = pollCaseAndGetHearingForDefendant(caseId, defendantId); + + final JsonEnvelope publicEventEnvelope = envelopeFrom(buildMetadata(PUBLIC_LISTING_HEARING_CONFIRMED, userId), getInstructedJsonObject(PUBLIC_LISTING_HEARING_CONFIRMED_FILE, + caseId, hearingId, defendantId, courtCentreId, courtCentreName)); + messageProducerClientPublic.sendMessage(PUBLIC_LISTING_HEARING_CONFIRMED, publicEventEnvelope); + + pollHearingWithStatusInitialised(hearingId); + + Thread.sleep(1000 * 5); + final JsonEnvelope disassociationEnvelope = envelopeFrom(buildMetadata(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, userId), buildDisassociationPayload()); + messageProducerClientPublic.sendMessage(PUBLIC_DEFENCE_ORGANISATION_DISASSOCIATED, disassociationEnvelope); + + verifyNoEmailNotificationIsRaised(); + } + + private JsonObject buildDisassociationPayload() { + return createObjectBuilder() + .add("caseId", caseId) + .add("defendantId", defendantId) + .add("organisationId", ORGANISATION_ID) + .add("isLAA", false) + .build(); + } + private JsonObject getInstructedJsonObject(final String path, final String caseId, final String hearingId, final String defendantId, final String courtCentreId, final String courtCentreName) { final String strPayload = getPayloadForCreatingRequest(path) diff --git a/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/helper/PreAndPostConditionHelper.java b/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/helper/PreAndPostConditionHelper.java index 094e1e0f27..6679046086 100644 --- a/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/helper/PreAndPostConditionHelper.java +++ b/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/helper/PreAndPostConditionHelper.java @@ -195,6 +195,24 @@ public static Response addProsecutionCaseToCrownCourt(final String caseId, final jsonPayload.toString()); } + public static Response addCPSProsecutionCaseToCrownCourt(final String caseId, final String defendantId) throws JSONException { + final JSONObject jsonPayload = new JSONObject(createReferProsecutionCaseToCrownCourtJsonBody(caseId, defendantId, randomUUID().toString(), + randomUUID().toString(), randomUUID().toString(), randomUUID().toString(), generateUrn(), + "progression.command.prosecution-case-refer-to-court-cps.json")); + jsonPayload.getJSONObject("courtReferral").remove("courtDocuments"); + return postCommand(getWriteUrl("/refertocourt"), + APPLICATION_VND_PROGRESSION_REFER_CASES_TO_COURT_JSON, + jsonPayload.toString()); + } + + public static Response addCivilProsecutionCaseToCourt(final String caseId, final String defendantId) { + final String listedStartDateTime = ZonedDateTimes.fromString("2019-06-30T18:32:04.238Z").toString(); + final String earliestStartDateTime = ZonedDateTimes.fromString("2019-05-30T18:32:04.238Z").toString(); + final String dob = LocalDate.now().minusYears(25).toString(); + return civilCaseInitiateCourtProceedings(caseId, defendantId, randomUUID().toString(), randomUUID().toString(), + randomUUID().toString(), listedStartDateTime, earliestStartDateTime, dob, randomUUID().toString()); + } + public static Response addProsecutionCaseToCrownCourtFirstHearing(final String caseId, final String defendantId, final String caseUrn, final boolean isYouth) throws JSONException { final JSONObject jsonPayload = new JSONObject(createReferProsecutionCaseToCrownCourtFirstHearingJsonBody(caseId, defendantId, randomUUID().toString(), randomUUID().toString(), randomUUID().toString(), randomUUID().toString(), caseUrn, isYouth)); diff --git a/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/stub/NotificationServiceStub.java b/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/stub/NotificationServiceStub.java index 967fa9a9c9..ef8e8c79f8 100644 --- a/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/stub/NotificationServiceStub.java +++ b/progression-integration-test/src/test/java/uk/gov/moj/cpp/progression/stub/NotificationServiceStub.java @@ -89,6 +89,18 @@ public static void verifyEmailNotificationIsRaisedWithoutAttachment(final List { + try { + verify(exactly(0), postRequestedFor(urlPathMatching(NOTIFICATION_NOTIFY_ENDPOINT)) + .withHeader(CONTENT_TYPE, equalTo(NOTIFICATIONNOTIFY_SEND_EMAIL_NOTIFICATION_JSON))); + return true; + } catch (VerificationException e) { + return false; + } + }); + } + public static void verifyEmailNotificationIsRaisedWithAttachment(final List expectedValues) { verifyEmailNotificationIsRaisedWithAttachment(expectedValues, Optional.empty()); } diff --git a/progression-integration-test/src/test/resources/progression.command.prosecution-case-refer-to-court-cps.json b/progression-integration-test/src/test/resources/progression.command.prosecution-case-refer-to-court-cps.json new file mode 100644 index 0000000000..f943b0d924 --- /dev/null +++ b/progression-integration-test/src/test/resources/progression.command.prosecution-case-refer-to-court-cps.json @@ -0,0 +1,264 @@ +{ + "courtReferral": { + "sjpReferral": { + "noticeDate": "2018-01-01", + "referralDate": "2018-02-15", + "referringJudicialDecision": { + "location": "Lavender Hill Magistrates' Court", + "judiciary": [ + { + "judicialName": "Mrs Theresa Mary May", + "judicialRoleTypeSJP": "MAGISTRATE" + }, + { + "judicialName": "Mr Michel Bernard Barnier", + "judicialRoleTypeSJP": "MAGISTRATE" + } + ] + } + }, + "prosecutionCases": [ + { + "id": "RANDOM_CASE_ID", + "prosecutionCaseIdentifier": { + "prosecutionAuthorityId": "cf73207f-3ced-488a-82a0-3fba79c2ce85", + "prosecutionAuthorityCode": "CPS", + "prosecutionAuthorityReference": "RANDOM_REFERENCE" + }, + "originatingOrganisation": "G01FT01AB", + "initiationCode": "J", + "statementOfFacts": "You did it", + "statementOfFactsWelsh": "You did it in Welsh", + "defendants": [ + { + "id": "RANDOM_DEFENDANT_ID", + "prosecutionCaseId": "RANDOM_CASE_ID", + "numberOfPreviousConvictionsCited": 5, + "prosecutionAuthorityReference": "CPS12345-ABC", + "witnessStatement": "he did not do it", + "witnessStatementWelsh": "he did not do it in Welsh", + "mitigation": "I was not there", + "mitigationWelsh": "I was not there in Welsh", + "defenceOrganisation": { + "name": "defence Organisation abc" + }, + "offences": [ + { + "id": "3789ab16-0bb7-4ef1-87ef-c936bf0364f1", + "offenceDefinitionId": "490dce00-8591-49af-b2d0-1e161e7d0c36", + "wording": "No Travel Card", + "wordingWelsh": "No Travel Card In Welsh", + "startDate": "2018-01-01", + "endDate": "2018-01-01", + "arrestDate": "2018-01-01", + "chargeDate": "2018-01-01", + "orderIndex": 1, + "count": 0, + "notifiedPlea": { + "offenceId": "3789ab16-0bb7-4ef1-87ef-c936bf0364f1", + "notifiedPleaDate": "2018-04-01", + "notifiedPleaValue": "NOTIFIED_GUILTY" + }, + "offenceFacts": { + "vehicleRegistration": "AA12345", + "alcoholReadingAmount": 111, + "alcoholReadingMethodCode": "2222" + }, + "maxPenalty": "Max Penalty", + "reportingRestrictions": [ + { + "id": "3789ab16-e588-4b7f-806a-44dc0eb0e75e", + "label": "Complainant's anonymity protected by virtue of Section 1 of the Sexual Offences Amendment Act 1992", + "orderedDate": "2021-08-28" + }, + { + "id": "6fdc9e9d-6f0a-4d02-92e9-bc5765475182", + "label": "Complainant's anonymity protected by virtue of Section 1 of the Sexual Offences Amendment Act 1992", + "orderedDate": "2021-08-28" + } + ], + "offenceDateCode": 4 + } + ], + "associatedPersons": [ + { + "person": { + "title": "DR", + "firstName": "Harry", + "middleName": "Jack", + "lastName": "Kane", + "dateOfBirth": "1995-01-01", + "nationalityId": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "additionalNationalityId": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "disabilityStatus": "a", + "gender": "MALE", + "interpreterLanguageNeeds": "Hindi", + "documentationLanguageNeeds": "WELSH", + "nationalInsuranceNumber": "NH222222B", + "occupation": "Footballer", + "occupationCode": "F", + "address": { + "address1": "22", + "address2": "Acacia Avenue", + "address3": "Acacia Town", + "address4": "Acacia City", + "address5": "Acacia Country", + "postcode": "CR7 0AA" + }, + "contact": { + "home": "123456", + "work": "7891011", + "mobile": "+45678910", + "primaryEmail": "harry.kane@spurs.co.uk", + "secondaryEmail": "harry.kane@hotmail.com", + "fax": "3425678" + } + }, + "role": "parent" + } + ], + "personDefendant": { + "personDetails": { + "title": "DR", + "firstName": "Harry", + "middleName": "Jack", + "lastName": "Kane Junior", + "dateOfBirth": "2010-01-01", + "nationalityId": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "additionalNationalityId": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "disabilityStatus": "a", + "ethnicityId": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "gender": "MALE", + "interpreterLanguageNeeds": "Welsh", + "documentationLanguageNeeds": "WELSH", + "nationalInsuranceNumber": "NH323232B", + "occupation": "Kid", + "occupationCode": "F", + "specificRequirements": "Screen", + "address": { + "address1": "22", + "address2": "Acacia Avenue", + "address3": "Acacia Town", + "address4": "Acacia City", + "address5": "Acacia Country", + "postcode": "CR7 0AA" + }, + "contact": { + "home": "123456", + "work": "7891011", + "mobile": "45678910", + "primaryEmail": "harry.kanejunior@spurs.co.uk", + "secondaryEmail": "harry.kanejunior@hotmail.com", + "fax": "3425678" + } + }, + "bailStatus": { + "id": "2593cf09-ace0-4b7d-a746-0703a29f33b5", + "code": "C", + "description": "Remanded into Custody" + }, + "custodyTimeLimit": "2018-01-01", + "perceivedBirthYear": 2015, + "driverNumber": "AACC12345", + "arrestSummonsNumber": "arrest123", + "employerOrganisation": { + "name": "Disneyland Paris", + "incorporationNumber": "Mickeymouse1", + "address": { + "address1": "Disney Road", + "address2": "Disney Town", + "address3": "Disney District", + "address4": "Paris", + "address5": "France", + "postcode": "CR7 0AA" + }, + "contact": { + "work": "0207 654 3246 extn 1234", + "primaryEmail": "person@hotmail.com", + "secondaryEmail": "associate@hotmail.com", + "fax": "a" + } + }, + "employerPayrollReference": "payyou1234", + "observedEthnicityId": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "selfDefinedEthnicityId": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "pncId": "1234567" + } + } + ] + } + ], + "courtDocuments": [ + { + "courtDocumentId": "RANDOM_DOC_ID", + "documentCategory": { + "defendantDocument": { + "prosecutionCaseId": "RANDOM_CASE_ID", + "defendants": [ + "e1d32d9d-29ec-4934-a932-22a50f223966" + ] + } + }, + "name": "Bank Statement", + "documentTypeId": "460f7ec0-c002-11e8-a355-529269fb1459", + "mimeType": "pdf", + "materials": [ + { + "id": "RANDOM_MATERIAL_ID_ONE", + "name": "BankStatment.pdf", + "uploadDateTime": "2018-03-20T16:14:29.000Z", + "userGroups": [ + "defence", + "prosecution", + "courtClerk", + "Listing Officers" + ] + }, + { + "id": "RANDOM_MATERIAL_ID_TWO", + "name": "Fine.pdf", + "uploadDateTime": "2018-03-20T16:14:29.000Z", + "userGroups": [ + "defence", + "prosecution", + "Legal Advisers", + "Listing Officers" + ] + } + ], + "containsFinancialMeans": true + } + ], + "listHearingRequests": [ + { + "hearingType": { + "id": "2daefec3-2f76-8109-82d9-2e60544a6c02" + }, + "jurisdictionType": "MAGISTRATES", + "estimateMinutes": 20, + "reportingRestrictionReason": "Automatic anonymity under the Sexual Offences (Amendment) Act 1992", + "courtCentre": { + "id": "88cdf36e-93e4-41b0-8277-17d9dba7f06f" + }, + "prosecutorDatesToAvoid": "wednesdays", + "listingDirections": "tricky defendant", + "listDefendantRequests": [ + { + "prosecutionCaseId": "RANDOM_CASE_ID", + "referralReason": { + "id": "2daefec3-2f76-8109-82d9-2e60544a6c02", + "description": "forTrial", + "defendantId": "RANDOM_DEFENDANT_ID" + }, + "datesToAvoid": "thursdays", + "summonsRequired": "SJP_REFERRAL", + "hearingLanguageNeeds": "WELSH", + "defendantOffences": [ + "3789ab16-0bb7-4ef1-87ef-c936bf0364f1" + ] + } + ] + } + ] + } +}