From 40c3ef9b6affeb84f49470d62e3561767d3d3f90 Mon Sep 17 00:00:00 2001 From: KS Date: Fri, 10 Jul 2026 11:27:22 +0100 Subject: [PATCH 1/3] CIMD-3540 Case level validation Civil / Enfo case --- .../aggregate/ProsecutionCaseFile.java | 2 +- .../CcProsecutionValidationRuleProvider.java | 7 ++++ ...ProsecutionValidationRuleProviderTest.java | 23 +++++++++++ .../ProsecutionCaseFileTest.java | 41 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java index edc4f898..fc50864e 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java @@ -508,7 +508,7 @@ private Stream receiveCCCase(final ProsecutionWithReferenceData received final Boolean isCivil = Optional.ofNullable(receivedProsecutionWithReferenceData.getProsecution().getIsCivil()).orElse(false); - final List caseProblems = validate(prosecutionWithReferenceData, referenceDataQueryService, getCaseValidationRules(receivedInitiationCode)); + final List caseProblems = validate(prosecutionWithReferenceData, referenceDataQueryService, getCaseValidationRules(receivedInitiationCode, isCivil)); boolean isMCCWithListNewHearing = MCC.equals(prosecutionChannel) && Objects.nonNull(prosecutionWithReferenceData.getProsecution().getListNewHearing()); //ACTIVE // INACTIVE diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java index e0c508c8..4f4a3f6a 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java @@ -334,6 +334,13 @@ public static List> getCaseValidationRules(final String caseInitiationCode, final Boolean isCivil) { + if (nonNull(isCivil) && isCivil) { + return getCaseValidationRulesForCivil(caseInitiationCode); + } + return getCaseValidationRules(caseInitiationCode); + } + private static List> getValidationRules( final String defendantInitiationCode, final List> commonDefendantRules, diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java index 4e61f47d..0577d0ab 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java @@ -10,6 +10,7 @@ import uk.gov.moj.cpp.prosecution.casefile.service.ReferenceDataQueryService; import uk.gov.moj.cpp.prosecution.casefile.validation.CaseType; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.CaseInitiationValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.CaseMarkersValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.ProsecutorReferenceDataValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.SummonsCodeValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationRule; @@ -174,5 +175,27 @@ public void verifyGroupCasesValidationRulesWithSummonsCode() { assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s-> s.equals(SummonsCodeValidationRule.class))); } + @Test + public void shouldReturnCivilCaseValidationRulesWhenIsCivilTrue() { + + final List> validationRules = CcProsecutionValidationRuleProvider + .getCaseValidationRules(INITIATION_CODE_CHARGE_CASE, Boolean.TRUE); + + assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(CaseInitiationValidationRule.class))); + assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(ProsecutorReferenceDataValidationRule.class))); + assertFalse(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(CaseMarkersValidationAndEnricherRule.class))); + } + + @Test + public void shouldReturnStandardCaseValidationRulesWhenIsCivilFalseOrNull() { + + final List> validationRulesForFalse = CcProsecutionValidationRuleProvider + .getCaseValidationRules(INITIATION_CODE_CHARGE_CASE, Boolean.FALSE); + final List> validationRulesForNull = CcProsecutionValidationRuleProvider + .getCaseValidationRules(INITIATION_CODE_CHARGE_CASE, null); + + assertTrue(validationRulesForFalse.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(CaseMarkersValidationAndEnricherRule.class))); + assertTrue(validationRulesForNull.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(CaseMarkersValidationAndEnricherRule.class))); + } } diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java index 3f769af7..c7dd3d4d 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java @@ -420,6 +420,42 @@ private static Stream provideParametersForCCCaseTest() { ); } + @Test + public void shouldUseCivilCaseValidationRulesAndIgnoreInvalidCaseMarkerWhenIsCivilTrue() { + final LocalDate offenceCommittedDate = of(2018, 3, 2); + final LocalDate offenceChargeDate = of(2018, 11, 2); + + final ProsecutionWithReferenceData prosecutionWithReferenceData = getProsecutionWithReferenceDataAndCivilFees( + of(buildDefendantWithOffence(offenceCommittedDate, offenceChargeDate, PROSECUTOR_DEFENDANT_REFERENCE_ONE)), + CIVIL, true, Collections.emptyList(), singletonList(caseMarker().withMarkerTypeCode(INVALID_CASE_MARKER_CODE).build())); + + final Stream objectStream = prosecutionCaseFile.receiveCCCase(prosecutionWithReferenceData, new ArrayList<>(), new ArrayList<>(), + referenceDataQueryService); + + final List eventList = objectStream.collect(toList()); + + assertThat(getFirstMatching(eventList, CcProsecutionRejected.class).isPresent(), is(false)); + } + + @Test + public void shouldUseStandardCaseValidationRulesAndRejectInvalidCaseMarkerWhenIsCivilFalse() { + final LocalDate offenceCommittedDate = of(2018, 3, 2); + final LocalDate offenceChargeDate = of(2018, 11, 2); + + final ProsecutionWithReferenceData prosecutionWithReferenceData = getProsecutionWithReferenceDataAndCivilFees( + of(buildDefendantWithOffence(offenceCommittedDate, offenceChargeDate, PROSECUTOR_DEFENDANT_REFERENCE_ONE)), + CPPI, false, Collections.emptyList(), singletonList(caseMarker().withMarkerTypeCode(INVALID_CASE_MARKER_CODE).build())); + + final Stream objectStream = prosecutionCaseFile.receiveCCCase(prosecutionWithReferenceData, new ArrayList<>(), new ArrayList<>(), + referenceDataQueryService); + + final List eventList = objectStream.collect(toList()); + + final Optional ccProsecutionRejected = getFirstMatching(eventList, CcProsecutionRejected.class); + assertThat(ccProsecutionRejected.isPresent(), is(true)); + assertThat(ccProsecutionRejected.get().getCaseErrors().get(0).getCode(), is(ProblemCode.CASE_MARKER_IS_INVALID.name())); + } + @Test public void shouldCreateCCCaseWithWarningsForCPPIWithMultipleDefendants() { final LocalDate offenceCommittedDate = of(2018, 3, 2); @@ -1933,6 +1969,10 @@ private ProsecutionWithReferenceData getProsecutionWithReferenceData(final List< } private ProsecutionWithReferenceData getProsecutionWithReferenceDataAndCivilFees(final List defendantList, final Channel channel, boolean isCivil, List civilFees) { + return getProsecutionWithReferenceDataAndCivilFees(defendantList, channel, isCivil, civilFees, null); + } + + private ProsecutionWithReferenceData getProsecutionWithReferenceDataAndCivilFees(final List defendantList, final Channel channel, boolean isCivil, List civilFees, List caseMarkers) { final ReferenceDataVO referenceDataVO = new ReferenceDataVO(); referenceDataVO.setOffenceReferenceData(singletonList(offenceReferenceData().withCjsOffenceCode(OFFENCE_CODE).withProsecutionTimeLimit("6").withOffenceStartDate(OFFENCE_START_DATE).build())); referenceDataVO.addCountryNationalityReferenceData(referenceDataCountryNationality().build()); @@ -1950,6 +1990,7 @@ private ProsecutionWithReferenceData getProsecutionWithReferenceDataAndCivilFees .withCpsOrganisation(CPS_ORGANISATION) .withFeeStatus(CollectionUtils.isNotEmpty(civilFees) ? civilFees.get(0).getFeeStatus(): null) .withPaymentReference(CollectionUtils.isNotEmpty(civilFees) ? civilFees.get(0).getPaymentReference(): null) + .withCaseMarkers(caseMarkers) .build()) .withDefendants(defendantList) .withChannel(channel) From 0426889eb9968c544e0bf80b871c135ba40dc1af Mon Sep 17 00:00:00 2001 From: KS Date: Fri, 10 Jul 2026 12:08:26 +0100 Subject: [PATCH 2/3] =?UTF-8?q?CIMD-3540=20Implemented=20=E2=80=94=20The?= =?UTF-8?q?=2012=20additional=20rules=20are=20also=20applied=20to=20single?= =?UTF-8?q?,=20non-manual=20CIVIL-channel=20civil=20cases,=20without=20aff?= =?UTF-8?q?ecting=20group=20civil=20cases=20or=20the=20MCC-channel=20route?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../casefile/ProsecutionCaseFileHelper.java | 5 +- .../aggregate/GroupProsecutionCaseFile.java | 2 +- .../aggregate/ProsecutionCaseFile.java | 6 +- .../CcProsecutionValidationRuleProvider.java | 11 +++- .../GroupProsecutionCaseFileTest.java | 31 +++++++++- ...ProsecutionValidationRuleProviderTest.java | 40 ++++++++++--- .../ProsecutionCaseFileTest.java | 60 +++++++++++++++++++ 7 files changed, 139 insertions(+), 16 deletions(-) diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java index 0b70b64a..9af1cb67 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java @@ -219,7 +219,8 @@ public static List validateDefendantErrors(final CaseDetails c final DefendantsWithReferenceData defendantsWithReferenceData, final ReferenceDataQueryService referenceDataQueryService, final Stream.Builder builder, - final Boolean isGroupCase, final boolean isMCCWithListNewHearing, final boolean isInactiveMigratedCase,final Boolean isCivil) { + final boolean isMCCWithListNewHearing, final boolean isInactiveMigratedCase,final Boolean isCivil, + final Boolean isGroupCase) { final List defendantErrors = new ArrayList<>(); defendantsWithReferenceData.getDefendants().forEach(defendant -> { @@ -228,7 +229,7 @@ public static List validateDefendantErrors(final CaseDetails c final String initiationCode = defendantInitiationCode != null && isValidInitiationCode(defendantInitiationCode) ? defendant.getInitiationCode() : caseDetails.getInitiationCode(); final List defendantProblemList = - validate(defendantWithReferenceData, referenceDataQueryService, getDefendantValidationRules(initiationCode, channel,isCivil)); + validate(defendantWithReferenceData, referenceDataQueryService, getDefendantValidationRules(initiationCode, channel, isCivil, isGroupCase)); if (!defendantProblemList.isEmpty()) { defendantErrors.add(defendantProblem() diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFile.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFile.java index 3fb2c192..0f7c7d52 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFile.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFile.java @@ -195,7 +195,7 @@ private List validateDefendants(final GroupProsecutionList gro return groupProsecutionList.getGroupProsecutionWithReferenceDataList().stream() .flatMap(groupProsecutionWithReferenceData -> { final DefendantsWithReferenceData defendantsWithReferenceData = defendantsWithReferenceDataMap.get(groupProsecutionWithReferenceData.getGroupProsecution().getCaseDetails().getCaseId()); - final List errors = validateDefendantErrors(groupProsecutionWithReferenceData.getGroupProsecution().getCaseDetails(), groupProsecutionList.getChannel(), defendantsWithReferenceData, referenceDataQueryService, builder, Boolean.TRUE, false, false,isCivil); + final List errors = validateDefendantErrors(groupProsecutionWithReferenceData.getGroupProsecution().getCaseDetails(), groupProsecutionList.getChannel(), defendantsWithReferenceData, referenceDataQueryService, builder, false, false,isCivil, Boolean.TRUE); return errors.stream(); }).toList(); } diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java index fc50864e..6d732a8a 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java @@ -276,7 +276,7 @@ public Stream receiveSjpProsecution(ProsecutionWithReferenceData prosecu caseProblems.add(newProblem(DUPLICATED_PROSECUTION, "urn", prosecution.getCaseDetails().getProsecutorCaseReference())); } final Boolean isCivil = prosecution.getIsCivil(); - final List defendantProblems = validate(defendantWithReferenceData, referenceDataQueryService, getDefendantValidationRules(caseInitiationCode, prosecutionChannel,isCivil)); + final List defendantProblems = validate(defendantWithReferenceData, referenceDataQueryService, getDefendantValidationRules(caseInitiationCode, prosecutionChannel,isCivil, Boolean.FALSE)); final List rejections = newArrayList(concat(caseProblems, defendantProblems)); if (!rejections.isEmpty()) { builder.accept(new SjpProsecutionRejected(rejections, prosecutionWithReferenceData.getExternalId(), prosecution)); @@ -519,7 +519,7 @@ private Stream receiveCCCase(final ProsecutionWithReferenceData received .filter(status -> MigrationCaseStatus.INACTIVE == status) .isPresent(); - final List defendantErrors = validateDefendantErrors(prosecution.getCaseDetails(), prosecutionChannel, defendantsWithReferenceData, referenceDataQueryService, builder, Boolean.FALSE, isMCCWithListNewHearing,isStandaloneCaseWithoutHearing, isCivil); + final List defendantErrors = validateDefendantErrors(prosecution.getCaseDetails(), prosecutionChannel, defendantsWithReferenceData, referenceDataQueryService, builder, isMCCWithListNewHearing,isStandaloneCaseWithoutHearing, isCivil, Boolean.FALSE); if ((messageFromCppiOrMccOrCivil && prosecutionReceived) || !noDefendantsParkedForSummonsApplicationApproval) { caseProblems.add(newProblem(DUPLICATED_PROSECUTION, "urn", prosecution.getCaseDetails().getProsecutorCaseReference())); @@ -839,7 +839,7 @@ private List validDefendants(final DefendantsWithReferenceData defend public Stream addErrorCorrectedDefendantsForSPI(final UUID caseId, final UUID externalId, final DefendantsWithReferenceData defendantsWithReferenceData, final ReferenceDataQueryService referenceDataQueryService,final Boolean isCivil) { final Builder builder = builder(); - final List defendantErrors = validateDefendantErrors(this.caseDetails, SPI, defendantsWithReferenceData, referenceDataQueryService, builder, Boolean.FALSE, false, false,isCivil); + final List defendantErrors = validateDefendantErrors(this.caseDetails, SPI, defendantsWithReferenceData, referenceDataQueryService, builder, false, false,isCivil, Boolean.FALSE); return addDefendants(caseId, externalId, defendantsWithReferenceData, defendantErrors, builder); } diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java index 4f4a3f6a..dc60a4a5 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java @@ -276,6 +276,10 @@ public class CcProsecutionValidationRuleProvider { SUMMONS.getCode(), GROUP_CIVIL_DEFENDANT_RULE_SET, OTHER.getCode(), GROUP_CIVIL_DEFENDANT_RULE_SET); + private static final Map>> defendantValidationMapForSingleCivilCases = of( + SUMMONS.getCode(), Stream.of(GROUP_CIVIL_DEFENDANT_RULE_SET, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET).flatMap(Collection::stream).toList(), + OTHER.getCode(), Stream.of(GROUP_CIVIL_DEFENDANT_RULE_SET, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET).flatMap(Collection::stream).toList()); + private static final Map>> defendantValidationMapMCCCivil = of( SUMMONS.getCode(), Stream.of(GROUP_CIVIL_DEFENDANT_RULE_SET,COMMON_DEFENDANT_RULE_SET, NON_POLICE_DEFENDANT_RULE_SET, SUMMONS_DEFENDANT_RULE_MCC_SET).flatMap(Collection::stream).toList(), OTHER.getCode(), Stream.of(GROUP_CIVIL_DEFENDANT_RULE_SET,COMMON_DEFENDANT_RULE_SET, NON_POLICE_DEFENDANT_RULE_SET, CHARGE_DEFENDANT_RULE_SET_CIVIL).flatMap(Collection::stream).toList()); @@ -296,9 +300,12 @@ public static List> getDefendantValidationRules(final String defendantInitiationCode, final Channel channel, - final Boolean isCivil) { + final Boolean isCivil, + final Boolean isGroupCase) { if (nonNull(channel) && CIVIL.equals(channel) && nonNull(isCivil) && (isCivil)) { - return getValidationRules(defendantInitiationCode, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET, defendantValidationMapForGroupCivilCases); + final Map>> civilMap = + (nonNull(isGroupCase) && isGroupCase) ? defendantValidationMapForGroupCivilCases : defendantValidationMapForSingleCivilCases; + return getValidationRules(defendantInitiationCode, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET, civilMap); } else if (nonNull(channel) && MCC.equals(channel) && nonNull(isCivil) && (isCivil)) { return getValidationRules(defendantInitiationCode, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET, defendantValidationMapMCCCivil); } else if (nonNull(channel) && SPI.equals(channel)) { diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFileTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFileTest.java index 82e5219e..87a718e5 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFileTest.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/GroupProsecutionCaseFileTest.java @@ -221,6 +221,10 @@ public void shouldNotThrowRuntimeExceptionForDuplicateProsecutionCaseIds() { } private GroupProsecutionWithReferenceData buildGroupProsecutionWithReferenceData(final String initiationCode, final UUID prosecutionCaseId, final Boolean isGroupMaster, final String prosecutorCaseReference){ + return buildGroupProsecutionWithReferenceData(initiationCode, prosecutionCaseId, isGroupMaster, prosecutorCaseReference, LocalDate.now().minusDays(2)); + } + + private GroupProsecutionWithReferenceData buildGroupProsecutionWithReferenceData(final String initiationCode, final UUID prosecutionCaseId, final Boolean isGroupMaster, final String prosecutorCaseReference, final LocalDate chargeDate){ return new GroupProsecutionWithReferenceData(GroupProsecution.groupProsecution() .withGroupId(groupId) .withIsCivil(true) @@ -245,7 +249,7 @@ private GroupProsecutionWithReferenceData buildGroupProsecutionWithReferenceData .withOffenceId(randomUUID()) .withOffenceCode(OFFENCE_CODE) .withArrestDate(LocalDate.now().minusDays(2)) - .withChargeDate(LocalDate.now().minusDays(2)) + .withChargeDate(chargeDate) .withOffenceLocation("London") .withOffenceCommittedDate(LocalDate.now().minusDays(2)) .withStatementOfFacts("statements") @@ -258,4 +262,29 @@ private GroupProsecutionWithReferenceData buildGroupProsecutionWithReferenceData .build())) .build()); } + + @Test + public void shouldNotRejectGroupCivilCaseForFutureChargeDate() { + + final Optional optionalOrganisationUnitWithCourtroomReferenceData = + Optional.of(OrganisationUnitWithCourtroomReferenceData.organisationUnitWithCourtroomReferenceData().build()); + + when(referenceDataQueryService.retrieveOrganisationUnitWithCourtroom("C55BN00")).thenReturn(optionalOrganisationUnitWithCourtroomReferenceData); + + final List groupProsecutionWithReferenceDataList = new ArrayList<>(); + final ReferenceDataVO referenceDataVO = new ReferenceDataVO(); + referenceDataVO.setInitiationTypes(Arrays.asList("O")); + final GroupProsecutionWithReferenceData groupProsecutionWithReferenceData1 = buildGroupProsecutionWithReferenceData(INITIATION_CODE_CIVIL_CASE, randomUUID(), true, "URN1", LocalDate.now().plusDays(5)); + groupProsecutionWithReferenceData1.setReferenceDataVO(referenceDataVO); + final GroupProsecutionWithReferenceData groupProsecutionWithReferenceData2 = buildGroupProsecutionWithReferenceData(INITIATION_CODE_CIVIL_CASE, randomUUID(), false, "URN2", LocalDate.now().plusDays(5)); + groupProsecutionWithReferenceData2.setReferenceDataVO(referenceDataVO); + groupProsecutionWithReferenceDataList.add(groupProsecutionWithReferenceData1); + groupProsecutionWithReferenceDataList.add(groupProsecutionWithReferenceData2); + final GroupProsecutionList groupProsecutionList = new GroupProsecutionList(groupProsecutionWithReferenceDataList); + groupProsecutionList.setChannel(Channel.CIVIL); + + final Stream eventStream = groupProsecutionCaseFile.receiveGroupProsecution(groupProsecutionList, new ArrayList<>(), new ArrayList<>(), referenceDataQueryService); + final Object object = eventStream.findFirst().get(); + assertThat(object, is(instanceOf(GroupCasesReceived.class))); + } } diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java index 0577d0ab..39705863 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java @@ -17,8 +17,12 @@ import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.CroNumberSpiValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DateOfHearingPastDateValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.CroNumberValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DefendantInitiationCodeValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.ObservedEthnicityValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.PncIdSpiValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.PncIdValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.PostCodeValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.offence.ChargeDateValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.offence.OffenceGenericValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.offence.StatementOfFactsValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.offence.StatementOfFactsWelshValidationRule; @@ -49,7 +53,7 @@ public class CcProsecutionValidationRuleProviderTest { public void shouldValidateDefendantValidateSpiRules() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_CHARGE_CASE, Channel.SPI,Boolean.FALSE); + .getDefendantValidationRules(INITIATION_CODE_CHARGE_CASE, Channel.SPI,Boolean.FALSE, Boolean.FALSE); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s-> s.equals(CroNumberSpiValidationRule.class))); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s-> s.equals(PncIdSpiValidationRule.class))); @@ -78,7 +82,7 @@ public void shouldValidateSJPCaseCreationValidationRule() { public void shouldValidateTheDefendantForStatementOfFactsWhenSummonsIsInitiationFromCPPIChannel() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.CPPI,Boolean.FALSE); + .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.CPPI,Boolean.FALSE, Boolean.FALSE); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(StatementOfFactsValidationRule.class))); } @@ -87,7 +91,7 @@ public void shouldValidateTheDefendantForStatementOfFactsWhenSummonsIsInitiation public void shouldValidateTheDefendantForStatementOfFactsWhenSummonsIsInitiationFromSPIChannel() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.SPI,Boolean.FALSE); + .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.SPI,Boolean.FALSE, Boolean.FALSE); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(StatementOfFactsValidationRule.class))); } @@ -96,7 +100,7 @@ public void shouldValidateTheDefendantForStatementOfFactsWhenSummonsIsInitiation public void shouldValidateDefendantValidateCPPIRules() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_CHARGE_CASE, Channel.CPPI,Boolean.FALSE); + .getDefendantValidationRules(INITIATION_CODE_CHARGE_CASE, Channel.CPPI,Boolean.FALSE, Boolean.FALSE); assertFalse(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s-> s.equals(CroNumberSpiValidationRule.class))); assertFalse(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s-> s.equals(PncIdSpiValidationRule.class))); @@ -109,7 +113,7 @@ public void shouldValidateDefendantValidateCPPIRules() { public void shouldValidateDefendantValidateMCCRules() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_CHARGE_CASE, Channel.MCC,Boolean.FALSE); + .getDefendantValidationRules(INITIATION_CODE_CHARGE_CASE, Channel.MCC,Boolean.FALSE, Boolean.FALSE); assertFalse(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s-> s.equals(CroNumberSpiValidationRule.class))); assertFalse(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s-> s.equals(PncIdSpiValidationRule.class))); @@ -141,7 +145,7 @@ public void verifyGroupCasesValidationRules() { public void shouldIncludeDateOfHearingPastDateValidationRuleForOtherInitiationCodeWhenChannelIsCivilAndIsCivilIsTrue() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE); + .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE, Boolean.FALSE); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); } @@ -150,11 +154,33 @@ public void shouldIncludeDateOfHearingPastDateValidationRuleForOtherInitiationCo public void shouldIncludeDateOfHearingPastDateValidationRuleForSummonsInitiationCodeWhenChannelIsCivilAndIsCivilIsTrue() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.CIVIL, Boolean.TRUE); + .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.CIVIL, Boolean.TRUE, Boolean.FALSE); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); } + @Test + public void shouldIncludeExtraDefendantRulesForSingleCivilCaseOnly() { + + final List> singleCaseRules = CcProsecutionValidationRuleProvider + .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE, Boolean.FALSE); + final List> groupCaseRules = CcProsecutionValidationRuleProvider + .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE, Boolean.TRUE); + + assertFalse(singleCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(ChargeDateValidationRule.class))); + assertTrue(singleCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(ObservedEthnicityValidationAndEnricherRule.class))); + assertTrue(singleCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DefendantInitiationCodeValidationRule.class))); + assertTrue(singleCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(PostCodeValidationRule.class))); + + assertFalse(groupCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(ChargeDateValidationRule.class))); + assertFalse(groupCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(ObservedEthnicityValidationAndEnricherRule.class))); + assertFalse(groupCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DefendantInitiationCodeValidationRule.class))); + assertFalse(groupCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(PostCodeValidationRule.class))); + + assertTrue(groupCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); + assertTrue(singleCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); + } + @Test public void verifyCasesValidationRules() { diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java index c7dd3d4d..0e0b86f4 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java @@ -456,6 +456,19 @@ public void shouldUseStandardCaseValidationRulesAndRejectInvalidCaseMarkerWhenIs assertThat(ccProsecutionRejected.get().getCaseErrors().get(0).getCode(), is(ProblemCode.CASE_MARKER_IS_INVALID.name())); } + @Test + public void shouldNotRejectSingleNonManualCivilCaseForFutureChargeDate() { + final ProsecutionWithReferenceData prosecutionWithReferenceData = + getCivilProsecutionWithReferenceDataForSingleCase("O", now().plusDays(5)); + + final Stream objectStream = prosecutionCaseFile.receiveCCCase(prosecutionWithReferenceData, new ArrayList<>(), new ArrayList<>(), + referenceDataQueryService); + + final List eventList = objectStream.collect(toList()); + + assertThat(getFirstMatching(eventList, CcProsecutionRejected.class).isPresent(), is(false)); + } + @Test public void shouldCreateCCCaseWithWarningsForCPPIWithMultipleDefendants() { final LocalDate offenceCommittedDate = of(2018, 3, 2); @@ -2001,6 +2014,53 @@ private ProsecutionWithReferenceData getProsecutionWithReferenceDataAndCivilFees return prosecutionWithReferenceData; } + private ProsecutionWithReferenceData getCivilProsecutionWithReferenceDataForSingleCase(final String initiationCode, final LocalDate chargeDate) { + final ReferenceDataVO referenceDataVO = new ReferenceDataVO(); + referenceDataVO.setOffenceReferenceData(singletonList(offenceReferenceData().withCjsOffenceCode(OFFENCE_CODE).withProsecutionTimeLimit("6").withOffenceStartDate(OFFENCE_START_DATE).build())); + referenceDataVO.addCountryNationalityReferenceData(referenceDataCountryNationality().build()); + referenceDataVO.setInitiationTypes(asList("J", "C", initiationCode)); + referenceDataVO.setProsecutorsReferenceData(prosecutorsReferenceData() + .withId(randomUUID()) + .build()); + + final uk.gov.moj.cpp.prosecution.casefile.json.schemas.Defendant civilDefendant = defendant() + .withId(DEFENDANT_ID) + .withProsecutorDefendantReference(PROSECUTOR_DEFENDANT_REFERENCE_ONE) + .withIndividual(individual() + .withPersonalInformation(personalInformation().withFirstName(FORENAME).withLastName(SURNAME).build()) + .withSelfDefinedInformation(selfDefinedInformation().withDateOfBirth(BIRTH_DATE).build()) + .build()) + .withInitialHearing(initialHearing() + .withDateOfHearing(DATE_OF_HEARING) + .withCourtHearingLocation(COURT_HEARING_LOCATION) + .build()) + .withOffences(singletonList(offence() + .withArrestDate(ARREST_DATE) + .withOffenceCode(OFFENCE_CODE) + .withOffenceSequenceNumber(1) + .withOffenceId(offenceId) + .withOffenceCommittedDate(now().minusDays(30)) + .withChargeDate(chargeDate) + .build())) + .build(); + + final ProsecutionWithReferenceData prosecutionWithReferenceData = new ProsecutionWithReferenceData(prosecution() + .withCaseDetails(caseDetails() + .withCaseId(CASE_ID) + .withInitiationCode(initiationCode) + .withProsecutorCaseReference(PROSECUTOR_CASE_REFERENCE) + .withOriginatingOrganisation(ORIGINATING_ORGANISATION) + .withCpsOrganisation(CPS_ORGANISATION) + .build()) + .withDefendants(singletonList(civilDefendant)) + .withChannel(CIVIL) + .withIsCivil(true) + .build()); + prosecutionWithReferenceData.setReferenceDataVO(referenceDataVO); + prosecutionWithReferenceData.setExternalId(EXTERNAL_ID); + return prosecutionWithReferenceData; + } + private ProsecutionWithReferenceData getProsecutionWithMixedValidAndInvalidCaseMarkerRefData(final List defendantList) { final ReferenceDataVO referenceDataVO = new ReferenceDataVO(); referenceDataVO.setOffenceReferenceData(singletonList(offenceReferenceData().withCjsOffenceCode(OFFENCE_CODE).withProsecutionTimeLimit("6").withOffenceStartDate(OFFENCE_START_DATE).build())); From f308aa7bfbca367d93c98d5508c4e6cc7c698318 Mon Sep 17 00:00:00 2001 From: KS Date: Tue, 14 Jul 2026 07:48:02 +0100 Subject: [PATCH 3/3] CIMD-3540 implements three warning rules into the single, non-manual CIVIL-channel case creation rout --- .../casefile/ProsecutionCaseFileHelper.java | 4 +- .../aggregate/ProsecutionCaseFile.java | 4 +- .../casefile/validation/ProblemCode.java | 1 + .../CcProsecutionValidationRuleProvider.java | 22 ++++- .../CcProsecutionWarningRuleProvider.java | 15 +++- ...31DaysInPastValidationAndEnricherRule.java | 41 +++++++++ ...ProsecutionValidationRuleProviderTest.java | 26 ++++-- .../CcProsecutionWarningRuleProviderTest.java | 85 +++++++++++++++++++ ...ysInPastValidationAndEnricherRuleTest.java | 83 ++++++++++++++++++ .../ProsecutionCaseFileTest.java | 77 ++++++++++++++++- 10 files changed, 342 insertions(+), 16 deletions(-) create mode 100644 prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule.java create mode 100644 prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProviderTest.java create mode 100644 prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRuleTest.java diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java index 9af1cb67..3d5d03d7 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/ProsecutionCaseFileHelper.java @@ -259,7 +259,7 @@ private static boolean isValidInitiationCode(final String initiationCode) { .anyMatch(code -> initiationCode.equalsIgnoreCase(String.valueOf(code))); } - public static List validateDefendantWarnings(final DefendantsWithReferenceData defendantsWithReferenceData, final String initiationCode) { + public static List validateDefendantWarnings(final DefendantsWithReferenceData defendantsWithReferenceData, final String initiationCode, final Channel channel) { final ReferenceDataValidationContext referenceDataValidationContext = ReferenceDataValidationContext.newInstance(defendantsWithReferenceData.getReferenceDataVO().getOffenceReferenceData(), defendantsWithReferenceData.getReferenceDataVO().getCountryNationalityReferenceData()); @@ -270,7 +270,7 @@ public static List validateDefendantWarnings(final DefendantsW final List validationWarnings = validate( defendant, referenceDataValidationContext, - CcProsecutionWarningRuleProvider.getWarningRules(initiationCode)); + CcProsecutionWarningRuleProvider.getWarningRules(initiationCode, channel)); if (!validationWarnings.isEmpty()) { defendantProblems.add(defendantProblem() .withProblems(validationWarnings) diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java index 6d732a8a..3ab797e3 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/aggregate/ProsecutionCaseFile.java @@ -755,7 +755,7 @@ private Stream processWithoutProblems(final ProsecutionWithReferenceData final Prosecution prosecution = prosecutionWithReferenceData.getProsecution(); final String incomingInitiationCode = prosecution.getCaseDetails().getInitiationCode(); final Channel prosecutionChannel = prosecution.getChannel(); - final List defendantWarningsForIncomingMessage = prosecutionChannel == SPI ? List.of() : validateDefendantWarnings(defendantsWithReferenceData, incomingInitiationCode); + final List defendantWarningsForIncomingMessage = prosecutionChannel == SPI ? List.of() : validateDefendantWarnings(defendantsWithReferenceData, incomingInitiationCode, prosecutionChannel); if (incomingInitiationCode.equals(SUMMONS_INITIATION_CODE)) { return apply(builder.add(defendantsParkedForSummonsApplicationApproval() @@ -786,7 +786,7 @@ public Stream associateEnterpriseId(final String enterpriseId) { } private Stream addDefendants(final UUID caseId, final UUID externalId, final DefendantsWithReferenceData defendantsWithReferenceData, List defendantProblemList, final Builder builder) { - final List defendantWarningsList = channel == CPPI ? validateDefendantWarnings(defendantsWithReferenceData, this.caseDetails.getInitiationCode()) : null; + final List defendantWarningsList = channel == CPPI ? validateDefendantWarnings(defendantsWithReferenceData, this.caseDetails.getInitiationCode(), channel) : null; final List validDefendantList = channel == SPI ? validDefendants(defendantsWithReferenceData, defendantProblemList) : defendantsWithReferenceData.getDefendants(); final String initiationCodeForSameCaseWithNewDefendant = defendantsWithReferenceData.getCaseDetails().getInitiationCode(); if (!validDefendantList.isEmpty()) { diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/ProblemCode.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/ProblemCode.java index 946e0bd9..4d64b3ee 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/ProblemCode.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/ProblemCode.java @@ -21,6 +21,7 @@ public enum ProblemCode { DATE_OF_HEARING_IN_THE_PAST, DATE_OF_HEARING_EARLIER_THAN_OFFENCE_COMMITTED_DATE, DATE_OF_HEARING_NOT_AVAILABLE, + DATE_OF_HEARING_MORE_THAN_31DAYS_IN_PAST, COURT_HEARING_LOCATION_OUCODE_INVALID, DEFENDANT_ADDITIONAL_NATIONALITY_INVALID, DEFENDANT_PRIMARY_EMAIL_ADDRESS_INVALID, diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java index dc60a4a5..55e3ab2f 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProvider.java @@ -35,6 +35,7 @@ import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.CroNumberSpiValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.CroNumberValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.CustodyStatusValidationAndEnricherRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DateOfHearingPastDateValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DateOfHearingValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DefendantDateOfBirthValidationRule; @@ -276,9 +277,26 @@ public class CcProsecutionValidationRuleProvider { SUMMONS.getCode(), GROUP_CIVIL_DEFENDANT_RULE_SET, OTHER.getCode(), GROUP_CIVIL_DEFENDANT_RULE_SET); + private static final List> SINGLE_CIVIL_CASE_ONLY_RULE_SET = unmodifiableList(asList( + new ArrestDateValidationRuleForCivil(), + new DefendantDateOfBirthValidationRule(), + new ParentGuardianDateOfBirthValidationRule(), + new CourtHearingLocationValidationRule(), + new OffenderCodeValidationAndEnricherRule(), + new OffenceLocationValidationAndEnricherRule(), + new NationalityValidationAndEnricherRule(), + new VehicleCodeValidationAndEnricherRule(), + new OffenceCodeValidationAndEnricherRule(), + new CourtReceivedFromCodeCourtValidationRules(), + new CourtReceivedToCodeCourtValidationRules(), + new HearingTypeCodeValidationRule(), + new LaidDateValidationRule(), + new DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule() + )); + private static final Map>> defendantValidationMapForSingleCivilCases = of( - SUMMONS.getCode(), Stream.of(GROUP_CIVIL_DEFENDANT_RULE_SET, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET).flatMap(Collection::stream).toList(), - OTHER.getCode(), Stream.of(GROUP_CIVIL_DEFENDANT_RULE_SET, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET).flatMap(Collection::stream).toList()); + SUMMONS.getCode(), Stream.of(SINGLE_CIVIL_CASE_ONLY_RULE_SET, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET).flatMap(Collection::stream).toList(), + OTHER.getCode(), Stream.of(SINGLE_CIVIL_CASE_ONLY_RULE_SET, COMMON_DEFENDANT_RULE_SET, SPI_DEFENDANT_RULE_SET).flatMap(Collection::stream).toList()); private static final Map>> defendantValidationMapMCCCivil = of( SUMMONS.getCode(), Stream.of(GROUP_CIVIL_DEFENDANT_RULE_SET,COMMON_DEFENDANT_RULE_SET, NON_POLICE_DEFENDANT_RULE_SET, SUMMONS_DEFENDANT_RULE_MCC_SET).flatMap(Collection::stream).toList(), diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProvider.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProvider.java index c55288eb..c5cf7068 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProvider.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProvider.java @@ -2,10 +2,13 @@ import static java.util.Collections.emptyList; +import static uk.gov.moj.cpp.prosecution.casefile.json.schemas.Channel.CIVIL; +import uk.gov.moj.cpp.prosecution.casefile.json.schemas.Channel; import uk.gov.moj.cpp.prosecution.casefile.json.schemas.Defendant; import uk.gov.moj.cpp.prosecution.casefile.validation.context.ReferenceDataValidationContext; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.warning.ImprisonableOffenceValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.warning.OffenceInEffectOnOffenceCommittedDateValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.warning.OffenceOutOfTimeValidationRule; @@ -20,11 +23,19 @@ public class CcProsecutionWarningRuleProvider { OffenceOutOfTimeValidationRule.INSTANCE, OffenceInEffectOnOffenceCommittedDateValidationRule.INSTANCE); + private static final List> CIVIL_WARNING_RULES = + ImmutableList.of( + OffenceOutOfTimeValidationRule.INSTANCE, + OffenceInEffectOnOffenceCommittedDateValidationRule.INSTANCE, + ImprisonableOffenceValidationRule.INSTANCE); + private CcProsecutionWarningRuleProvider() { } - public static List> getWarningRules(final String caseInitiationCode) { - if("C".equals(caseInitiationCode) || "Q".equals(caseInitiationCode)) { + public static List> getWarningRules(final String caseInitiationCode, final Channel channel) { + if (CIVIL.equals(channel) && ("O".equals(caseInitiationCode) || "S".equals(caseInitiationCode))) { + return CIVIL_WARNING_RULES; + } else if ("C".equals(caseInitiationCode) || "Q".equals(caseInitiationCode)) { return WARNING_RULES; } else { return emptyList(); diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule.java new file mode 100644 index 00000000..515b173b --- /dev/null +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/main/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule.java @@ -0,0 +1,41 @@ +package uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant; + +import static java.util.Optional.of; +import static uk.gov.moj.cpp.prosecution.casefile.validation.ProblemCode.DATE_OF_HEARING_MORE_THAN_31DAYS_IN_PAST; +import static uk.gov.moj.cpp.prosecution.casefile.validation.Problems.newProblem; +import static uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationResult.VALID; +import static uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationResult.newValidationResult; + +import uk.gov.moj.cpp.prosecution.casefile.domain.DefendantWithReferenceData; +import uk.gov.moj.cpp.prosecution.casefile.json.schemas.ProblemValue; +import uk.gov.moj.cpp.prosecution.casefile.service.ReferenceDataQueryService; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.FieldName; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationResult; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationRule; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule implements ValidationRule { + + private static final int MAX_DAYS_IN_PAST = 31; + + @Override + public ValidationResult validate(final DefendantWithReferenceData defendantWithReferenceData, final ReferenceDataQueryService referenceDataQueryService) { + if (defendantWithReferenceData.isMCCWithListNewHearing() || defendantWithReferenceData.isInactiveMigratedCase()) { + return VALID; + } + final String dateOfHearing = defendantWithReferenceData.getDefendant().getInitialHearing().getDateOfHearing(); + final LocalDate hearingDate = convertToLocalDate(dateOfHearing); + + if (hearingDate.isBefore(LocalDate.now().minusDays(MAX_DAYS_IN_PAST))) { + return newValidationResult(of(newProblem(DATE_OF_HEARING_MORE_THAN_31DAYS_IN_PAST, new ProblemValue(null, FieldName.DEFENDANT_DATE_OF_HEARING.getValue(), dateOfHearing)))); + } + return VALID; + } + + private LocalDate convertToLocalDate(final String date) { + return LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + +} diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java index 39705863..b3bc2011 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionValidationRuleProviderTest.java @@ -15,6 +15,7 @@ import uk.gov.moj.cpp.prosecution.casefile.validation.rules.SummonsCodeValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.CroNumberSpiValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DateOfHearingPastDateValidationAndEnricherRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.CroNumberValidationRule; import uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant.DefendantInitiationCodeValidationRule; @@ -142,19 +143,19 @@ public void verifyGroupCasesValidationRules() { } @Test - public void shouldIncludeDateOfHearingPastDateValidationRuleForOtherInitiationCodeWhenChannelIsCivilAndIsCivilIsTrue() { + public void shouldIncludeDateOfHearingPastDateValidationRuleForOtherInitiationCodeWhenChannelIsCivilAndIsCivilIsTrueForGroupCase() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE, Boolean.FALSE); + .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE, Boolean.TRUE); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); } @Test - public void shouldIncludeDateOfHearingPastDateValidationRuleForSummonsInitiationCodeWhenChannelIsCivilAndIsCivilIsTrue() { + public void shouldIncludeDateOfHearingPastDateValidationRuleForSummonsInitiationCodeWhenChannelIsCivilAndIsCivilIsTrueForGroupCase() { final List> validationRules = CcProsecutionValidationRuleProvider - .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.CIVIL, Boolean.TRUE, Boolean.FALSE); + .getDefendantValidationRules(INITIATION_CODE_FOR_SUMMONS, Channel.CIVIL, Boolean.TRUE, Boolean.TRUE); assertTrue(validationRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); } @@ -178,7 +179,22 @@ public void shouldIncludeExtraDefendantRulesForSingleCivilCaseOnly() { assertFalse(groupCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(PostCodeValidationRule.class))); assertTrue(groupCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); - assertTrue(singleCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); + assertFalse(singleCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingPastDateValidationAndEnricherRule.class))); + } + + @Test + public void shouldIncludeDateOfHearingMoreThan31DaysInPastRuleOnlyForSingleCivilCase() { + + final List> singleCivilCaseRules = CcProsecutionValidationRuleProvider + .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE, Boolean.FALSE); + final List> groupCivilCaseRules = CcProsecutionValidationRuleProvider + .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL, Boolean.TRUE, Boolean.TRUE); + final List> mccCivilCaseRules = CcProsecutionValidationRuleProvider + .getDefendantValidationRules(INITIATION_CODE_FOR_OTHER, Channel.MCC, Boolean.TRUE, Boolean.FALSE); + + assertTrue(singleCivilCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule.class))); + assertFalse(groupCivilCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule.class))); + assertFalse(mccCivilCaseRules.stream().map((Function, ? extends Class>) ValidationRule::getClass).anyMatch(s -> s.equals(DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule.class))); } @Test diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProviderTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProviderTest.java new file mode 100644 index 00000000..bf38d31c --- /dev/null +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/provider/CcProsecutionWarningRuleProviderTest.java @@ -0,0 +1,85 @@ +package uk.gov.moj.cpp.prosecution.casefile.validation.provider; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import uk.gov.moj.cpp.prosecution.casefile.json.schemas.Channel; +import uk.gov.moj.cpp.prosecution.casefile.json.schemas.Defendant; +import uk.gov.moj.cpp.prosecution.casefile.validation.context.ReferenceDataValidationContext; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.ValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.warning.ImprisonableOffenceValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.warning.OffenceInEffectOnOffenceCommittedDateValidationRule; +import uk.gov.moj.cpp.prosecution.casefile.validation.rules.warning.OffenceOutOfTimeValidationRule; + +import java.util.List; +import java.util.function.Function; + +import org.junit.jupiter.api.Test; + +public class CcProsecutionWarningRuleProviderTest { + + private static final String INITIATION_CODE_FOR_OTHER = "O"; + private static final String INITIATION_CODE_FOR_SUMMONS = "S"; + private static final String INITIATION_CODE_CHARGE = "C"; + private static final String INITIATION_CODE_REQUISITION = "Q"; + + @Test + public void shouldIncludeAllThreeWarningRulesForCivilChannelOtherInitiationCode() { + final List> rules = CcProsecutionWarningRuleProvider + .getWarningRules(INITIATION_CODE_FOR_OTHER, Channel.CIVIL); + + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceOutOfTimeValidationRule.class))); + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceInEffectOnOffenceCommittedDateValidationRule.class))); + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(ImprisonableOffenceValidationRule.class))); + } + + @Test + public void shouldIncludeAllThreeWarningRulesForCivilChannelSummonsInitiationCode() { + final List> rules = CcProsecutionWarningRuleProvider + .getWarningRules(INITIATION_CODE_FOR_SUMMONS, Channel.CIVIL); + + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceOutOfTimeValidationRule.class))); + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceInEffectOnOffenceCommittedDateValidationRule.class))); + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(ImprisonableOffenceValidationRule.class))); + } + + @Test + public void shouldNotIncludeImprisonableOffenceRuleForMccChannelOtherInitiationCode() { + final List> rules = CcProsecutionWarningRuleProvider + .getWarningRules(INITIATION_CODE_FOR_OTHER, Channel.MCC); + + assertTrue(rules.isEmpty()); + } + + @Test + public void shouldNotIncludeImprisonableOffenceRuleForCppiChannelChargeInitiationCode() { + final List> rules = CcProsecutionWarningRuleProvider + .getWarningRules(INITIATION_CODE_CHARGE, Channel.CPPI); + + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceOutOfTimeValidationRule.class))); + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceInEffectOnOffenceCommittedDateValidationRule.class))); + assertFalse(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(ImprisonableOffenceValidationRule.class))); + } + + @Test + public void shouldNotIncludeImprisonableOffenceRuleForCivilChannelRequisitionInitiationCode() { + final List> rules = CcProsecutionWarningRuleProvider + .getWarningRules(INITIATION_CODE_REQUISITION, Channel.CIVIL); + + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceOutOfTimeValidationRule.class))); + assertTrue(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(OffenceInEffectOnOffenceCommittedDateValidationRule.class))); + assertFalse(rules.stream().map(warningRuleClass()).anyMatch(s -> s.equals(ImprisonableOffenceValidationRule.class))); + } + + @Test + public void shouldReturnEmptyListForUnmappedInitiationCodeAndChannel() { + final List> rules = CcProsecutionWarningRuleProvider + .getWarningRules("J", Channel.SPI); + + assertTrue(rules.isEmpty()); + } + + private Function, ? extends Class> warningRuleClass() { + return ValidationRule::getClass; + } +} diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRuleTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRuleTest.java new file mode 100644 index 00000000..44994793 --- /dev/null +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cpp/prosecution/casefile/validation/rules/defendant/DateOfHearingMoreThan31DaysInPastValidationAndEnricherRuleTest.java @@ -0,0 +1,83 @@ +package uk.gov.moj.cpp.prosecution.casefile.validation.rules.defendant; + +import static java.time.LocalDate.now; +import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; +import static uk.gov.moj.cpp.prosecution.casefile.validation.ProblemCode.DATE_OF_HEARING_MORE_THAN_31DAYS_IN_PAST; +import static uk.gov.moj.cpp.prosecution.casefile.validation.rules.FieldName.DEFENDANT_DATE_OF_HEARING; + +import uk.gov.moj.cpp.prosecution.casefile.domain.DefendantWithReferenceData; +import uk.gov.moj.cpp.prosecution.casefile.json.schemas.Problem; +import uk.gov.moj.cpp.prosecution.casefile.service.ReferenceDataQueryService; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class DateOfHearingMoreThan31DaysInPastValidationAndEnricherRuleTest { + + @Mock + ReferenceDataQueryService referenceDataQueryService; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + DefendantWithReferenceData defendantWithReferenceData; + + @Test + public void shouldReturnEmptyListWhenDateOfHearingIsInFuture() { + when(defendantWithReferenceData.getDefendant().getInitialHearing().getDateOfHearing()).thenReturn(now().plusDays(5).format(ISO_LOCAL_DATE)); + + final Optional optionalProblem = new DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule().validate(defendantWithReferenceData, referenceDataQueryService) + .problems().stream().findFirst(); + assertThat(optionalProblem.isPresent(), is(false)); + } + + @Test + public void shouldReturnEmptyListWhenDateOfHearingIsExactly31DaysInPast() { + when(defendantWithReferenceData.getDefendant().getInitialHearing().getDateOfHearing()).thenReturn(now().minusDays(31).format(ISO_LOCAL_DATE)); + + final Optional optionalProblem = new DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule().validate(defendantWithReferenceData, referenceDataQueryService) + .problems().stream().findFirst(); + assertThat(optionalProblem.isPresent(), is(false)); + } + + @Test + public void shouldReturnEmptyListWhenMigratedCaseIsInactive() { + when(defendantWithReferenceData.isInactiveMigratedCase()).thenReturn(true); + + final Optional optionalProblem = new DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule().validate(defendantWithReferenceData, referenceDataQueryService) + .problems().stream().findFirst(); + assertThat(optionalProblem.isPresent(), is(false)); + } + + @Test + public void shouldReturnValidWhenMCCWithListNewHearing() { + when(defendantWithReferenceData.isMCCWithListNewHearing()).thenReturn(true); + + final Optional optionalProblem = new DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule().validate(defendantWithReferenceData, referenceDataQueryService) + .problems().stream().findFirst(); + assertTrue(optionalProblem.isEmpty()); + } + + @Test + public void shouldReturnProblemWhenDateOfHearingIsMoreThan31DaysInPast() { + final String hearingDate = now().minusDays(32).format(ISO_LOCAL_DATE); + when(defendantWithReferenceData.getDefendant().getInitialHearing().getDateOfHearing()).thenReturn(hearingDate); + + final Optional optionalProblem = new DateOfHearingMoreThan31DaysInPastValidationAndEnricherRule().validate(defendantWithReferenceData, referenceDataQueryService) + .problems().stream().findFirst(); + + assertThat(optionalProblem.isPresent(), is(true)); + assertThat(optionalProblem.get().getCode(), is(DATE_OF_HEARING_MORE_THAN_31DAYS_IN_PAST.name())); + assertThat(optionalProblem.get().getValues().get(0).getKey(), is(DEFENDANT_DATE_OF_HEARING.getValue())); + assertThat(optionalProblem.get().getValues().get(0).getValue(), is(hearingDate)); + } + +} diff --git a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java index 0e0b86f4..f1edfb8b 100644 --- a/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java +++ b/prosecutioncasefile-domain/prosecutioncasefile-domain-aggregate/src/test/java/uk/gov/moj/cps/prosecutioncasefile/ProsecutionCaseFileTest.java @@ -469,6 +469,69 @@ public void shouldNotRejectSingleNonManualCivilCaseForFutureChargeDate() { assertThat(getFirstMatching(eventList, CcProsecutionRejected.class).isPresent(), is(false)); } + @Test + public void shouldRejectSingleNonManualCivilCaseForHearingDateMoreThan31DaysInPast() { + final ProsecutionWithReferenceData prosecutionWithReferenceData = + getCivilProsecutionWithReferenceDataForSingleCase("O", now().minusDays(2), now().minusDays(40).toString()); + + final Stream objectStream = prosecutionCaseFile.receiveCCCase(prosecutionWithReferenceData, new ArrayList<>(), new ArrayList<>(), + referenceDataQueryService); + + final List eventList = objectStream.collect(toList()); + + final Optional ccProsecutionRejected = getFirstMatching(eventList, CcProsecutionRejected.class); + assertThat(ccProsecutionRejected.isPresent(), is(true)); + assertThat(ccProsecutionRejected.get().getDefendantErrors().get(0).getProblems().stream() + .anyMatch(problem -> problem.getCode().equals(ProblemCode.DATE_OF_HEARING_MORE_THAN_31DAYS_IN_PAST.name())), is(true)); + assertThat(ccProsecutionRejected.get().getDefendantErrors().get(0).getProblems().stream() + .anyMatch(problem -> problem.getCode().equals(ProblemCode.DATE_OF_HEARING_IN_THE_PAST.name())), is(false)); + } + + @Test + public void shouldNotRejectSingleNonManualCivilCaseForHearingDateWithin31DaysInPast() { + final ProsecutionWithReferenceData prosecutionWithReferenceData = + getCivilProsecutionWithReferenceDataForSingleCase("O", now().minusDays(2), now().minusDays(10).toString()); + + final Stream objectStream = prosecutionCaseFile.receiveCCCase(prosecutionWithReferenceData, new ArrayList<>(), new ArrayList<>(), + referenceDataQueryService); + + final List eventList = objectStream.collect(toList()); + + assertThat(getFirstMatching(eventList, CcProsecutionRejected.class).isPresent(), is(false)); + } + + @Test + public void shouldRaiseOffenceOutOfTimeWarningForSingleNonManualCivilCase() { + final ProsecutionWithReferenceData prosecutionWithReferenceData = + getCivilProsecutionWithReferenceDataForSingleCase("O", now(), now().plusDays(5).toString(), now().minusMonths(10), CIVIL); + + final Stream objectStream = prosecutionCaseFile.receiveCCCase(prosecutionWithReferenceData, new ArrayList<>(), new ArrayList<>(), + referenceDataQueryService); + + final List eventList = objectStream.collect(toList()); + + assertThat(getFirstMatching(eventList, CcProsecutionRejected.class).isPresent(), is(false)); + final Optional ccCaseReceivedWithWarnings = getFirstMatching(eventList, CcCaseReceivedWithWarnings.class); + assertThat(ccCaseReceivedWithWarnings.isPresent(), is(true)); + assertThat(ccCaseReceivedWithWarnings.get().getDefendantWarnings().get(0).getProblems().stream() + .anyMatch(problem -> problem.getCode().equals(ProblemCode.OFFENCE_OUT_OF_TIME.name())), is(true)); + } + + @Test + public void shouldNotRaiseOffenceOutOfTimeWarningForMccChannelCase() { + final ProsecutionWithReferenceData prosecutionWithReferenceData = + getCivilProsecutionWithReferenceDataForSingleCase("O", now(), now().plusDays(5).toString(), now().minusMonths(10), MCC); + + final Stream objectStream = prosecutionCaseFile.receiveCCCase(prosecutionWithReferenceData, new ArrayList<>(), new ArrayList<>(), + referenceDataQueryService); + + final List eventList = objectStream.collect(toList()); + + assertThat(getFirstMatching(eventList, CcProsecutionRejected.class).isPresent(), is(false)); + final Optional ccCaseReceivedWithWarnings = getFirstMatching(eventList, CcCaseReceivedWithWarnings.class); + assertThat(ccCaseReceivedWithWarnings.isPresent(), is(false)); + } + @Test public void shouldCreateCCCaseWithWarningsForCPPIWithMultipleDefendants() { final LocalDate offenceCommittedDate = of(2018, 3, 2); @@ -2015,6 +2078,14 @@ private ProsecutionWithReferenceData getProsecutionWithReferenceDataAndCivilFees } private ProsecutionWithReferenceData getCivilProsecutionWithReferenceDataForSingleCase(final String initiationCode, final LocalDate chargeDate) { + return getCivilProsecutionWithReferenceDataForSingleCase(initiationCode, chargeDate, DATE_OF_HEARING); + } + + private ProsecutionWithReferenceData getCivilProsecutionWithReferenceDataForSingleCase(final String initiationCode, final LocalDate chargeDate, final String dateOfHearing) { + return getCivilProsecutionWithReferenceDataForSingleCase(initiationCode, chargeDate, dateOfHearing, now().minusDays(30), CIVIL); + } + + private ProsecutionWithReferenceData getCivilProsecutionWithReferenceDataForSingleCase(final String initiationCode, final LocalDate chargeDate, final String dateOfHearing, final LocalDate offenceCommittedDate, final Channel channel) { final ReferenceDataVO referenceDataVO = new ReferenceDataVO(); referenceDataVO.setOffenceReferenceData(singletonList(offenceReferenceData().withCjsOffenceCode(OFFENCE_CODE).withProsecutionTimeLimit("6").withOffenceStartDate(OFFENCE_START_DATE).build())); referenceDataVO.addCountryNationalityReferenceData(referenceDataCountryNationality().build()); @@ -2031,7 +2102,7 @@ private ProsecutionWithReferenceData getCivilProsecutionWithReferenceDataForSing .withSelfDefinedInformation(selfDefinedInformation().withDateOfBirth(BIRTH_DATE).build()) .build()) .withInitialHearing(initialHearing() - .withDateOfHearing(DATE_OF_HEARING) + .withDateOfHearing(dateOfHearing) .withCourtHearingLocation(COURT_HEARING_LOCATION) .build()) .withOffences(singletonList(offence() @@ -2039,7 +2110,7 @@ private ProsecutionWithReferenceData getCivilProsecutionWithReferenceDataForSing .withOffenceCode(OFFENCE_CODE) .withOffenceSequenceNumber(1) .withOffenceId(offenceId) - .withOffenceCommittedDate(now().minusDays(30)) + .withOffenceCommittedDate(offenceCommittedDate) .withChargeDate(chargeDate) .build())) .build(); @@ -2053,7 +2124,7 @@ private ProsecutionWithReferenceData getCivilProsecutionWithReferenceDataForSing .withCpsOrganisation(CPS_ORGANISATION) .build()) .withDefendants(singletonList(civilDefendant)) - .withChannel(CIVIL) + .withChannel(channel) .withIsCivil(true) .build()); prosecutionWithReferenceData.setReferenceDataVO(referenceDataVO);