diff --git a/src/main/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandler.java b/src/main/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandler.java index f4f62d6d671..752eabdfa28 100644 --- a/src/main/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandler.java +++ b/src/main/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandler.java @@ -2,17 +2,18 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import uk.gov.hmcts.reform.ccd.client.model.AboutToStartOrSubmitCallbackResponse; import uk.gov.hmcts.reform.ccd.client.model.CallbackResponse; import uk.gov.hmcts.reform.ccd.client.model.SubmittedCallbackResponse; +import uk.gov.hmcts.reform.civil.bankholidays.WorkingDayIndicator; import uk.gov.hmcts.reform.civil.callback.Callback; import uk.gov.hmcts.reform.civil.callback.CallbackHandler; import uk.gov.hmcts.reform.civil.callback.CallbackParams; import uk.gov.hmcts.reform.civil.callback.CaseEvent; +import uk.gov.hmcts.reform.civil.documentmanagement.model.Document; import uk.gov.hmcts.reform.civil.enums.MultiPartyScenario; -import uk.gov.hmcts.reform.civil.model.common.Element; -import uk.gov.hmcts.reform.civil.service.FeatureToggleService; import uk.gov.hmcts.reform.civil.model.BusinessProcess; import uk.gov.hmcts.reform.civil.model.CaseData; import uk.gov.hmcts.reform.civil.model.CertificateOfService; @@ -20,9 +21,10 @@ import uk.gov.hmcts.reform.civil.model.ServedDocumentFiles; import uk.gov.hmcts.reform.civil.model.common.DynamicList; import uk.gov.hmcts.reform.civil.model.common.DynamicListElement; -import uk.gov.hmcts.reform.civil.documentmanagement.model.Document; +import uk.gov.hmcts.reform.civil.model.common.Element; import uk.gov.hmcts.reform.civil.service.DeadlinesCalculator; import uk.gov.hmcts.reform.civil.service.ExitSurveyContentService; +import uk.gov.hmcts.reform.civil.service.FeatureToggleService; import uk.gov.hmcts.reform.civil.service.Time; import uk.gov.hmcts.reform.civil.utils.AssignCategoryId; import uk.gov.hmcts.reform.civil.utils.ElementUtils; @@ -52,6 +54,7 @@ import static uk.gov.hmcts.reform.civil.helpers.DateFormatHelper.DATE_TIME_AT; import static uk.gov.hmcts.reform.civil.helpers.DateFormatHelper.formatLocalDateTime; +@Slf4j @Service @RequiredArgsConstructor public class NotifyClaimDetailsCallbackHandler extends CallbackHandler implements ParticularsOfClaimValidator { @@ -81,21 +84,31 @@ public class NotifyClaimDetailsCallbackHandler extends CallbackHandler implement "Your claim will progress offline if you only notify one Defendant of the claim details."; public static final String DOC_SERVED_DATE_IN_FUTURE = - "Date you served the documents must be today or in the past"; + "On what day did you serve must be today or in the past"; public static final String DOC_SERVED_DATE_OLDER_THAN_14DAYS = - "Date of Service should not be more than 14 days old"; + "On what day did you serve should not be more than 14 days old"; + + public static final String DATE_OF_SERVICE_NOT_GREATER_THAN_2_WORKING_DAYS = + "The date of service must be no greater than 2 working days in the future"; + + public static final String DATE_OF_SERVICE_DATE_OLDER_THAN_14DAYS = + "The date of service should not be more than 14 days old"; + + public static final String DATE_OF_SERVICE_DATE_IS_WORKING_DAY = + "For the date of service please enter a working day"; public static final String DOC_SERVED_MANDATORY = "Supporting evidence is required"; public static final String BOTH_CERTIFICATE_SERVED_SAME_DATE = - "Date of Service for both certificate must be the same"; + "The date of Service for defendant 1 and defendant 2 must be the same"; private final ExitSurveyContentService exitSurveyContentService; private final ObjectMapper objectMapper; private final Time time; private final DeadlinesCalculator deadlinesCalculator; + private final WorkingDayIndicator workingDayIndicator; private final FeatureToggleService featureToggleService; private final AssignCategoryId assignCategoryId; @@ -208,24 +221,31 @@ private CallbackResponse submitClaim(CallbackParams callbackParams) { private LocalDateTime getEarliestDateOfService(CaseData caseData) { LocalDateTime date = time.now(); + LocalDateTime deemedDate1 = null; + LocalDateTime deemedDate2 = null; if (Objects.nonNull(caseData.getCosNotifyClaimDetails1()) - && Objects.nonNull(caseData.getCosNotifyClaimDetails1().getCosDateOfServiceForDefendant())) { - LocalDateTime cosDate1 = caseData.getCosNotifyClaimDetails1() - .getCosDateOfServiceForDefendant().atTime(time.now().toLocalTime()); - if (cosDate1.isBefore(date)) { - date = cosDate1; - } + && Objects.nonNull(caseData.getCosNotifyClaimDetails1().getCosDateDeemedServedForDefendant())) { + deemedDate1 = caseData.getCosNotifyClaimDetails1() + .getCosDateDeemedServedForDefendant().atTime(time.now().toLocalTime()); } + if (Objects.nonNull(caseData.getCosNotifyClaimDetails2()) - && Objects.nonNull(caseData.getCosNotifyClaimDetails2().getCosDateOfServiceForDefendant())) { - LocalDateTime cosDate2 = caseData.getCosNotifyClaimDetails2() - .getCosDateOfServiceForDefendant().atTime(time.now().toLocalTime()); - if (cosDate2.isBefore(date)) { - date = cosDate2; - } + && Objects.nonNull(caseData.getCosNotifyClaimDetails2().getCosDateDeemedServedForDefendant())) { + deemedDate2 = caseData.getCosNotifyClaimDetails2() + .getCosDateDeemedServedForDefendant().atTime(time.now().toLocalTime()); + } + + if (deemedDate1 != null && deemedDate2 != null) { + return deemedDate1.isBefore(deemedDate2) ? deemedDate1 : deemedDate2; + } else if (deemedDate1 != null) { + return deemedDate1; + } else if (deemedDate2 != null) { + return deemedDate2; + } else { + // If both deemedDate1 and deemedDate2 are null, use the current date and time + return date; } - return date; } private CaseData saveCoSDetailsDoc(CaseData caseData, int lipNumber) { @@ -369,12 +389,9 @@ private CallbackResponse validateCoSDetailsDefendant1(final CallbackParams callb caseData.getCosNotifyClaimDetails1().setCosDocSaved(NO); } - final String dateValidationErrorMessage = getServiceOfDateValidationMessage( - caseData.getCosNotifyClaimDetails1()); + List dateValidationErrorMessages = getServiceOfDateValidationMessages(caseData.getCosNotifyClaimDetails1()); + errors.addAll(dateValidationErrorMessages); - if (!dateValidationErrorMessage.isEmpty()) { - errors.add(dateValidationErrorMessage); - } if (Objects.nonNull(caseData.getCosNotifyClaimDetails1()) && isMandatoryDocMissing(caseData.getCosNotifyClaimDetails1())) { errors.add(DOC_SERVED_MANDATORY); @@ -396,12 +413,8 @@ private CallbackResponse validateCoSDetailsDefendant2(final CallbackParams callb if (Objects.nonNull(caseData.getCosNotifyClaimDetails2())) { caseData.getCosNotifyClaimDetails2().setCosDocSaved(NO); } - final String dateValidationErrorMessage = getServiceOfDateValidationMessage( - caseData.getCosNotifyClaimDetails2()); - - if (!dateValidationErrorMessage.isEmpty()) { - errors.add(dateValidationErrorMessage); - } + List dateValidationErrorMessages = getServiceOfDateValidationMessages(caseData.getCosNotifyClaimDetails2()); + errors.addAll(dateValidationErrorMessages); if (isBothDefendantLip(caseData) && !isBothDefendantWithSameDateOfService(caseData)) { errors.add(BOTH_CERTIFICATE_SERVED_SAME_DATE); @@ -426,16 +439,32 @@ private boolean isMandatoryDocMissing(CertificateOfService certificateOfService) return Objects.isNull(certificateOfService.getCosEvidenceDocument()); } - private String getServiceOfDateValidationMessage(CertificateOfService certificateOfService) { - final String errorMessage = ""; + private List getServiceOfDateValidationMessages(CertificateOfService certificateOfService) { + List errorMessages = new ArrayList<>(); + if (Objects.nonNull(certificateOfService)) { if (isCosDefendantNotifyDateFutureDate(certificateOfService.getCosDateOfServiceForDefendant())) { - return DOC_SERVED_DATE_IN_FUTURE; - } else if (isCosDefendantNotifyDateOlderThan14Days(certificateOfService.getCosDateOfServiceForDefendant())) { - return DOC_SERVED_DATE_OLDER_THAN_14DAYS; + errorMessages.add(DOC_SERVED_DATE_IN_FUTURE); + } + + if (isCosDefendantNotifyDateOlderThan14Days(certificateOfService.getCosDateOfServiceForDefendant())) { + errorMessages.add(DOC_SERVED_DATE_OLDER_THAN_14DAYS); + } + + if (isDeemedServedWithinMaxWorkingDays(certificateOfService.getCosDateDeemedServedForDefendant())) { + errorMessages.add(DATE_OF_SERVICE_NOT_GREATER_THAN_2_WORKING_DAYS); + } + + if (isDeemedServedDateIsNotWorkingDay(certificateOfService.getCosDateDeemedServedForDefendant())) { + errorMessages.add(DATE_OF_SERVICE_DATE_IS_WORKING_DAY); + } + + if (isDeemedServedDateOlderThan14Days(certificateOfService.getCosDateDeemedServedForDefendant())) { + errorMessages.add(DATE_OF_SERVICE_DATE_OLDER_THAN_14DAYS); } } - return errorMessage; + + return errorMessages; } private boolean isCosDefendantNotifyDateFutureDate(LocalDate cosDateOfServiceForDefendant) { @@ -443,9 +472,42 @@ private boolean isCosDefendantNotifyDateFutureDate(LocalDate cosDateOfServiceFor } private boolean isCosDefendantNotifyDateOlderThan14Days(LocalDate cosDateOfServiceForDefendant) { - return time.now().isAfter(deadlinesCalculator.plus14DaysAt4pmDeadline(cosDateOfServiceForDefendant - .atTime(time.now().toLocalTime()))); + LocalDateTime notificationDeadline = deadlinesCalculator.plus14DaysDeadline(cosDateOfServiceForDefendant + .atTime(time.now().toLocalTime())); + LocalDateTime currentDateTime = time.now(); + LocalDateTime today4pm = currentDateTime.toLocalDate().atTime(16, 0); + + boolean isAfter4pmToday = currentDateTime.isAfter(today4pm) + && currentDateTime.toLocalDate().equals(notificationDeadline.toLocalDate()); + + boolean isAfter14DaysAt4pmDeadline = currentDateTime.isAfter(notificationDeadline); + + return isAfter14DaysAt4pmDeadline || isAfter4pmToday; + } + + private boolean isDeemedServedDateOlderThan14Days(LocalDate cosDateOfServiceForDefendant) { + LocalDateTime deemedServedDeadline = deadlinesCalculator.plus14DaysDeadline(cosDateOfServiceForDefendant + .atTime(time.now().toLocalTime())); + LocalDateTime currentDateTime = time.now(); + LocalDateTime today4pm = currentDateTime.toLocalDate().atTime(16, 0); + + boolean isAfter4pmToday = currentDateTime.isAfter(today4pm) + && currentDateTime.toLocalDate().equals(deemedServedDeadline.toLocalDate()); + + boolean isAfter14DaysAt4pmDeadline = currentDateTime.isAfter(deemedServedDeadline); + + return isAfter14DaysAt4pmDeadline || isAfter4pmToday; + } + + public boolean isDeemedServedWithinMaxWorkingDays(LocalDate cosDateOfServiceForDefendant) { + LocalDate currentDate = LocalDate.now(); + LocalDate maxWorkingDaysDate = deadlinesCalculator.plusWorkingDays(currentDate, 2); + + return cosDateOfServiceForDefendant.isAfter(maxWorkingDaysDate); + } + private boolean isDeemedServedDateIsNotWorkingDay(LocalDate cosDateOfServiceForDefendant) { + return !workingDayIndicator.isWorkingDay(cosDateOfServiceForDefendant); } private boolean isBothDefendantLip(CaseData caseData) { @@ -458,8 +520,8 @@ private boolean isBothDefendantLip(CaseData caseData) { private boolean isBothDefendantWithSameDateOfService(CaseData caseData) { if (Objects.nonNull(caseData.getCosNotifyClaimDetails1()) && Objects.nonNull(caseData.getCosNotifyClaimDetails2())) { - if (caseData.getCosNotifyClaimDetails1().getCosDateOfServiceForDefendant() - .equals(caseData.getCosNotifyClaimDetails2().getCosDateOfServiceForDefendant())) { + if (caseData.getCosNotifyClaimDetails1().getCosDateDeemedServedForDefendant() + .equals(caseData.getCosNotifyClaimDetails2().getCosDateDeemedServedForDefendant())) { return true; } } diff --git a/src/main/java/uk/gov/hmcts/reform/civil/model/CertificateOfService.java b/src/main/java/uk/gov/hmcts/reform/civil/model/CertificateOfService.java index a0f83c9cd6b..df1a5830ff0 100644 --- a/src/main/java/uk/gov/hmcts/reform/civil/model/CertificateOfService.java +++ b/src/main/java/uk/gov/hmcts/reform/civil/model/CertificateOfService.java @@ -27,6 +27,8 @@ public class CertificateOfService { @JsonProperty("cosDateOfServiceForDefendant") private LocalDate cosDateOfServiceForDefendant; + @JsonProperty("cosDateDeemedServedForDefendant") + private LocalDate cosDateDeemedServedForDefendant; @JsonProperty("cosServedDocumentFiles") private String cosServedDocumentFiles; @JsonProperty("cosEvidenceDocument") diff --git a/src/test/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandlerTest.java b/src/test/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandlerTest.java index 56cefd08ece..e8969ee3e43 100644 --- a/src/test/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandlerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/civil/handler/callback/user/NotifyClaimDetailsCallbackHandlerTest.java @@ -13,25 +13,27 @@ import org.springframework.boot.test.mock.mockito.MockBean; import uk.gov.hmcts.reform.ccd.client.model.AboutToStartOrSubmitCallbackResponse; import uk.gov.hmcts.reform.ccd.client.model.SubmittedCallbackResponse; +import uk.gov.hmcts.reform.civil.bankholidays.WorkingDayIndicator; import uk.gov.hmcts.reform.civil.callback.CallbackParams; import uk.gov.hmcts.reform.civil.config.ExitSurveyConfiguration; import uk.gov.hmcts.reform.civil.documentmanagement.model.Document; import uk.gov.hmcts.reform.civil.handler.callback.BaseCallbackHandlerTest; import uk.gov.hmcts.reform.civil.helpers.CaseDetailsConverter; -import uk.gov.hmcts.reform.civil.model.DocumentWithRegex; -import uk.gov.hmcts.reform.civil.model.common.Element; -import uk.gov.hmcts.reform.civil.service.FeatureToggleService; import uk.gov.hmcts.reform.civil.model.CaseData; +import uk.gov.hmcts.reform.civil.model.DocumentWithRegex; import uk.gov.hmcts.reform.civil.model.ServedDocumentFiles; +import uk.gov.hmcts.reform.civil.model.common.Element; import uk.gov.hmcts.reform.civil.sampledata.CaseDataBuilder; import uk.gov.hmcts.reform.civil.sampledata.PartyBuilder; import uk.gov.hmcts.reform.civil.service.DeadlinesCalculator; import uk.gov.hmcts.reform.civil.service.ExitSurveyContentService; +import uk.gov.hmcts.reform.civil.service.FeatureToggleService; import uk.gov.hmcts.reform.civil.service.Time; import uk.gov.hmcts.reform.civil.utils.AssignCategoryId; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -69,6 +71,9 @@ class NotifyClaimDetailsCallbackHandlerTest extends BaseCallbackHandlerTest { @MockBean private Time time; + @MockBean + private WorkingDayIndicator workingDayIndicator; + @MockBean private DeadlinesCalculator deadlinesCalculator; @@ -208,14 +213,20 @@ void setup() { newDate = LocalDateTime.of(2020, 1, 15, 16, 0, 0); sixMonthDate = LocalDateTime.of(2020, 7, 1, 0, 0, 0); when(time.now()).thenReturn(localDateTime); + when(deadlinesCalculator.plus14DaysDeadline(localDateTime)).thenReturn(newDate); when(deadlinesCalculator.plus14DaysAt4pmDeadline(localDateTime)).thenReturn(newDate); when(deadlinesCalculator.addMonthsToDateToNextWorkingDayAtMidnight(6, localDateTime.toLocalDate())) .thenReturn(sixMonthDate); + when(workingDayIndicator.isWeekend(any(LocalDate.class))).thenReturn(true); + when(deadlinesCalculator.plusWorkingDays(localDateTime.toLocalDate(), 2)) + .thenReturn(LocalDate.of(2023, 10, 16)); } @Test void shouldUpdateBusinessProcess_whenInvoked() { - CaseData caseData = CaseDataBuilder.builder().atStateClaimNotified_1v1().build(); + CaseData caseData = CaseDataBuilder.builder().atStateClaimNotified_1v1() + .setCoSClaimDetailsWithDate(true, false, localDateTime.toLocalDate(), localDateTime.toLocalDate(), null, null, true, false) + .build(); CallbackParams params = callbackParamsOf(caseData, ABOUT_TO_SUBMIT); var response = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); @@ -255,14 +266,20 @@ void shouldUpdateBusinessProcess_whenInvoked1v2DifferentSolicitor() { @Test void shouldUpdateCertificateOfService_and_documents_cos1_whenSubmitted() { LocalDate cosDate = localDateTime.minusDays(2).toLocalDate(); + LocalDate deemedDate = localDateTime.minusDays(2).toLocalDate(); when(time.now()).thenReturn(LocalDate.now().atTime(15, 05)); when(deadlinesCalculator.plus14DaysAt4pmDeadline(cosDate.atTime(15, 05))) + .thenReturn(newDate.minusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(cosDate.atTime(15, 05))) .thenReturn(newDate.minusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(deemedDate.atTime(15, 05))) + .thenReturn(newDate.minusDays(2)); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, false, cosDate, null, true, false) + .setCoSClaimDetailsWithDate(true, false, cosDate, deemedDate, null, null, true, false) .build(); + CallbackParams params = callbackParamsOf(caseData, ABOUT_TO_SUBMIT); var response = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); CaseData updatedData = mapper.convertValue(response.getData(), CaseData.class); @@ -278,13 +295,21 @@ void shouldUpdateCertificateOfService_and_documents_cos1_whenSubmitted() { @Test void shouldUpdateCertificateOfService_and_documents_cos2_whenSubmitted() { LocalDate cosDate = localDateTime.minusDays(2).toLocalDate(); + LocalDate deemedDate = localDateTime.minusDays(2).toLocalDate(); + LocalDate currentDate = LocalDate.now(); + + when(deadlinesCalculator.plusWorkingDays(currentDate, 2)) + .thenReturn(LocalDate.now().plusDays(2)); when(time.now()).thenReturn(LocalDate.now().atTime(15, 05)); when(deadlinesCalculator.plus14DaysAt4pmDeadline(cosDate.atTime(15, 05))) .thenReturn(newDate.minusDays(2)); + when(deadlinesCalculator.plus14DaysAt4pmDeadline(deemedDate.atTime(15, 05))) + .thenReturn(newDate.minusDays(2)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(false); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(false, true, null, cosDate, false, true) + .setCoSClaimDetailsWithDate(false, true, null, null, cosDate, deemedDate, false, true) .build(); CallbackParams params = callbackParamsOf(caseData, ABOUT_TO_SUBMIT); var response = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); @@ -302,15 +327,17 @@ void shouldUpdateCertificateOfService_and_documents_cos2_whenSubmitted() { void shouldUpdate_to_earliest_day_cos2_is_earliest_whenSubmitted() { LocalDate cos1Date = localDateTime.minusDays(2).toLocalDate(); LocalDate cos2Date = localDateTime.minusDays(3).toLocalDate(); + LocalDate deemed1Date = localDateTime.minusDays(2).toLocalDate(); + LocalDate deemed2Date = localDateTime.minusDays(3).toLocalDate(); when(time.now()).thenReturn(LocalDate.now().atTime(15, 05)); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(cos1Date.atTime(15, 05))) + when(deadlinesCalculator.plus14DaysAt4pmDeadline(deemed1Date.atTime(15, 05))) .thenReturn(newDate.minusDays(2)); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(cos2Date.atTime(15, 05))) + when(deadlinesCalculator.plus14DaysAt4pmDeadline(deemed2Date.atTime(15, 05))) .thenReturn(newDate.minusDays(3)); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, true, cos1Date, cos2Date, true, true) + .setCoSClaimDetailsWithDate(true, true, cos1Date, deemed1Date, cos2Date, deemed2Date, true, true) .build(); CallbackParams params = callbackParamsOf(caseData, ABOUT_TO_SUBMIT); var response = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); @@ -327,15 +354,21 @@ void shouldUpdate_to_earliest_day_cos2_is_earliest_whenSubmitted() { void shouldUpdate_to_earliest_day_cos1_is_earliest_whenSubmitted() { LocalDate cos1Date = localDateTime.minusDays(3).toLocalDate(); LocalDate cos2Date = localDateTime.minusDays(2).toLocalDate(); + LocalDate deemed1Date = localDateTime.minusDays(2).toLocalDate(); + LocalDate deemed2Date = localDateTime.minusDays(3).toLocalDate(); when(time.now()).thenReturn(LocalDate.now().atTime(15, 05)); when(deadlinesCalculator.plus14DaysAt4pmDeadline(cos1Date.atTime(15, 05))) - .thenReturn(newDate.minusDays(3)); + .thenReturn(newDate.minusDays(3)); when(deadlinesCalculator.plus14DaysAt4pmDeadline(cos2Date.atTime(15, 05))) + .thenReturn(newDate.minusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(cos1Date.atTime(15, 05))) + .thenReturn(newDate.minusDays(3)); + when(deadlinesCalculator.plus14DaysDeadline(cos2Date.atTime(15, 05))) .thenReturn(newDate.minusDays(2)); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, true, cos1Date, cos2Date, true, true) + .setCoSClaimDetailsWithDate(true, true, cos1Date, deemed1Date, cos2Date, deemed2Date, true, true) .build(); CallbackParams params = callbackParamsOf(caseData, ABOUT_TO_SUBMIT); var response = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); @@ -371,7 +404,8 @@ static Stream caseDataStream() { .other(documentList).build(); return Stream.of( - arguments(CaseDataBuilder.builder().atStateClaimDraft().build().toBuilder() + arguments(CaseDataBuilder.builder().atStateClaimDraft() + .build().toBuilder() .uploadParticularsOfClaim(YES) .servedDocumentFiles(documentToUpload) .build()) @@ -382,7 +416,6 @@ static Stream caseDataStream() { @MethodSource("caseDataStream") void shouldAssignCategoryIds_whenDocumentExist(CaseData caseData) { when(featureToggleService.isCaseFileViewEnabled()).thenReturn(true); - var response = (AboutToStartOrSubmitCallbackResponse) handler.handle( callbackParamsOf(caseData, ABOUT_TO_SUBMIT)); // When @@ -499,7 +532,7 @@ void shouldReturnCoSConfirmation_whenCosNotifyDetailsSuccess() { .thenReturn(past.plusDays(14).atTime(16, 0)); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, true, past, past, true, true) + .setCoSClaimDetailsWithDate(true, true, past, past, past, past, true, true) .build(); CallbackParams params = callbackParamsOf(caseData, SUBMITTED); SubmittedCallbackResponse response = (SubmittedCallbackResponse) handler.handle(params); @@ -514,7 +547,7 @@ void shouldReturnCoSConfirmation_1Lip1Lr_whenCosNotifyDetailsSuccess() { .thenReturn(past.plusDays(14).atTime(16, 0)); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_1Lip_1Lr() - .setCoSClaimDetailsWithDate(true, false, past, null, true, false) + .setCoSClaimDetailsWithDate(true, false, past, past, null, null, true, false) .build(); CallbackParams params = callbackParamsOf(caseData, SUBMITTED); SubmittedCallbackResponse response = (SubmittedCallbackResponse) handler.handle(params); @@ -524,17 +557,29 @@ void shouldReturnCoSConfirmation_1Lip1Lr_whenCosNotifyDetailsSuccess() { @Nested class MidEventValidateCos { + public static final String DATE_OF_SERVICE_NOT_GREATER_THAN_2_WORKING_DAYS = + "The date of service must be no greater than 2 working days in the future"; + + public static final String DATE_OF_SERVICE_DATE_OLDER_THAN_14DAYS = + "The date of service should not be more than 14 days old"; + + public static final String DATE_OF_SERVICE_DATE_IS_WORKING_DAY = + "For the date of service please enter a working day"; + @Test void shouldPassValidateCertificateOfService_whenDateIsPast() { LocalDate past = LocalDate.now().minusDays(1); when(time.now()).thenReturn(LocalDate.now().atTime(15, 05)); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(any())) + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(any())) .thenReturn(past.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, true, past, past, true, true) + .setCoSClaimDetailsWithDate(true, true, past, past, past, past, true, true) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails2"); AboutToStartOrSubmitCallbackResponse successResponse = @@ -549,12 +594,15 @@ void shouldPassValidateCertificateOfService_1Lip1Lr_whenDateIsPast() { LocalDate past = LocalDate.now().minusDays(1); when(time.now()).thenReturn(LocalDate.now().atTime(16, 05)); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(any())) + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(any())) .thenReturn(past.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_1Lip_1Lr() - .setCoSClaimDetailsWithDate(true, false, past, null, true, false) + .setCoSClaimDetailsWithDate(true, false, past, past, null, null, true, false) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); AboutToStartOrSubmitCallbackResponse successResponse = @@ -569,12 +617,15 @@ void shouldPassValidateCertificateOfService_1Lr1Lip_whenServiceDateIsPast_notOld LocalDate past = LocalDate.now().minusDays(1); when(time.now()).thenReturn(LocalDate.now().atTime(15, 05)); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(past.atTime(15, 05))) + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(past.atTime(15, 05))) .thenReturn(past.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_1Lr_1Lip() - .setCoSClaimDetailsWithDate(true, false, past, null, true, false) + .setCoSClaimDetailsWithDate(true, false, past, past, null, null, true, false) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); AboutToStartOrSubmitCallbackResponse successResponse = @@ -588,17 +639,20 @@ void shouldNotPassValidateCertificateOfService_1Lr1Lip_whenServiceDateIsPast_Old LocalDate past = LocalDate.now().minusDays(15); when(time.now()).thenReturn(LocalDate.now().atTime(15, 05)); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(past.atTime(15, 05))) + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(past.atTime(15, 05))) .thenReturn(past.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_1Lr_1Lip() - .setCoSClaimDetailsWithDate(true, false, past, null, true, false) + .setCoSClaimDetailsWithDate(true, false, past, past, null, null, true, false) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); AboutToStartOrSubmitCallbackResponse successResponse = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); - assertThat(successResponse.getErrors().size()).isEqualTo(1); + assertThat(successResponse.getErrors().size()).isEqualTo(2); assertThat(params.getCaseData().getCosNotifyClaimDetails1().getCosDocSaved()).isEqualTo(NO); } @@ -606,18 +660,21 @@ void shouldNotPassValidateCertificateOfService_1Lr1Lip_whenServiceDateIsPast_Old void shouldNotPassValidateCertificateOfService_1Lr1Lip_whenServiceDateIsPast_deadlineTodayDate_After16hrs() { LocalDate past = LocalDate.now().minusDays(14); - when(time.now()).thenReturn(LocalDate.now().atTime(16, 05)); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(any())) + when(time.now()).thenReturn(LocalDate.now().atTime(17, 05)); + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(past.atTime(17, 05))) .thenReturn(past.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_1Lr_1Lip() - .setCoSClaimDetailsWithDate(true, false, past, null, true, false) + .setCoSClaimDetailsWithDate(true, false, past, past, null, null, true, false) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); AboutToStartOrSubmitCallbackResponse successResponse = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); - assertThat(successResponse.getErrors().size()).isEqualTo(1); + assertThat(successResponse.getErrors().size()).isEqualTo(2); assertThat(params.getCaseData().getCosNotifyClaimDetails1().getCosDocSaved()).isEqualTo(NO); } @@ -627,12 +684,15 @@ void shouldFailValidateCertificateOfService_When1v2LIP_BothDefendant_DifferentDa LocalDate def2pastDate = LocalDate.now().minusDays(2); when(time.now()).thenReturn(LocalDateTime.now()); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(any())) + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(any())) .thenReturn(def2pastDate.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, true, def1pastDate, def2pastDate, true, true) + .setCoSClaimDetailsWithDate(true, true, def1pastDate, def1pastDate, def2pastDate, def2pastDate, true, true) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails2"); AboutToStartOrSubmitCallbackResponse successResponse = @@ -642,17 +702,20 @@ void shouldFailValidateCertificateOfService_When1v2LIP_BothDefendant_DifferentDa @Test void shouldNotFailValidateCertificateOfService_When1v2LIP_BothDefendant_SameDateOfService() { + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); when(time.now()).thenReturn(LocalDateTime.now()); LocalDate def1pastDate = LocalDate.now().minusDays(1); LocalDate def2pastDate = LocalDate.now().minusDays(1); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(any())) + when(deadlinesCalculator.plus14DaysDeadline(any())) .thenReturn(def1pastDate.plusDays(14).atTime(16, 0)); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, true, def1pastDate, def2pastDate, true, true) + .setCoSClaimDetailsWithDate(true, true, def1pastDate, def1pastDate, def2pastDate, def2pastDate, true, true) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails2"); AboutToStartOrSubmitCallbackResponse successResponse = @@ -664,12 +727,15 @@ void shouldNotFailValidateCertificateOfService_When1v2LIP_BothDefendant_SameDate void shouldPassValidateCertificateOfService_whenHasFile() { LocalDate past = LocalDate.now().minusDays(1); when(time.now()).thenReturn(LocalDateTime.now()); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(any())) + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(any())) .thenReturn(past.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, false, past, null, true, false) + .setCoSClaimDetailsWithDate(true, false, past, past, null, null, true, false) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); AboutToStartOrSubmitCallbackResponse successResponse = @@ -681,17 +747,98 @@ void shouldPassValidateCertificateOfService_whenHasFile() { void shouldFailValidateCertificateOfService_whenHasNoFile() { LocalDate past = LocalDate.now().minusDays(1); when(time.now()).thenReturn(LocalDateTime.now()); - when(deadlinesCalculator.plus14DaysAt4pmDeadline(any())) + when(deadlinesCalculator.plusWorkingDays(LocalDate.now(), 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(any())) .thenReturn(past.plusDays(14).atTime(16, 0)); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); CaseData caseData = CaseDataBuilder.builder() .atStateClaimDetailsNotified_1v2_andNotifyBothCoS() - .setCoSClaimDetailsWithDate(true, false, past, null, false, false) + .setCoSClaimDetailsWithDate(true, false, past, past, null, null, false, false) + .build(); + CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); + AboutToStartOrSubmitCallbackResponse successResponse = + (AboutToStartOrSubmitCallbackResponse) handler.handle(params); + assertThat(successResponse.getErrors().size()).isEqualTo(1); + } + + @Test + void shouldNotPassValidateCertificateOfService_1Lr1Lip_whenDeemedDateIsPast_deadline() { + LocalDate currentDate = LocalDate.now(); + LocalDate deemedServedDate = currentDate.minusDays(15); + + when(time.now()).thenReturn(LocalDate.now().atTime(16, 00)); + when(deadlinesCalculator.plusWorkingDays(currentDate, 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(currentDate.atTime(16, 0))) + .thenReturn(LocalDateTime.of(currentDate, LocalTime.of(16, 0))); + when(deadlinesCalculator.plus14DaysDeadline(deemedServedDate.atTime(16, 0))) + .thenReturn(LocalDateTime.of(deemedServedDate, LocalTime.of(16, 0))); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); + + CaseData caseData = CaseDataBuilder.builder() + .atStateClaimDetailsNotified_1v2_1Lip_1Lr() + .setCoSClaimDetailsWithDate(true, false, currentDate, deemedServedDate, null, null, true, false) .build(); CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); AboutToStartOrSubmitCallbackResponse successResponse = (AboutToStartOrSubmitCallbackResponse) handler.handle(params); assertThat(successResponse.getErrors().size()).isEqualTo(1); + assertThat(successResponse.getErrors()).contains(DATE_OF_SERVICE_DATE_OLDER_THAN_14DAYS); + assertThat(params.getCaseData().getCosNotifyClaimDetails1().getCosDocSaved()).isEqualTo(NO); + } + + @Test + void shouldNotPassValidateCertificateOfService_1Lr1Lip_whenDeemedDateNotInWorkingDay() { + LocalDate currentDate = LocalDate.now(); + LocalDate deemedServedDate = currentDate; + + when(time.now()).thenReturn(LocalDate.now().atTime(16, 00)); + when(deadlinesCalculator.plusWorkingDays(currentDate, 2)) + .thenReturn(LocalDate.now().plusDays(2)); + when(deadlinesCalculator.plus14DaysDeadline(deemedServedDate.atTime(16, 0))) // assuming 4 pm deadline + .thenReturn(LocalDateTime.of(deemedServedDate, LocalTime.of(16, 0))); + when(deadlinesCalculator.plus14DaysDeadline(currentDate.atTime(16, 0))) // assuming 4 pm deadline + .thenReturn(LocalDateTime.of(currentDate, LocalTime.of(16, 0))); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(false); + + CaseData caseData = CaseDataBuilder.builder() + .atStateClaimDetailsNotified_1v2_1Lip_1Lr() + .setCoSClaimDetailsWithDate(true, false, currentDate, deemedServedDate, null, null, true, false) + .build(); + CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); + AboutToStartOrSubmitCallbackResponse successResponse = + (AboutToStartOrSubmitCallbackResponse) handler.handle(params); + assertThat(successResponse.getErrors().size()).isEqualTo(1); + assertThat(successResponse.getErrors()).contains(DATE_OF_SERVICE_DATE_IS_WORKING_DAY); + assertThat(params.getCaseData().getCosNotifyClaimDetails1().getCosDocSaved()).isEqualTo(NO); + } + + @Test + void shouldNotPassValidateCertificateOfService_1Lr1Lip_whenDeemedDateExceeds2WorkingDays() { + LocalDate currentDate = LocalDate.now(); + LocalDate deemedServedDate = currentDate.plusDays(5); + + when(time.now()).thenReturn(LocalDate.now().atTime(16, 00)); + when(deadlinesCalculator.plusWorkingDays(currentDate, 2)) + .thenReturn(LocalDate.of(2023, 10, 16)); + when(deadlinesCalculator.plus14DaysDeadline(deemedServedDate.atTime(16, 0))) + .thenReturn(LocalDateTime.of(deemedServedDate, LocalTime.of(16, 0))); + when(deadlinesCalculator.plus14DaysDeadline(currentDate.atTime(16, 0))) + .thenReturn(LocalDateTime.of(currentDate, LocalTime.of(16, 0))); + when(workingDayIndicator.isWorkingDay(any(LocalDate.class))).thenReturn(true); + + CaseData caseData = CaseDataBuilder.builder() + .atStateClaimDetailsNotified_1v2_1Lip_1Lr() + .setCoSClaimDetailsWithDate(true, false, currentDate, deemedServedDate, null, null, true, false) + .build(); + CallbackParams params = callbackParamsOf(caseData, MID, "validateCosNotifyClaimDetails1"); + AboutToStartOrSubmitCallbackResponse successResponse = + (AboutToStartOrSubmitCallbackResponse) handler.handle(params); + assertThat(successResponse.getErrors().size()).isEqualTo(1); + assertThat(successResponse.getErrors()).contains(DATE_OF_SERVICE_NOT_GREATER_THAN_2_WORKING_DAYS); + assertThat(params.getCaseData().getCosNotifyClaimDetails1().getCosDocSaved()).isEqualTo(NO); } } } diff --git a/src/test/java/uk/gov/hmcts/reform/civil/sampledata/CaseDataBuilder.java b/src/test/java/uk/gov/hmcts/reform/civil/sampledata/CaseDataBuilder.java index 09ca1f58eee..e5ee5aa7379 100644 --- a/src/test/java/uk/gov/hmcts/reform/civil/sampledata/CaseDataBuilder.java +++ b/src/test/java/uk/gov/hmcts/reform/civil/sampledata/CaseDataBuilder.java @@ -5729,7 +5729,7 @@ public CaseDataBuilder setCaseListDisplayDefendantSolicitorReferences(boolean is } public CaseDataBuilder setCoSClaimDetailsWithDate(boolean setCos1, boolean setCos2, - LocalDate cos1Date, LocalDate cos2Date, + LocalDate cos1Date, LocalDate deemed1Date, LocalDate cos2Date, LocalDate deemed2Date, boolean file1, boolean file2) { List> files = wrapElements(Document.builder() .documentUrl("fake-url") @@ -5745,7 +5745,8 @@ public CaseDataBuilder setCoSClaimDetailsWithDate(boolean setCos1, boolean setCo cosUIStatement.add("CERTIFIED"); if (setCos1) { CertificateOfService.CertificateOfServiceBuilder cos1Builder = CertificateOfService.builder() - .cosDateOfServiceForDefendant(cos1Date); + .cosDateOfServiceForDefendant(cos1Date) + .cosDateDeemedServedForDefendant(deemed1Date); if (file1) { cos1Builder.cosEvidenceDocument(files); } @@ -5753,7 +5754,8 @@ public CaseDataBuilder setCoSClaimDetailsWithDate(boolean setCos1, boolean setCo } if (setCos2) { CertificateOfService.CertificateOfServiceBuilder cos2Builder = CertificateOfService.builder() - .cosDateOfServiceForDefendant(cos2Date); + .cosDateOfServiceForDefendant(cos2Date) + .cosDateDeemedServedForDefendant(deemed2Date); if (file2) { cos2Builder.cosEvidenceDocument(files2); }