diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index fa6ffe830d..55497435ef 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -87,6 +87,8 @@ def secrets = [ secret('em-stitching-enabled', 'IA_EM_STITCHING_ENABLED'), secret('submit-hearing-requirements-enabled', 'IA_SUBMIT_HEARING_REQUIREMENTS_ENABLED'), secret('launch-darkly-sdk-key', 'LAUNCH_DARKLY_SDK_KEY'), + secret('ia-gov-notify-key', 'IA_GOV_NOTIFY_KEY'), + secret('ia-bail-gov-notify-key', 'IA_BAIL_GOV_NOTIFY_KEY'), secret('app-insights-connection-string', 'app-insights-connection-string'), secret('postgres-auth-values-password', 'PG_AUTH_VALUES_YAML_PASS'), secret('generic-values-preview-password', 'GENERIC_VALUES_PREVIEW_YAML_PASS'), diff --git a/Jenkinsfile_nightly b/Jenkinsfile_nightly index acf923c3c9..d013cff765 100644 --- a/Jenkinsfile_nightly +++ b/Jenkinsfile_nightly @@ -71,6 +71,8 @@ def secrets = [ secret('em-stitching-enabled', 'IA_EM_STITCHING_ENABLED'), secret('submit-hearing-requirements-enabled', 'IA_SUBMIT_HEARING_REQUIREMENTS_ENABLED'), secret('launch-darkly-sdk-key', 'LAUNCH_DARKLY_SDK_KEY'), + secret('ia-gov-notify-key', 'IA_GOV_NOTIFY_KEY'), + secret('ia-bail-gov-notify-key', 'IA_BAIL_GOV_NOTIFY_KEY'), secret('app-insights-connection-string', 'app-insights-connection-string'), secret('postgres-auth-values-password', 'PG_AUTH_VALUES_YAML_PASS'), secret('generic-values-preview-password', 'GENERIC_VALUES_PREVIEW_YAML_PASS'), diff --git a/Jenkinsfile_parameterized b/Jenkinsfile_parameterized index 1f1929e245..e397e9b7ea 100644 --- a/Jenkinsfile_parameterized +++ b/Jenkinsfile_parameterized @@ -51,6 +51,8 @@ def secrets = [ secret('s2s-microservice', 'IA_S2S_MICROSERVICE'), secret('prof-ref-data-url', 'PROF_REF_DATA_URL'), secret('launch-darkly-sdk-key', 'LAUNCH_DARKLY_SDK_KEY'), + secret('ia-gov-notify-key', 'IA_GOV_NOTIFY_KEY'), + secret('ia-bail-gov-notify-key', 'IA_BAIL_GOV_NOTIFY_KEY'), secret('app-insights-connection-string', 'app-insights-connection-string'), secret('postgres-auth-values-password', 'PG_AUTH_VALUES_YAML_PASS'), secret('generic-values-preview-password', 'GENERIC_VALUES_PREVIEW_YAML_PASS'), diff --git a/charts/ia-case-api/Chart.yaml b/charts/ia-case-api/Chart.yaml index ae9c05355a..db7f7ffdeb 100644 --- a/charts/ia-case-api/Chart.yaml +++ b/charts/ia-case-api/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: ia-case-api home: https://github.com/hmcts/ia-case-api -version: 0.0.55 +version: 0.0.56 description: Immigration & Asylum Case API maintainers: - name: HMCTS Immigration & Asylum Team diff --git a/charts/ia-case-api/values.preview.template.yaml b/charts/ia-case-api/values.preview.template.yaml index f425f253a9..f40dfdcc45 100644 --- a/charts/ia-case-api/values.preview.template.yaml +++ b/charts/ia-case-api/values.preview.template.yaml @@ -35,10 +35,16 @@ java: FEES_REGISTER_API_URL: "http://fees-register-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal" DUMMY: true PAYMENT_REMINDER_DUE_IN_MINUTES: 1 + IA_GOV_NOTIFY_KEY: ${IA_GOV_NOTIFY_KEY} + IA_BAIL_GOV_NOTIFY_KEY: ${IA_BAIL_GOV_NOTIFY_KEY} keyVaults: ia: resourceGroup: ia secrets: + - name: ia-gov-notify-key + alias: IA_GOV_NOTIFY_KEY + - name: ia-bail-gov-notify-key + alias: IA_BAIL_GOV_NOTIFY_KEY - name: docmosis-enabled alias: IA_DOCMOSIS_ENABLED - name: em-stitching-enabled @@ -200,7 +206,7 @@ ia-case-notifications-api: enabled: true #set to true if testing against a local branch java: imagePullPolicy: Always - image: hmctspublic.azurecr.io/ia/case-notifications-api:latest + image: hmctspublic.azurecr.io/ia/case-notifications-api:pr-1343 releaseNameOverride: ${SERVICE_NAME}-case-notifications-api ingressHost: ${SERVICE_NAME}-notifications-api.preview.platform.hmcts.net devcpuRequests: 500m @@ -209,8 +215,8 @@ ia-case-notifications-api: devmemoryLimits: 4Gi environment: IA_HOME_OFFICE_GOV_NOTIFY_ENABLED: true - IA_GOV_NOTIFY_KEY: "test_key-7f72d0fb-2bc4-421b-bceb-1bf5bf350ff9-3df5a74b-f25b-4052-b00f-3f71d33cd0eb" - IA_BAIL_GOV_NOTIFY_KEY: "testkey-b9593914-99e1-484e-ad63-a51d7b4c164f-b817a2e5-7a30-4938-98f0-6099110c2879" + IA_GOV_NOTIFY_KEY: ${IA_GOV_NOTIFY_KEY} + IA_BAIL_GOV_NOTIFY_KEY: ${IA_BAIL_GOV_NOTIFY_KEY} IA_EXUI_FRONTEND_URL: https://manage-case.{{ .Values.global.environment }}.platform.hmcts.net/ IA_AIP_FRONTEND_URL: https://immigration-appeal.{{ .Values.global.environment }}.platform.hmcts.net/ DM_URL: http://dm-store-aat.service.core-compute-aat.internal @@ -451,7 +457,6 @@ ia-timed-event-service: java: imagePullPolicy: Always image: hmctspublic.azurecr.io/ia/timed-event-service:latest - # image: hmctspublic.azurecr.io/ia/timed-event-service:pr-95 releaseNameOverride: ${SERVICE_NAME}-timed-event-service ingressHost: ${SERVICE_NAME}-timed-event-service.preview.platform.hmcts.net devcpuRequests: 500m @@ -571,6 +576,7 @@ ia-aip-frontend: nodejs: imagePullPolicy: Always image: hmctspublic.azurecr.io/ia/aip-frontend:latest + # image: hmctspublic.azurecr.io/ia/aip-frontend:pr-972 ingressHost: ${SERVICE_NAME}-aip-frontend.preview.platform.hmcts.net # override in public facing environments applicationPort: 3000 devcpuRequests: 500m diff --git a/charts/ia-case-api/values.yaml b/charts/ia-case-api/values.yaml index 419854760e..90e8c8c9c5 100644 --- a/charts/ia-case-api/values.yaml +++ b/charts/ia-case-api/values.yaml @@ -46,6 +46,8 @@ java: PAYMENT_EA_HU_NO_REMISSION_DUE_IN_MINUTES: 20160 ADA_CASE_LISTED_DIRECTION_DUE_IN_DAYS: 15 PAYMENT_REMINDER_DUE_IN_MINUTES: 10080 + IA_GOV_NOTIFY_KEY: ${IA_GOV_NOTIFY_KEY} + IA_BAIL_GOV_NOTIFY_KEY: ${IA_BAIL_GOV_NOTIFY_KEY} postgresql: auth: username: ia_case_api @@ -57,6 +59,10 @@ java: ia: resourceGroup: ia secrets: + - name: ia-gov-notify-key + alias: IA_GOV_NOTIFY_KEY + - name: ia-bail-gov-notify-key + alias: IA_BAIL_GOV_NOTIFY_KEY - name: docmosis-enabled alias: IA_DOCMOSIS_ENABLED - name: em-stitching-enabled diff --git a/docker-compose.yml b/docker-compose.yml index 99e5c8fcfb..96116a4ee6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,6 +53,8 @@ services: IA_SUBMIT_HEARING_REQUIREMENTS_ENABLED: CASE_DOCUMENT_AM_URL: http://ccd-case-document-am-api:4455 IA_HEARINGS_API_URL: http://ia-hearings-api:8100 + IA_GOV_NOTIFY_KEY: + IA_BAIL_GOV_NOTIFY_KEY: external_links: - idam-api - dm-store diff --git a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/AsylumCaseFieldDefinition.java b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/AsylumCaseFieldDefinition.java index 4ddc423d1c..0c3b160bd3 100644 --- a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/AsylumCaseFieldDefinition.java +++ b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/AsylumCaseFieldDefinition.java @@ -2735,6 +2735,9 @@ public enum AsylumCaseFieldDefinition { IS_REMOTE_HEARING("isRemoteHearing", new TypeReference(){}), + NOTIFICATIONS("notifications", new TypeReference>>(){}), + NOTIFICATIONS_SENT("notificationsSent", new TypeReference>>(){}), + REQUEST_FEE_REMISSION_DATE( "requestFeeRemissionDate", new TypeReference(){}), diff --git a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/StoredNotification.java b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/StoredNotification.java new file mode 100644 index 0000000000..6b8f388388 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/StoredNotification.java @@ -0,0 +1,22 @@ +package uk.gov.hmcts.reform.iacaseapi.domain.entities; + +import lombok.*; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.Document; + +@EqualsAndHashCode +@ToString +@Getter +@Builder +@AllArgsConstructor +public class StoredNotification { + @NonNull private String notificationId; + @NonNull private String notificationDateSent; + @NonNull private String notificationSentTo; + @NonNull private String notificationBody; + @Setter private Document notificationDocument; + @NonNull private String notificationMethod; + @NonNull private String notificationStatus; + @NonNull private String notificationReference; + @NonNull private String notificationSubject; + private String notificationErrorMessage; +} diff --git a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/Event.java b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/Event.java index 27df3a566f..05b995996b 100644 --- a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/Event.java +++ b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/Event.java @@ -154,6 +154,7 @@ public enum Event { LIST_ASSIST_INTEGRATION("listAssistIntegration"), TRIGGER_CMR_LISTED("triggerCmrListed"), DECISION_WITHOUT_HEARING_LISTED("decisionWithoutHearingListed"), + SAVE_NOTIFICATIONS_TO_DATA("saveNotificationsToData"), @JsonEnumDefaultValue UNKNOWN("unknown"); diff --git a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandler.java b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandler.java index ae917760ef..af84f2dd9c 100644 --- a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandler.java +++ b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandler.java @@ -137,7 +137,8 @@ public boolean canHandle( Event.REINSTATE_APPEAL, Event.GENERATE_UPPER_TRIBUNAL_BUNDLE, Event.MANAGE_FEE_UPDATE, - Event.UPDATE_TRIBUNAL_DECISION); + Event.UPDATE_TRIBUNAL_DECISION, + Event.SAVE_NOTIFICATIONS_TO_DATA); if (isEmStitchingEnabled) { allowedEvents.add(Event.SUBMIT_CASE); if (!isSaveAndContinueEnabled) { diff --git a/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/SaveNotificationsToDataHandler.java b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/SaveNotificationsToDataHandler.java new file mode 100644 index 0000000000..81a566eb11 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/SaveNotificationsToDataHandler.java @@ -0,0 +1,152 @@ +package uk.gov.hmcts.reform.iacaseapi.domain.handlers.presubmit; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCase; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.StoredNotification; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.iacaseapi.domain.handlers.PreSubmitCallbackHandler; +import uk.gov.hmcts.reform.iacaseapi.domain.service.Appender; +import uk.gov.service.notify.Notification; +import uk.gov.service.notify.NotificationClient; +import uk.gov.service.notify.NotificationClientException; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +import static java.util.Collections.emptyList; +import static java.util.Objects.requireNonNull; +import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.NOTIFICATIONS; +import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.NOTIFICATIONS_SENT; + +@Slf4j +@Component +public class SaveNotificationsToDataHandler implements PreSubmitCallbackHandler { + + private final NotificationClient notificationClient; + private final Appender notificationAppender; + + + public SaveNotificationsToDataHandler( + NotificationClient notificationClient, + Appender notificationAppender + ) { + this.notificationClient = notificationClient; + this.notificationAppender = notificationAppender; + } + + public boolean canHandle( + PreSubmitCallbackStage callbackStage, + Callback callback + ) { + requireNonNull(callbackStage, "callbackStage must not be null"); + requireNonNull(callback, "callback must not be null"); + + return callbackStage == PreSubmitCallbackStage.ABOUT_TO_SUBMIT + && callback.getEvent() == Event.SAVE_NOTIFICATIONS_TO_DATA; + } + + public PreSubmitCallbackResponse handle( + PreSubmitCallbackStage callbackStage, + Callback callback + ) { + if (!canHandle(callbackStage, callback)) { + throw new IllegalStateException("Cannot handle callback"); + } + + AsylumCase asylumCase = + callback + .getCaseDetails() + .getCaseData(); + + Optional>> maybeExistingNotifications = + asylumCase.read(NOTIFICATIONS); + + Optional>> notificationsSent = + asylumCase.read(NOTIFICATIONS_SENT); + + List> allNotifications = maybeExistingNotifications.orElse(emptyList()); + List notificationIds = getUnstoredNotificationIds(allNotifications, notificationsSent.orElse(emptyList())); + if (!notificationIds.isEmpty()) { + for (String notificationId : notificationIds) { + try { + Notification notification = notificationClient.getNotificationById(notificationId); + StoredNotification storedNotification = + getStoredNotification(notificationId, notification); + allNotifications = notificationAppender.append(storedNotification, allNotifications); + } catch (NotificationClientException exception) { + log.warn("Notification client error on case " + + callback.getCaseDetails().getId() + ": ", exception); + } + } + allNotifications = sortNotificationsByDate(allNotifications); + asylumCase.write(NOTIFICATIONS, allNotifications); + } + + return new PreSubmitCallbackResponse<>(asylumCase); + } + + private static StoredNotification getStoredNotification(String notificationId, Notification notification) { + String reference = notification.getReference().orElse(notificationId); + String notificationBody = "
" + notification.getBody() + .replace("\r\n", "
") + .replace("’", "'") + .replace("‘", "'") + + "
"; + + String method = notification.getNotificationType(); + String sentTo = switch (method) { + case "email" -> notification.getEmailAddress().orElse("N/A"); + case "sms" -> notification.getPhoneNumber().orElse("N/A"); + default -> "N/A"; + }; + String status = notification.getStatus(); + List failedStatus = List.of("permanent-failure", "temporary-failure", "technical-failure"); + status = failedStatus.contains(status) ? "Failed" : StringUtils.capitalize(status); + ZonedDateTime zonedSentAt = notification.getSentAt().orElse(ZonedDateTime.now()) + .withZoneSameInstant(ZoneId.of("Europe/London")); + String sentAt = zonedSentAt.toLocalDateTime().toString(); + String subject = notification.getSubject().orElse("N/A"); + return StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent(sentAt) + .notificationSentTo(sentTo) + .notificationBody(notificationBody) + .notificationMethod(StringUtils.capitalize(method)) + .notificationStatus(status) + .notificationReference(reference) + .notificationSubject(subject) + .build(); + } + + private List getUnstoredNotificationIds(List> storedNotifications, + List> sentNotificationIds) { + List storedNotificationIds = storedNotifications.stream() + .map(idValue -> idValue.getValue().getNotificationId()) + .toList(); + return sentNotificationIds.stream() + .filter(idValue -> !storedNotificationIds.contains(idValue.getValue())) + .map(IdValue::getValue) + .toList(); + } + + private List> sortNotificationsByDate(List> allNotifications) { + List> mutableNotifications = new ArrayList<>(allNotifications); + mutableNotifications.sort(Comparator.comparing(notification -> + LocalDateTime.parse(notification.getValue().getNotificationDateSent()), + Comparator.reverseOrder() + )); + return mutableNotifications; + } + +} diff --git a/src/main/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSender.java b/src/main/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSender.java index f91fac7ae6..0d08a2352c 100644 --- a/src/main/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSender.java +++ b/src/main/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSender.java @@ -2,34 +2,69 @@ import static java.util.Objects.requireNonNull; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import uk.gov.hmcts.reform.iacaseapi.domain.DateProvider; import uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCase; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event; import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.Callback; import uk.gov.hmcts.reform.iacaseapi.domain.service.NotificationSender; +import uk.gov.hmcts.reform.iacaseapi.domain.service.Scheduler; +import uk.gov.hmcts.reform.iacaseapi.infrastructure.clients.model.TimedEvent; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +@Slf4j @Service public class AsylumCaseNotificationApiSender implements NotificationSender { private final AsylumCaseCallbackApiDelegator asylumCaseCallbackApiDelegator; private final String notificationsApiEndpoint; private final String aboutToSubmitPath; + private final boolean timedEventServiceEnabled; + private final DateProvider dateProvider; + private final Scheduler scheduler; public AsylumCaseNotificationApiSender( AsylumCaseCallbackApiDelegator asylumCaseCallbackApiDelegator, @Value("${notificationsApi.endpoint}") String notificationsApiEndpoint, - @Value("${notificationsApi.aboutToSubmitPath}") String aboutToSubmitPath + @Value("${notificationsApi.aboutToSubmitPath}") String aboutToSubmitPath, + @Value("${featureFlag.timedEventServiceEnabled}") boolean timedEventServiceEnabled, + DateProvider dateProvider, + Scheduler scheduler ) { this.asylumCaseCallbackApiDelegator = asylumCaseCallbackApiDelegator; this.notificationsApiEndpoint = notificationsApiEndpoint; this.aboutToSubmitPath = aboutToSubmitPath; + this.timedEventServiceEnabled = timedEventServiceEnabled; + this.dateProvider = dateProvider; + this.scheduler = scheduler; } public AsylumCase send( Callback callback ) { requireNonNull(callback, "callback must not be null"); - + if (timedEventServiceEnabled) { + ZonedDateTime scheduledTime = ZonedDateTime.of(dateProvider.nowWithTime(), ZoneId.systemDefault()) + .plusSeconds(15); + try { + scheduler.schedule( + new TimedEvent( + "", + Event.SAVE_NOTIFICATIONS_TO_DATA, + scheduledTime, + "IA", + "Asylum", + callback.getCaseDetails().getId() + ) + ); + } catch (AsylumCaseServiceResponseException e) { + log.error("Scheduling SAVE_NOTIFICATIONS_TO_DATA event failed: ", e); + } + } return asylumCaseCallbackApiDelegator.delegate( callback, notificationsApiEndpoint + aboutToSubmitPath diff --git a/src/main/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/config/GovNotifyConfiguration.java b/src/main/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/config/GovNotifyConfiguration.java new file mode 100644 index 0000000000..3069bddf7a --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/config/GovNotifyConfiguration.java @@ -0,0 +1,36 @@ +package uk.gov.hmcts.reform.iacaseapi.infrastructure.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import uk.gov.service.notify.NotificationClient; + +import static java.util.Objects.requireNonNull; + +@Slf4j +@Configuration +public class GovNotifyConfiguration { + + @Bean + @Primary + public NotificationClient notificationClient( + @Value("${govnotify.key}") String key, + @Value("${govnotify.baseUrl}") String govNotifyBaseUrl + ) { + requireNonNull(key); + + return new NotificationClient(key, govNotifyBaseUrl); + } + + @Bean("BailClient") + public NotificationClient notificationBailClient( + @Value("${govnotify.bail.key}") String key, + @Value("${govnotify.baseUrl}") String govNotifyBaseUrl + ) { + requireNonNull(key); + + return new NotificationClient(key, govNotifyBaseUrl); + } +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index ce68ffed09..d892b277cd 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -396,6 +396,7 @@ security: - "generateServiceRequest" - "recordRemissionReminder" - "markAppealAsRemitted" + - "saveNotificationsToData" - "refundConfirmation" - "progressMigratedCase" caseworker-ia-homeofficeapc: @@ -500,6 +501,7 @@ security: - "recordAdjournmentDetails" - "triggerCmrListed" - "decisionWithoutHearingListed" + - "saveNotificationsToData" - "reTriggerWaTasks" - "reTriggerWaBulkTasks" - "recordRemissionReminder" @@ -572,3 +574,9 @@ govUkHolidays: url: https://www.gov.uk/ caseIdListJsonLocation: caseIdForRetrigger.json + +govnotify: + baseUrl: "https://api.notifications.service.gov.uk" + key: ${IA_GOV_NOTIFY_KEY:gov-key} + bail: + key: ${IA_BAIL_GOV_NOTIFY_KEY:gov-bail-key} diff --git a/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/StoredNotificationTest.java b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/StoredNotificationTest.java new file mode 100644 index 0000000000..924b2a1f29 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/StoredNotificationTest.java @@ -0,0 +1,67 @@ +package uk.gov.hmcts.reform.iacaseapi.domain.entities; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.Document; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.mock; + +class StoredNotificationTest { + + private final String notificationId = "someId"; + private final String notificationDateSent = "someDateSent"; + private final String notificationSentTo = "someSentTo"; + private final String notificationMethod = "someMethod"; + private final String notificationStatus = "someStatus"; + private final String notificationBody = "someBody"; + private final String notificationReference = "someReference"; + private final String notificationSubject = "someSubject"; + private final Document document = mock(Document.class); + + private StoredNotification storedNotification; + + @BeforeEach + public void setUp() { + storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent(notificationDateSent) + .notificationSentTo(notificationSentTo) + .notificationBody(notificationBody) + .notificationMethod(notificationMethod) + .notificationStatus(notificationStatus) + .notificationReference(notificationReference) + .notificationSubject(notificationSubject) + .build(); + } + + @Test + void should_hold_onto_values() { + assertThat(storedNotification.getNotificationId()).isEqualTo(notificationId); + assertThat(storedNotification.getNotificationMethod()).isEqualTo(notificationMethod); + assertThat(storedNotification.getNotificationSentTo()).isEqualTo(notificationSentTo); + assertThat(storedNotification.getNotificationStatus()).isEqualTo(notificationStatus); + assertThat(storedNotification.getNotificationBody()).isEqualTo(notificationBody); + assertThat(storedNotification.getNotificationDateSent()).isEqualTo(notificationDateSent); + assertThat(storedNotification.getNotificationReference()).isEqualTo(notificationReference); + assertThat(storedNotification.getNotificationSubject()).isEqualTo(notificationSubject); + assertThat(storedNotification.getNotificationDocument()).isNull(); + storedNotification.setNotificationDocument(document); + assertThat(storedNotification.getNotificationDocument()).isEqualTo(document); + } + + @Test + void should_not_allow_null_arguments_other_than_document() { + + StoredNotification.StoredNotificationBuilder builder = StoredNotification.builder(); + assertThatThrownBy(() -> builder.notificationId(null)).isExactlyInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> builder.notificationDateSent(null)).isExactlyInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> builder.notificationSentTo(null)).isExactlyInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> builder.notificationBody(null)).isExactlyInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> builder.notificationMethod(null)).isExactlyInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> builder.notificationStatus(null)).isExactlyInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> builder.notificationReference(null)).isExactlyInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> builder.notificationSubject(null)).isExactlyInstanceOf(NullPointerException.class); + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/EventTest.java b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/EventTest.java index e64b6f58b9..b4c20e6e77 100644 --- a/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/EventTest.java +++ b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/entities/ccd/EventTest.java @@ -149,6 +149,7 @@ void has_correct_values() { assertEquals("reTriggerWaTasks", Event.RE_TRIGGER_WA_TASKS.toString()); assertEquals("recordRemissionReminder", Event.RECORD_REMISSION_REMINDER.toString()); assertEquals("markAppealAsRemitted", Event.MARK_APPEAL_AS_REMITTED.toString()); + assertEquals("saveNotificationsToData", Event.SAVE_NOTIFICATIONS_TO_DATA.toString()); assertEquals("sendPaymentReminderNotification", Event.SEND_PAYMENT_REMINDER_NOTIFICATION.toString()); assertEquals("ariaCreateCase", Event.ARIA_CREATE_CASE.toString()); assertEquals("progressMigratedCase", Event.PROGRESS_MIGRATED_CASE.toString()); @@ -157,6 +158,6 @@ void has_correct_values() { @Test void if_this_test_fails_it_is_because_it_needs_updating_with_your_changes() { - assertEquals(149, Event.values().length); + assertEquals(150, Event.values().length); } } diff --git a/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandlerTest.java b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandlerTest.java index 8b97e977fa..8fcb6baf50 100644 --- a/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandlerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/GenerateDocumentHandlerTest.java @@ -1,5 +1,43 @@ package uk.gov.hmcts.reform.iacaseapi.domain.handlers.presubmit; +import com.google.common.collect.ImmutableSet; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import uk.gov.hmcts.reform.iacaseapi.domain.DateProvider; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.AppealDecision; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.Application; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ApplicationType; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCase; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.HearingCentre; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.CaseDetails; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.State; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.DispatchPriority; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.YesOrNo; +import uk.gov.hmcts.reform.iacaseapi.domain.service.DocumentGenerator; +import uk.gov.hmcts.reform.iacaseapi.domain.service.DueDateService; + +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.immutableEnumSet; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -29,101 +67,12 @@ import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.LIST_CASE_HEARING_CENTRE; import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.LIST_CASE_HEARING_DATE; import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.RELIST_CASE_IMMEDIATELY; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.UPDATED_APPEAL_DECISION; import static uk.gov.hmcts.reform.iacaseapi.domain.entities.HearingCentre.GLASGOW; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.ADA_SUITABILITY_REVIEW; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.ADJOURN_HEARING_WITHOUT_DATE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.APPLY_FOR_FTPA_APPELLANT; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.APPLY_FOR_FTPA_RESPONDENT; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.ASYNC_STITCHING_COMPLETE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.CHANGE_DIRECTION_DUE_DATE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.CHANGE_HEARING_CENTRE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.CREATE_CASE_LINK; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.CUSTOMISE_HEARING_BUNDLE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.DECIDE_AN_APPLICATION; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.DRAFT_HEARING_REQUIREMENTS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.EDIT_APPEAL_AFTER_SUBMIT; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.EDIT_CASE_LISTING; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.END_APPEAL; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.END_APPEAL_AUTOMATICALLY; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.GENERATE_DECISION_AND_REASONS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.GENERATE_HEARING_BUNDLE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.GENERATE_UPPER_TRIBUNAL_BUNDLE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.LIST_CASE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.LIST_CMA; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.MAINTAIN_CASE_LINKS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.MANAGE_FEE_UPDATE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.MARK_APPEAL_AS_ADA; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.MARK_APPEAL_PAID; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.RECORD_ADJOURNMENT_DETAILS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.RECORD_OUT_OF_TIME_DECISION; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.RECORD_REMISSION_DECISION; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REINSTATE_APPEAL; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REMOVE_DETAINED_STATUS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REQUEST_CASE_BUILDING; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REQUEST_HEARING_REQUIREMENTS_FEATURE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REQUEST_RESPONDENT_EVIDENCE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REQUEST_RESPONDENT_REVIEW; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REQUEST_RESPONSE_AMEND; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.REQUEST_RESPONSE_REVIEW; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.RESIDENT_JUDGE_FTPA_DECISION; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SEND_DECISION_AND_REASONS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SEND_DIRECTION; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SUBMIT_APPEAL; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SUBMIT_CASE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SUBMIT_CLARIFYING_QUESTION_ANSWERS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SUBMIT_CMA_REQUIREMENTS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SUBMIT_REASONS_FOR_APPEAL; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.TRANSFER_OUT_OF_ADA; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPDATE_HEARING_ADJUSTMENTS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPDATE_HEARING_REQUIREMENTS; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPDATE_TRIBUNAL_DECISION; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPLOAD_ADDENDUM_EVIDENCE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPLOAD_ADDENDUM_EVIDENCE_ADMIN_OFFICER; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPLOAD_ADDENDUM_EVIDENCE_HOME_OFFICE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPLOAD_ADDITIONAL_EVIDENCE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPLOAD_ADDITIONAL_EVIDENCE_HOME_OFFICE; -import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.UPLOAD_HOME_OFFICE_APPEAL_RESPONSE; +import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.*; import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.YesOrNo.NO; +import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.*; import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.YesOrNo.YES; -import java.time.LocalDate; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import com.google.common.collect.ImmutableSet; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; -import uk.gov.hmcts.reform.iacaseapi.domain.DateProvider; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.AppealDecision; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.Application; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ApplicationType; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCase; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.HearingCentre; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.CaseDetails; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.State; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.Callback; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.DispatchPriority; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.IdValue; -import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.YesOrNo; -import uk.gov.hmcts.reform.iacaseapi.domain.service.DocumentGenerator; -import uk.gov.hmcts.reform.iacaseapi.domain.service.DueDateService; - @MockitoSettings(strictness = Strictness.LENIENT) @ExtendWith(MockitoExtension.class) @SuppressWarnings("unchecked") @@ -190,7 +139,7 @@ public void setUp() { true, documentGenerator, dateProvider, - true, + true, dueDateService, FTPA_DUE_IN_DAYS_UK, FTPA_DUE_IN_DAYS_OOC, @@ -207,94 +156,87 @@ void setUpSendDecisionsAndReasonsData(AsylumCase asylumCase) { when(caseDetails.getCaseData()).thenReturn(asylumCase); when(asylumCase.read(IS_DECISION_ALLOWED, AppealDecision.class)) - .thenReturn(Optional.of(AppealDecision.ALLOWED)); + .thenReturn(Optional.of(AppealDecision.ALLOWED)); when(asylumCase.read(IS_ACCELERATED_DETAINED_APPEAL, YesOrNo.class)) - .thenReturn(Optional.of(YesOrNo.NO)); + .thenReturn(Optional.of(YesOrNo.NO)); when(asylumCase.read(APPEAL_OUT_OF_COUNTRY, YesOrNo.class)) - .thenReturn(Optional.empty()); + .thenReturn(Optional.empty()); when(dateProvider.now()).thenReturn(FAKE_APPEAL_DATE); } - @Test - void should_generate_document_and_update_the_case() { - - Arrays.asList( - SUBMIT_APPEAL, - SUBMIT_CASE, - LIST_CASE, - EDIT_CASE_LISTING, - GENERATE_DECISION_AND_REASONS, - GENERATE_HEARING_BUNDLE, - CUSTOMISE_HEARING_BUNDLE, - SEND_DECISION_AND_REASONS, - ADJOURN_HEARING_WITHOUT_DATE, - END_APPEAL, - SUBMIT_CMA_REQUIREMENTS, - LIST_CMA, - END_APPEAL, - END_APPEAL_AUTOMATICALLY, - EDIT_APPEAL_AFTER_SUBMIT, - GENERATE_UPPER_TRIBUNAL_BUNDLE, - SUBMIT_REASONS_FOR_APPEAL, - SUBMIT_CLARIFYING_QUESTION_ANSWERS, - RECORD_ADJOURNMENT_DETAILS, - REQUEST_CASE_BUILDING, - ASYNC_STITCHING_COMPLETE, - UPDATE_TRIBUNAL_DECISION - ).forEach(event -> { + @ParameterizedTest + @EnumSource(value = Event.class, names = { + "SUBMIT_APPEAL", + "SUBMIT_CASE", + "LIST_CASE", + "EDIT_CASE_LISTING", + "GENERATE_DECISION_AND_REASONS", + "GENERATE_HEARING_BUNDLE", + "CUSTOMISE_HEARING_BUNDLE", + "SEND_DECISION_AND_REASONS", + "ADJOURN_HEARING_WITHOUT_DATE", + "END_APPEAL", + "SUBMIT_CMA_REQUIREMENTS", + "LIST_CMA", + "END_APPEAL_AUTOMATICALLY", + "EDIT_APPEAL_AFTER_SUBMIT", + "GENERATE_UPPER_TRIBUNAL_BUNDLE", + "SUBMIT_REASONS_FOR_APPEAL", + "SUBMIT_CLARIFYING_QUESTION_ANSWERS", + "RECORD_ADJOURNMENT_DETAILS", + "REQUEST_CASE_BUILDING", + "ASYNC_STITCHING_COMPLETE", + "UPDATE_TRIBUNAL_DECISION", + "SAVE_NOTIFICATIONS_TO_DATA" + }) + void should_generate_document_and_update_the_case(Event event) { + AsylumCase expectedUpdatedCase = mock(AsylumCase.class); - AsylumCase expectedUpdatedCase = mock(AsylumCase.class); + when(callback.getEvent()).thenReturn(event); + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(NO)); - when(callback.getEvent()).thenReturn(event); + if (event.equals(EDIT_CASE_LISTING)) { when(callback.getCaseDetails()).thenReturn(caseDetails); when(caseDetails.getCaseData()).thenReturn(asylumCase); - when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(NO)); - - if (event.equals(EDIT_CASE_LISTING)) { - when(callback.getCaseDetails()).thenReturn(caseDetails); - when(caseDetails.getCaseData()).thenReturn(asylumCase); - when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.empty()); - when(caseDetails.getState()).thenReturn(state); - when(expectedUpdatedCase.read(APPLICATION_EDIT_LISTING_EXISTS, String.class)) + when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.empty()); + when(caseDetails.getState()).thenReturn(state); + when(expectedUpdatedCase.read(APPLICATION_EDIT_LISTING_EXISTS, String.class)) .thenReturn(Optional.of("Yes")); - when(expectedUpdatedCase.read(APPLICATIONS)).thenReturn(Optional.of(applications)); - } + when(expectedUpdatedCase.read(APPLICATIONS)).thenReturn(Optional.of(applications)); + } - if (event.equals(SEND_DECISION_AND_REASONS)) { - when(expectedUpdatedCase.read(IS_DECISION_ALLOWED, AppealDecision.class)) + if (event.equals(SEND_DECISION_AND_REASONS)) { + when(expectedUpdatedCase.read(IS_DECISION_ALLOWED, AppealDecision.class)) .thenReturn(Optional.of(AppealDecision.ALLOWED)); - when(dateProvider.now()).thenReturn(FAKE_APPEAL_DATE); - } + when(dateProvider.now()).thenReturn(FAKE_APPEAL_DATE); + } - when(documentGenerator.generate(callback)).thenReturn(expectedUpdatedCase); + when(documentGenerator.generate(callback)).thenReturn(expectedUpdatedCase); - PreSubmitCallbackResponse callbackResponse = + PreSubmitCallbackResponse callbackResponse = generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); - assertNotNull(callbackResponse); - assertEquals(expectedUpdatedCase, callbackResponse.getData()); - - verify(documentGenerator, times(1)).generate(callback); + assertNotNull(callbackResponse); + assertEquals(expectedUpdatedCase, callbackResponse.getData()); - if (event.equals(EDIT_CASE_LISTING)) { - verify(expectedUpdatedCase).clear(DISABLE_OVERVIEW_PAGE); - verify(expectedUpdatedCase).clear(APPLICATION_EDIT_LISTING_EXISTS); - verify(expectedUpdatedCase).write(CURRENT_CASE_STATE_VISIBLE_TO_CASE_OFFICER, state); - verify(expectedUpdatedCase).write(eq(APPLICATIONS), applicationsCaptor.capture()); - assertEquals("Completed", applicationsCaptor.getValue().get(0).getValue().getApplicationStatus()); - } + verify(documentGenerator, times(1)).generate(callback); - if (event.equals(SEND_DECISION_AND_REASONS)) { - verify(expectedUpdatedCase).write(APPEAL_DECISION, "Allowed"); - verify(expectedUpdatedCase).write(APPEAL_DATE, FAKE_APPEAL_DATE.toString()); - verify(expectedUpdatedCase).write(FTPA_APPLICATION_DEADLINE,EXPECTED_FTPA_DEADLINE_UK.toString()); - verify(expectedUpdatedCase).clear(UPDATED_APPEAL_DECISION); - } + if (event.equals(EDIT_CASE_LISTING)) { + verify(expectedUpdatedCase).clear(DISABLE_OVERVIEW_PAGE); + verify(expectedUpdatedCase).clear(APPLICATION_EDIT_LISTING_EXISTS); + verify(expectedUpdatedCase).write(CURRENT_CASE_STATE_VISIBLE_TO_CASE_OFFICER, state); + verify(expectedUpdatedCase).write(eq(APPLICATIONS), applicationsCaptor.capture()); + assertEquals("Completed", applicationsCaptor.getValue().get(0).getValue().getApplicationStatus()); + } - reset(callback); - reset(documentGenerator); - }); + if (event.equals(SEND_DECISION_AND_REASONS)) { + verify(expectedUpdatedCase).write(APPEAL_DECISION, "Allowed"); + verify(expectedUpdatedCase).write(APPEAL_DATE, FAKE_APPEAL_DATE.toString()); + verify(expectedUpdatedCase).write(FTPA_APPLICATION_DEADLINE, EXPECTED_FTPA_DEADLINE_UK.toString()); + } } @Test @@ -369,125 +311,114 @@ void handling_should_throw_if_cannot_actually_handle() { .isExactlyInstanceOf(IllegalStateException.class); } - @Test - void it_can_handle_callback() { + @ParameterizedTest + @EnumSource(value = Event.class) + void it_can_handle_callback(Event event) { + when(callback.getEvent()).thenReturn(event); + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(YES)); - for (Event event : Event.values()) { + for (PreSubmitCallbackStage callbackStage : PreSubmitCallbackStage.values()) { - when(callback.getEvent()).thenReturn(event); - when(callback.getCaseDetails()).thenReturn(caseDetails); - when(caseDetails.getCaseData()).thenReturn(asylumCase); - when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(YES)); - - for (PreSubmitCallbackStage callbackStage : PreSubmitCallbackStage.values()) { - - boolean canHandle = generateDocumentHandler.canHandle(callbackStage, callback); - - if (callbackStage == PreSubmitCallbackStage.ABOUT_TO_SUBMIT - && - Arrays.asList( - SUBMIT_APPEAL, - SUBMIT_CASE, - DRAFT_HEARING_REQUIREMENTS, - UPDATE_HEARING_REQUIREMENTS, - UPDATE_HEARING_ADJUSTMENTS, - ADA_SUITABILITY_REVIEW, - LIST_CASE, - EDIT_CASE_LISTING, - GENERATE_DECISION_AND_REASONS, - GENERATE_HEARING_BUNDLE, - CUSTOMISE_HEARING_BUNDLE, - SEND_DECISION_AND_REASONS, - ADJOURN_HEARING_WITHOUT_DATE, - END_APPEAL, - SUBMIT_CMA_REQUIREMENTS, - LIST_CMA, - END_APPEAL, - END_APPEAL_AUTOMATICALLY, - EDIT_APPEAL_AFTER_SUBMIT, - GENERATE_UPPER_TRIBUNAL_BUNDLE, - SUBMIT_REASONS_FOR_APPEAL, - SUBMIT_CLARIFYING_QUESTION_ANSWERS, - REQUEST_CASE_BUILDING, - REQUEST_RESPONDENT_REVIEW, - UPLOAD_HOME_OFFICE_APPEAL_RESPONSE, - ASYNC_STITCHING_COMPLETE, - RECORD_OUT_OF_TIME_DECISION, - REQUEST_RESPONDENT_EVIDENCE, - RECORD_REMISSION_DECISION, - MARK_APPEAL_PAID, - REQUEST_RESPONSE_REVIEW, - REQUEST_HEARING_REQUIREMENTS_FEATURE, - MARK_APPEAL_AS_ADA, - DECIDE_AN_APPLICATION, - APPLY_FOR_FTPA_RESPONDENT, - TRANSFER_OUT_OF_ADA, - RESIDENT_JUDGE_FTPA_DECISION, - APPLY_FOR_FTPA_APPELLANT, - MAINTAIN_CASE_LINKS, - UPLOAD_ADDENDUM_EVIDENCE_ADMIN_OFFICER, - UPLOAD_ADDITIONAL_EVIDENCE, - CHANGE_HEARING_CENTRE, - CREATE_CASE_LINK, - REQUEST_RESPONSE_AMEND, - SEND_DIRECTION, - EDIT_APPEAL_AFTER_SUBMIT, - CHANGE_HEARING_CENTRE, - CHANGE_DIRECTION_DUE_DATE, - UPLOAD_ADDITIONAL_EVIDENCE_HOME_OFFICE, - UPLOAD_ADDENDUM_EVIDENCE_HOME_OFFICE, - UPLOAD_ADDENDUM_EVIDENCE, - CHANGE_DIRECTION_DUE_DATE, - EDIT_APPEAL_AFTER_SUBMIT, - REINSTATE_APPEAL, - SUBMIT_CLARIFYING_QUESTION_ANSWERS, - UPDATE_TRIBUNAL_DECISION, - MANAGE_FEE_UPDATE - ).contains(event)) { - - assertTrue(canHandle); - } else { - assertFalse(canHandle, "failed callback: " + callbackStage + ", failed event " + event); - } + boolean canHandle = generateDocumentHandler.canHandle(callbackStage, callback); + + if (callbackStage == PreSubmitCallbackStage.ABOUT_TO_SUBMIT + && + Arrays.asList( + SUBMIT_APPEAL, + SUBMIT_CASE, + DRAFT_HEARING_REQUIREMENTS, + UPDATE_HEARING_REQUIREMENTS, + UPDATE_HEARING_ADJUSTMENTS, + ADA_SUITABILITY_REVIEW, + LIST_CASE, + EDIT_CASE_LISTING, + GENERATE_DECISION_AND_REASONS, + GENERATE_HEARING_BUNDLE, + CUSTOMISE_HEARING_BUNDLE, + SEND_DECISION_AND_REASONS, + ADJOURN_HEARING_WITHOUT_DATE, + END_APPEAL, + SUBMIT_CMA_REQUIREMENTS, + LIST_CMA, + END_APPEAL, + END_APPEAL_AUTOMATICALLY, + EDIT_APPEAL_AFTER_SUBMIT, + GENERATE_UPPER_TRIBUNAL_BUNDLE, + SUBMIT_REASONS_FOR_APPEAL, + SUBMIT_CLARIFYING_QUESTION_ANSWERS, + REQUEST_CASE_BUILDING, + REQUEST_RESPONDENT_REVIEW, + UPLOAD_HOME_OFFICE_APPEAL_RESPONSE, + ASYNC_STITCHING_COMPLETE, + RECORD_OUT_OF_TIME_DECISION, + REQUEST_RESPONDENT_EVIDENCE, + RECORD_REMISSION_DECISION, + MARK_APPEAL_PAID, + REQUEST_RESPONSE_REVIEW, + REQUEST_HEARING_REQUIREMENTS_FEATURE, + MARK_APPEAL_AS_ADA, + DECIDE_AN_APPLICATION, + APPLY_FOR_FTPA_RESPONDENT, + TRANSFER_OUT_OF_ADA, + RESIDENT_JUDGE_FTPA_DECISION, + APPLY_FOR_FTPA_APPELLANT, + MAINTAIN_CASE_LINKS, + UPLOAD_ADDENDUM_EVIDENCE_ADMIN_OFFICER, + UPLOAD_ADDITIONAL_EVIDENCE, + CHANGE_HEARING_CENTRE, + CREATE_CASE_LINK, + REQUEST_RESPONSE_AMEND, + SEND_DIRECTION, + EDIT_APPEAL_AFTER_SUBMIT, + CHANGE_HEARING_CENTRE, + CHANGE_DIRECTION_DUE_DATE, + UPLOAD_ADDITIONAL_EVIDENCE_HOME_OFFICE, + UPLOAD_ADDENDUM_EVIDENCE_HOME_OFFICE, + UPLOAD_ADDENDUM_EVIDENCE, + CHANGE_DIRECTION_DUE_DATE, + EDIT_APPEAL_AFTER_SUBMIT, + REINSTATE_APPEAL, + SUBMIT_CLARIFYING_QUESTION_ANSWERS, + UPDATE_TRIBUNAL_DECISION, + SAVE_NOTIFICATIONS_TO_DATA, + MANAGE_FEE_UPDATE + ).contains(event)) { + + assertTrue(canHandle); + } else { + assertFalse(canHandle, "failed callback: " + callbackStage + ", failed event " + event); } - - reset(callback); } } - @Test - void it_cannot_handle_callback_if_docmosis_not_enabled() { + @ParameterizedTest + @EnumSource(value = Event.class) + void it_cannot_handle_callback_if_docmosis_not_enabled(Event event) { generateDocumentHandler = new GenerateDocumentHandler( - false, - true, - documentGenerator, - dateProvider, - true, - dueDateService, - FTPA_DUE_IN_DAYS_UK, - FTPA_DUE_IN_DAYS_OOC, - FTPA_DUE_IN_WORKING_DAYS_ADA, - FTPA_DUE_IN_WORKING_DAYS_ADA_INTERNAL, - FTPA_DUE_IN_DAYS_NON_ADA_INTERNAL + false, + true, + documentGenerator, + dateProvider, + true, + dueDateService, + FTPA_DUE_IN_DAYS_UK, + FTPA_DUE_IN_DAYS_OOC, + FTPA_DUE_IN_WORKING_DAYS_ADA, + FTPA_DUE_IN_WORKING_DAYS_ADA_INTERNAL, + FTPA_DUE_IN_DAYS_NON_ADA_INTERNAL ); + when(callback.getEvent()).thenReturn(event); + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(YES)); - for (Event event : Event.values()) { - - when(callback.getEvent()).thenReturn(event); - when(callback.getCaseDetails()).thenReturn(caseDetails); - when(caseDetails.getCaseData()).thenReturn(asylumCase); - when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(YES)); - - for (PreSubmitCallbackStage callbackStage : PreSubmitCallbackStage.values()) { - - boolean canHandle = generateDocumentHandler.canHandle(callbackStage, callback); - - assertFalse(canHandle); - } - - reset(callback); + for (PreSubmitCallbackStage callbackStage : PreSubmitCallbackStage.values()) { + boolean canHandle = generateDocumentHandler.canHandle(callbackStage, callback); + assertFalse(canHandle); } } @@ -518,8 +449,9 @@ void it_cannot_handle_if_edit_case_listing_for_remote_to_remote_hearing_channel_ } } - @Test - void it_cannot_handle_generate_if_em_stitching_not_enabled() { + @ParameterizedTest + @EnumSource(value = Event.class) + void it_cannot_handle_generate_if_em_stitching_not_enabled(Event event) { generateDocumentHandler = new GenerateDocumentHandler( @@ -536,90 +468,84 @@ void it_cannot_handle_generate_if_em_stitching_not_enabled() { FTPA_DUE_IN_DAYS_NON_ADA_INTERNAL ); - for (Event event : Event.values()) { + when(callback.getEvent()).thenReturn(event); + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(YES)); - when(callback.getEvent()).thenReturn(event); - when(callback.getCaseDetails()).thenReturn(caseDetails); - when(caseDetails.getCaseData()).thenReturn(asylumCase); - when(asylumCase.read(RELIST_CASE_IMMEDIATELY, YesOrNo.class)).thenReturn(Optional.of(YES)); - - for (PreSubmitCallbackStage callbackStage : PreSubmitCallbackStage.values()) { - - boolean canHandle = generateDocumentHandler.canHandle(callbackStage, callback); - - ImmutableSet eventsThatDontRequireStitching = - immutableEnumSet( - SUBMIT_APPEAL, - DRAFT_HEARING_REQUIREMENTS, - UPDATE_HEARING_REQUIREMENTS, - UPDATE_HEARING_ADJUSTMENTS, - ADA_SUITABILITY_REVIEW, - LIST_CASE, - GENERATE_DECISION_AND_REASONS, - GENERATE_HEARING_BUNDLE, - CUSTOMISE_HEARING_BUNDLE, - EDIT_CASE_LISTING, - SEND_DECISION_AND_REASONS, - ADJOURN_HEARING_WITHOUT_DATE, - END_APPEAL, - SUBMIT_CMA_REQUIREMENTS, - LIST_CMA, - END_APPEAL, - END_APPEAL_AUTOMATICALLY, - EDIT_APPEAL_AFTER_SUBMIT, - GENERATE_UPPER_TRIBUNAL_BUNDLE, - SUBMIT_REASONS_FOR_APPEAL, - SUBMIT_CLARIFYING_QUESTION_ANSWERS, - REQUEST_CASE_BUILDING, - REQUEST_RESPONDENT_REVIEW, - UPLOAD_HOME_OFFICE_APPEAL_RESPONSE, - ASYNC_STITCHING_COMPLETE, - RECORD_OUT_OF_TIME_DECISION, - REQUEST_RESPONDENT_EVIDENCE, - RECORD_REMISSION_DECISION, - MARK_APPEAL_PAID, - REQUEST_RESPONSE_REVIEW, - REQUEST_HEARING_REQUIREMENTS_FEATURE, - MARK_APPEAL_AS_ADA, - DECIDE_AN_APPLICATION, - APPLY_FOR_FTPA_RESPONDENT, - TRANSFER_OUT_OF_ADA, - RESIDENT_JUDGE_FTPA_DECISION, - APPLY_FOR_FTPA_APPELLANT, - MAINTAIN_CASE_LINKS, - UPLOAD_ADDENDUM_EVIDENCE_ADMIN_OFFICER, - UPLOAD_ADDITIONAL_EVIDENCE, - CHANGE_HEARING_CENTRE, - CREATE_CASE_LINK, - REQUEST_RESPONSE_AMEND, - SEND_DIRECTION, - CHANGE_HEARING_CENTRE, - CHANGE_DIRECTION_DUE_DATE, - UPLOAD_ADDITIONAL_EVIDENCE_HOME_OFFICE, - UPLOAD_ADDENDUM_EVIDENCE_HOME_OFFICE, - UPLOAD_ADDENDUM_EVIDENCE, - CHANGE_DIRECTION_DUE_DATE, - REINSTATE_APPEAL, - SUBMIT_CLARIFYING_QUESTION_ANSWERS, - UPDATE_TRIBUNAL_DECISION, - MANAGE_FEE_UPDATE - ); - - if (callbackStage.equals(PreSubmitCallbackStage.ABOUT_TO_SUBMIT) - && (eventsThatDontRequireStitching.contains(event))) { - assertTrue(canHandle); - } else if (event.equals(GENERATE_HEARING_BUNDLE) - || event.equals(CUSTOMISE_HEARING_BUNDLE)) { - assertFalse(canHandle); - } else { - assertFalse(canHandle, "event: " + event + ", stage: " + callbackStage); - } + for (PreSubmitCallbackStage callbackStage : PreSubmitCallbackStage.values()) { + boolean canHandle = generateDocumentHandler.canHandle(callbackStage, callback); + + ImmutableSet eventsThatDontRequireStitching = + immutableEnumSet( + SUBMIT_APPEAL, + DRAFT_HEARING_REQUIREMENTS, + UPDATE_HEARING_REQUIREMENTS, + UPDATE_HEARING_ADJUSTMENTS, + ADA_SUITABILITY_REVIEW, + LIST_CASE, + GENERATE_DECISION_AND_REASONS, + GENERATE_HEARING_BUNDLE, + CUSTOMISE_HEARING_BUNDLE, + EDIT_CASE_LISTING, + SEND_DECISION_AND_REASONS, + ADJOURN_HEARING_WITHOUT_DATE, + END_APPEAL, + SUBMIT_CMA_REQUIREMENTS, + LIST_CMA, + END_APPEAL, + END_APPEAL_AUTOMATICALLY, + EDIT_APPEAL_AFTER_SUBMIT, + GENERATE_UPPER_TRIBUNAL_BUNDLE, + SUBMIT_REASONS_FOR_APPEAL, + SUBMIT_CLARIFYING_QUESTION_ANSWERS, + REQUEST_CASE_BUILDING, + REQUEST_RESPONDENT_REVIEW, + UPLOAD_HOME_OFFICE_APPEAL_RESPONSE, + ASYNC_STITCHING_COMPLETE, + RECORD_OUT_OF_TIME_DECISION, + REQUEST_RESPONDENT_EVIDENCE, + RECORD_REMISSION_DECISION, + MARK_APPEAL_PAID, + REQUEST_RESPONSE_REVIEW, + REQUEST_HEARING_REQUIREMENTS_FEATURE, + MARK_APPEAL_AS_ADA, + DECIDE_AN_APPLICATION, + APPLY_FOR_FTPA_RESPONDENT, + TRANSFER_OUT_OF_ADA, + RESIDENT_JUDGE_FTPA_DECISION, + APPLY_FOR_FTPA_APPELLANT, + MAINTAIN_CASE_LINKS, + UPLOAD_ADDENDUM_EVIDENCE_ADMIN_OFFICER, + UPLOAD_ADDITIONAL_EVIDENCE, + CHANGE_HEARING_CENTRE, + CREATE_CASE_LINK, + REQUEST_RESPONSE_AMEND, + SEND_DIRECTION, + CHANGE_HEARING_CENTRE, + CHANGE_DIRECTION_DUE_DATE, + UPLOAD_ADDITIONAL_EVIDENCE_HOME_OFFICE, + UPLOAD_ADDENDUM_EVIDENCE_HOME_OFFICE, + UPLOAD_ADDENDUM_EVIDENCE, + CHANGE_DIRECTION_DUE_DATE, + REINSTATE_APPEAL, + SUBMIT_CLARIFYING_QUESTION_ANSWERS, + UPDATE_TRIBUNAL_DECISION, + SAVE_NOTIFICATIONS_TO_DATA, + MANAGE_FEE_UPDATE + ); + + if (callbackStage.equals(PreSubmitCallbackStage.ABOUT_TO_SUBMIT) + && (eventsThatDontRequireStitching.contains(event))) { + assertTrue(canHandle); + } else if (event.equals(GENERATE_HEARING_BUNDLE) + || event.equals(CUSTOMISE_HEARING_BUNDLE)) { + assertFalse(canHandle); + } else { + assertFalse(canHandle, "event: " + event + ", stage: " + callbackStage); } - - reset(callback); } - } @Test @@ -648,16 +574,16 @@ void should_send_decision_and_reasons_and_populate_ftpa_field_ada_appeal() { setUpSendDecisionsAndReasonsData(expectedUpdatedCase); when(expectedUpdatedCase.read(IS_ACCELERATED_DETAINED_APPEAL, YesOrNo.class)) - .thenReturn(Optional.of(YesOrNo.YES)); + .thenReturn(Optional.of(YesOrNo.YES)); final ZonedDateTime fakeAppealDateTime = FAKE_APPEAL_DATE.atStartOfDay(ZoneOffset.UTC); when(dueDateService.calculateDueDate(fakeAppealDateTime, FTPA_DUE_IN_WORKING_DAYS_ADA)) - .thenReturn(ZonedDateTime.of(EXPECTED_FTPA_DEADLINE_ADA.atStartOfDay(), ZoneOffset.UTC)); + .thenReturn(ZonedDateTime.of(EXPECTED_FTPA_DEADLINE_ADA.atStartOfDay(), ZoneOffset.UTC)); when(documentGenerator.generate(callback)).thenReturn(expectedUpdatedCase); PreSubmitCallbackResponse callbackResponse = - generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); assertNotNull(callbackResponse); assertEquals(expectedUpdatedCase, callbackResponse.getData()); @@ -672,12 +598,12 @@ void should_send_decision_and_reasons_and_populate_ftpa_field_ooc_appeal() { setUpSendDecisionsAndReasonsData(expectedUpdatedCase); when(expectedUpdatedCase.read(APPEAL_OUT_OF_COUNTRY, YesOrNo.class)) - .thenReturn(Optional.of(YesOrNo.YES)); + .thenReturn(Optional.of(YesOrNo.YES)); when(documentGenerator.generate(callback)).thenReturn(expectedUpdatedCase); PreSubmitCallbackResponse callbackResponse = - generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); assertNotNull(callbackResponse); assertEquals(expectedUpdatedCase, callbackResponse.getData()); @@ -694,7 +620,7 @@ void should_send_decision_and_reasons_and_populate_ftpa_field_uk_appeal() { when(documentGenerator.generate(callback)).thenReturn(expectedUpdatedCase); PreSubmitCallbackResponse callbackResponse = - generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); assertNotNull(callbackResponse); assertEquals(expectedUpdatedCase, callbackResponse.getData()); @@ -710,17 +636,17 @@ void should_populate_ftpa_deadline_for_internal_case(YesOrNo yesOrNo) { setUpSendDecisionsAndReasonsData(expectedUpdatedCase); when(expectedUpdatedCase.read(IS_ACCELERATED_DETAINED_APPEAL, YesOrNo.class)) - .thenReturn(Optional.of(yesOrNo)); + .thenReturn(Optional.of(yesOrNo)); when(expectedUpdatedCase.read(IS_ADMIN, YesOrNo.class)).thenReturn(Optional.of(YesOrNo.YES)); final ZonedDateTime fakeAppealDateTime = FAKE_APPEAL_DATE.atStartOfDay(ZoneOffset.UTC); when(dueDateService.calculateDueDate(fakeAppealDateTime, FTPA_DUE_IN_WORKING_DAYS_ADA_INTERNAL)) - .thenReturn(ZonedDateTime.of(EXPECTED_FTPA_DEADLINE_ADA.atStartOfDay(), ZoneOffset.UTC)); + .thenReturn(ZonedDateTime.of(EXPECTED_FTPA_DEADLINE_ADA.atStartOfDay(), ZoneOffset.UTC)); when(documentGenerator.generate(callback)).thenReturn(expectedUpdatedCase); PreSubmitCallbackResponse callbackResponse = - generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + generateDocumentHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); assertNotNull(callbackResponse); assertEquals(expectedUpdatedCase, callbackResponse.getData()); diff --git a/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/SaveNotificationsToDataHandlerTest.java b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/SaveNotificationsToDataHandlerTest.java new file mode 100644 index 0000000000..281d212234 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/iacaseapi/domain/handlers/presubmit/SaveNotificationsToDataHandlerTest.java @@ -0,0 +1,383 @@ +package uk.gov.hmcts.reform.iacaseapi.domain.handlers.presubmit; + +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCase; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.StoredNotification; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.CaseDetails; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.iacaseapi.domain.service.Appender; +import uk.gov.service.notify.Notification; +import uk.gov.service.notify.NotificationClient; +import uk.gov.service.notify.NotificationClientException; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Optional; + +import static java.util.Collections.emptyList; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.NOTIFICATIONS; +import static uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCaseFieldDefinition.NOTIFICATIONS_SENT; +import static uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event.SAVE_NOTIFICATIONS_TO_DATA; + +@ExtendWith(MockitoExtension.class) +@SuppressWarnings("unchecked") +class SaveNotificationsToDataHandlerTest { + + @Mock + private NotificationClient notificationClient; + @Mock + private Appender storedNotificationAppender; + @Mock + private Notification notification; + @Mock + private Callback callback; + @Mock + private CaseDetails caseDetails; + @Mock + private AsylumCase asylumCase; + @Mock + private StoredNotification mockedStoredNotification; + @Mock + private StoredNotification mockedStoredNotification2; + + private final String reference = "someReference"; + private final String notificationId = "someNotificationId"; + private final String body = "someBody"; + private final String notificationTypeEmail = "email"; + private final String notificationTypeSms = "sms"; + private final String status = "someStatus"; + private final String email = "some-email@test.com"; + private final String phoneNumber = "07827000000"; + private final String subject = "someSubject"; + private SaveNotificationsToDataHandler saveNotificationsToDataHandler; + + @BeforeEach + void setUp() { + when(callback.getEvent()).thenReturn(SAVE_NOTIFICATIONS_TO_DATA); + saveNotificationsToDataHandler = new SaveNotificationsToDataHandler( + notificationClient, + storedNotificationAppender); + } + + @Test + void should_access_notify_client_if_missing_email_notification_and_should_sort_notification_list() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + List> notificationsSent = + List.of(new IdValue<>(reference, notificationId)); + List> storedNotifications = + List.of( + new IdValue<>("1", mockedStoredNotification), + new IdValue<>("2", mockedStoredNotification2) + ); + + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.of(storedNotifications)); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.of(notificationsSent)); + when(notificationClient.getNotificationById(notificationId)).thenReturn(notification); + when(notification.getBody()).thenReturn(body); + when(notification.getNotificationType()).thenReturn(notificationTypeEmail); + when(notification.getEmailAddress()).thenReturn(Optional.of(email)); + when(notification.getReference()).thenReturn(Optional.of(reference)); + when(notification.getSubject()).thenReturn(Optional.of(subject)); + String dateString = "01-01-2024 10:57"; + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Europe/London")); + when(notification.getSentAt()).thenReturn(Optional.of(zonedDateTime)); + when(notification.getStatus()).thenReturn(status); + when(mockedStoredNotification.getNotificationId()).thenReturn("1"); + when(mockedStoredNotification.getNotificationDateSent()).thenReturn("2024-01-01T00:00:00"); + when(mockedStoredNotification2.getNotificationId()).thenReturn("2"); + when(mockedStoredNotification2.getNotificationDateSent()).thenReturn("2024-01-01T00:05:00"); + StoredNotification storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent("2024-01-01T10:57") + .notificationSentTo(email) + .notificationBody("
" + body + "
") + .notificationMethod(StringUtils.capitalize(notificationTypeEmail)) + .notificationStatus(StringUtils.capitalize(status)) + .notificationReference(reference) + .notificationSubject(subject) + .build(); + List> appendedStoredNotifications = + List.of( + new IdValue<>("1", mockedStoredNotification), + new IdValue<>(notificationId, storedNotification), + new IdValue<>("2", mockedStoredNotification2) + ); + when(storedNotificationAppender.append(storedNotification, storedNotifications)).thenReturn(appendedStoredNotifications); + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(notificationClient, times(1)).getNotificationById(anyString()); + verify(storedNotificationAppender, times(1)).append(storedNotification, storedNotifications); + List> sortedStoredNotifications = + List.of( + new IdValue<>(notificationId, storedNotification), + new IdValue<>("2", mockedStoredNotification2), + new IdValue<>("1", mockedStoredNotification) + ); + verify(asylumCase, times(1)).write(eq(NOTIFICATIONS), eq(sortedStoredNotifications)); + } + + @Test + void should_access_notify_client_if_missing_sms_notification() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + List> notificationsSent = + List.of(new IdValue<>(reference, notificationId)); + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.empty()); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.of(notificationsSent)); + when(notificationClient.getNotificationById(notificationId)).thenReturn(notification); + when(notification.getBody()).thenReturn(body); + when(notification.getNotificationType()).thenReturn(notificationTypeSms); + when(notification.getPhoneNumber()).thenReturn(Optional.of(phoneNumber)); + when(notification.getReference()).thenReturn(Optional.of(reference)); + String dateString = "01-01-2024 10:57"; + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Europe/London")); + when(notification.getSentAt()).thenReturn(Optional.of(zonedDateTime)); + when(notification.getStatus()).thenReturn(status); + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(notificationClient, times(1)).getNotificationById(anyString()); + StoredNotification storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent("2024-01-01T10:57") + .notificationSentTo(phoneNumber) + .notificationBody("
" + body + "
") + .notificationMethod(StringUtils.capitalize(notificationTypeSms)) + .notificationStatus(StringUtils.capitalize(status)) + .notificationReference(reference) + .notificationSubject("N/A") + .build(); + verify(storedNotificationAppender, times(1)).append(storedNotification, emptyList()); + verify(asylumCase, times(1)).write(eq(NOTIFICATIONS), anyList()); + } + + @Test + void should_access_set_reference_to_id_if_no_reference() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + List> notificationsSent = + List.of(new IdValue<>(reference, notificationId)); + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.empty()); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.of(notificationsSent)); + when(notificationClient.getNotificationById(notificationId)).thenReturn(notification); + when(notification.getBody()).thenReturn(body); + when(notification.getNotificationType()).thenReturn(notificationTypeEmail); + when(notification.getEmailAddress()).thenReturn(Optional.of(email)); + when(notification.getSubject()).thenReturn(Optional.of(subject)); + String dateString = "01-01-2024 10:57"; + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Europe/London")); + when(notification.getSentAt()).thenReturn(Optional.of(zonedDateTime)); + when(notification.getStatus()).thenReturn(status); + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(notificationClient, times(1)).getNotificationById(anyString()); + StoredNotification storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent("2024-01-01T10:57") + .notificationSentTo(email) + .notificationBody("
" + body + "
") + .notificationMethod(StringUtils.capitalize(notificationTypeEmail)) + .notificationStatus(StringUtils.capitalize(status)) + .notificationReference(notificationId) + .notificationSubject(subject) + .build(); + verify(storedNotificationAppender, times(1)).append(storedNotification, emptyList()); + verify(asylumCase, times(1)).write(eq(NOTIFICATIONS), anyList()); + } + + @Test + void should_access_default_subject_if_none_found() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + List> notificationsSent = + List.of(new IdValue<>(reference, notificationId)); + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.empty()); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.of(notificationsSent)); + when(notificationClient.getNotificationById(notificationId)).thenReturn(notification); + when(notification.getBody()).thenReturn(body); + when(notification.getNotificationType()).thenReturn(notificationTypeEmail); + when(notification.getEmailAddress()).thenReturn(Optional.of(email)); + when(notification.getSubject()).thenReturn(Optional.empty()); + String dateString = "01-01-2024 10:57"; + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Europe/London")); + when(notification.getSentAt()).thenReturn(Optional.of(zonedDateTime)); + when(notification.getStatus()).thenReturn(status); + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(notificationClient, times(1)).getNotificationById(anyString()); + StoredNotification storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent("2024-01-01T10:57") + .notificationSentTo(email) + .notificationBody("
" + body + "
") + .notificationMethod(StringUtils.capitalize(notificationTypeEmail)) + .notificationStatus(StringUtils.capitalize(status)) + .notificationReference(notificationId) + .notificationSubject("N/A") + .build(); + verify(storedNotificationAppender, times(1)).append(storedNotification, emptyList()); + verify(asylumCase, times(1)).write(eq(NOTIFICATIONS), anyList()); + } + + + @Test + void should_access_default_sent_to_if_method_not_email_or_sms() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + List> notificationsSent = + List.of(new IdValue<>(reference, notificationId)); + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.empty()); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.of(notificationsSent)); + when(notificationClient.getNotificationById(notificationId)).thenReturn(notification); + when(notification.getBody()).thenReturn(body); + when(notification.getNotificationType()).thenReturn("unknownType"); + when(notification.getSubject()).thenReturn(Optional.empty()); + String dateString = "01-01-2024 10:57"; + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Europe/London")); + when(notification.getSentAt()).thenReturn(Optional.of(zonedDateTime)); + when(notification.getStatus()).thenReturn(status); + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(notificationClient, times(1)).getNotificationById(anyString()); + StoredNotification storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent("2024-01-01T10:57") + .notificationSentTo("N/A") + .notificationBody("
" + body + "
") + .notificationMethod("UnknownType") + .notificationStatus(StringUtils.capitalize(status)) + .notificationReference(notificationId) + .notificationSubject("N/A") + .build(); + verify(storedNotificationAppender, times(1)).append(storedNotification, emptyList()); + verify(asylumCase, times(1)).write(eq(NOTIFICATIONS), anyList()); + } + + @Test + void should_not_access_notify_client_if_no_notifications_sent() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + StoredNotification storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent("2024-01-01T10:57") + .notificationSentTo(email) + .notificationBody("
" + body + "
") + .notificationMethod(notificationTypeEmail) + .notificationStatus(StringUtils.capitalize(status)) + .notificationReference(reference) + .notificationSubject(subject) + .build(); + List> storedNotifications = + List.of(new IdValue<>(reference, storedNotification)); + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.of(storedNotifications)); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.empty()); + + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(notificationClient, never()).getNotificationById(anyString()); + verify(storedNotificationAppender, never()).append(any(StoredNotification.class), anyList()); + verify(asylumCase, never()).write(eq(NOTIFICATIONS), anyList()); + } + + @Test + void should_not_access_notify_client_if_stored_notifications_match_notifications_sent() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + StoredNotification storedNotification = + StoredNotification.builder() + .notificationId(notificationId) + .notificationDateSent("2024-01-01T10:57") + .notificationSentTo(email) + .notificationBody("
" + body + "
") + .notificationMethod(notificationTypeEmail) + .notificationStatus(StringUtils.capitalize(status)) + .notificationReference(reference) + .notificationSubject(subject) + .build(); + List> storedNotifications = + List.of(new IdValue<>(reference, storedNotification)); + List> notificationsSent = + List.of(new IdValue<>(reference, notificationId)); + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.of(storedNotifications)); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.of(notificationsSent)); + + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(notificationClient, never()).getNotificationById(anyString()); + verify(storedNotificationAppender, never()) + .append(any(StoredNotification.class), anyList()); + verify(asylumCase, never()).write(eq(NOTIFICATIONS), anyList()); + } + + @Test + void should_not_break_function_if_notification_client_throws_exception() throws NotificationClientException { + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getCaseData()).thenReturn(asylumCase); + List> notificationsSent = + List.of(new IdValue<>(reference, notificationId)); + when(asylumCase.read(NOTIFICATIONS)).thenReturn(Optional.empty()); + when(asylumCase.read(NOTIFICATIONS_SENT)).thenReturn(Optional.of(notificationsSent)); + when(notificationClient.getNotificationById(anyString())) + .thenThrow(new NotificationClientException("some-client-error")); + saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + verify(storedNotificationAppender, times(0)) + .append(any(StoredNotification.class), anyList()); + verify(asylumCase, times(1)).write(NOTIFICATIONS, emptyList()); + } + + @Test + void handling_should_throw_if_cannot_actually_handle() { + + assertThatThrownBy(() -> saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_START, callback)) + .hasMessage("Cannot handle callback") + .isExactlyInstanceOf(IllegalStateException.class); + + when(callback.getEvent()).thenReturn(Event.SUBMIT_APPEAL); + assertThatThrownBy(() -> saveNotificationsToDataHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback)) + .hasMessage("Cannot handle callback") + .isExactlyInstanceOf(IllegalStateException.class); + } + + @ParameterizedTest + @EnumSource(value = Event.class) + void it_can_handle_callback(Event event) { + when(callback.getEvent()).thenReturn(event); + for (PreSubmitCallbackStage callbackStage : PreSubmitCallbackStage.values()) { + + boolean canHandle = saveNotificationsToDataHandler.canHandle(callbackStage, callback); + + if (callbackStage == PreSubmitCallbackStage.ABOUT_TO_SUBMIT + && SAVE_NOTIFICATIONS_TO_DATA == callback.getEvent()) { + + assertTrue(canHandle); + } else { + assertFalse(canHandle); + } + } + } +} \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSenderTest.java b/src/test/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSenderTest.java index 8a8881e7d6..b17c41ca86 100644 --- a/src/test/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSenderTest.java +++ b/src/test/java/uk/gov/hmcts/reform/iacaseapi/infrastructure/clients/AsylumCaseNotificationApiSenderTest.java @@ -1,84 +1,135 @@ package uk.gov.hmcts.reform.iacaseapi.infrastructure.clients; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.reform.iacaseapi.domain.DateProvider; import uk.gov.hmcts.reform.iacaseapi.domain.entities.AsylumCase; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.CaseDetails; +import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.Event; import uk.gov.hmcts.reform.iacaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.iacaseapi.domain.service.Scheduler; +import uk.gov.hmcts.reform.iacaseapi.infrastructure.clients.model.TimedEvent; + +import java.time.LocalDateTime; +import java.time.Month; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @SuppressWarnings("unchecked") class AsylumCaseNotificationApiSenderTest { private static final String ENDPOINT = "http://endpoint"; - private static final String ABOUT_TO_SUBMIT_PATH = "/path"; - private static final String ABOUT_TO_START_PATH = "/path"; + private static final String CCD_SUBMITTED_PATH = "/path"; @Mock private AsylumCaseCallbackApiDelegator asylumCaseCallbackApiDelegator; @Mock private Callback callback; + @Mock + private CaseDetails caseDetails; + @Mock + private DateProvider dateProvider; + @Mock + private Scheduler scheduler; + + private AsylumCaseNotificationApiSender asylumCaseNotificationApiSender; - private AsylumCaseDocumentApiGenerator asylumCaseDocumentApiGenerator; @BeforeEach public void setUp() { - - asylumCaseDocumentApiGenerator = - new AsylumCaseDocumentApiGenerator( + asylumCaseNotificationApiSender = + new AsylumCaseNotificationApiSender( asylumCaseCallbackApiDelegator, ENDPOINT, - ABOUT_TO_SUBMIT_PATH, - ABOUT_TO_START_PATH + CCD_SUBMITTED_PATH, + false, + dateProvider, + scheduler ); } - + @Test void should_delegate_callback_to_downstream_api() { - final AsylumCase notifiedAsylumCase = mock(AsylumCase.class); - when(asylumCaseCallbackApiDelegator.delegate(callback, ENDPOINT + ABOUT_TO_SUBMIT_PATH)) + when(asylumCaseCallbackApiDelegator.delegate(callback, ENDPOINT + CCD_SUBMITTED_PATH)) .thenReturn(notifiedAsylumCase); - final AsylumCase actualAsylumCase = asylumCaseDocumentApiGenerator.generate(callback); - + final AsylumCase callbackResponse = asylumCaseNotificationApiSender.send(callback); + verify(scheduler, never()).schedule(any(TimedEvent.class)); verify(asylumCaseCallbackApiDelegator, times(1)) - .delegate(callback, ENDPOINT + ABOUT_TO_SUBMIT_PATH); + .delegate(callback, ENDPOINT + CCD_SUBMITTED_PATH); - assertEquals(notifiedAsylumCase, actualAsylumCase); + assertEquals(notifiedAsylumCase, callbackResponse); } @Test - public void should_delegate_about_to_start_callback_to_downstream_api() { - + void should_delegate_about_to_start_callback_to_downstream_api() { final AsylumCase notifiedAsylumCase = mock(AsylumCase.class); - when(asylumCaseCallbackApiDelegator.delegate(callback, ENDPOINT + ABOUT_TO_START_PATH)) + when(asylumCaseCallbackApiDelegator.delegate(callback, ENDPOINT + CCD_SUBMITTED_PATH)) .thenReturn(notifiedAsylumCase); - final AsylumCase actualAsylumCase = asylumCaseDocumentApiGenerator.aboutToStart(callback); - + final AsylumCase actualAsylumCase = asylumCaseNotificationApiSender.send(callback); + verify(scheduler, never()).schedule(any(TimedEvent.class)); verify(asylumCaseCallbackApiDelegator, times(1)) - .delegate(callback, ENDPOINT + ABOUT_TO_START_PATH); + .delegate(callback, ENDPOINT + CCD_SUBMITTED_PATH); assertEquals(notifiedAsylumCase, actualAsylumCase); } @Test void should_not_allow_null_arguments() { - - assertThatThrownBy(() -> asylumCaseDocumentApiGenerator.generate(null)) + assertThatThrownBy(() -> asylumCaseNotificationApiSender.send(null)) .hasMessage("callback must not be null") .isExactlyInstanceOf(NullPointerException.class); } + + @Test + void schedules_save_notification_to_data_event_if_tes_enabled() { + asylumCaseNotificationApiSender = + new AsylumCaseNotificationApiSender( + asylumCaseCallbackApiDelegator, + ENDPOINT, + CCD_SUBMITTED_PATH, + true, + dateProvider, + scheduler + ); + final AsylumCase notifiedAsylumCase = mock(AsylumCase.class); + + when(asylumCaseCallbackApiDelegator.delegate(callback, ENDPOINT + CCD_SUBMITTED_PATH)) + .thenReturn(notifiedAsylumCase); + LocalDateTime localDateTime = + LocalDateTime.of(2004, Month.FEBRUARY, 5, 10, 57, 33); + when(dateProvider.nowWithTime()).thenReturn(localDateTime); + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(caseDetails.getId()).thenReturn(0L); + + final AsylumCase callbackResponse = asylumCaseNotificationApiSender.send(callback); + + ZonedDateTime expectedTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault()) + .plusSeconds(15); + TimedEvent expectedTimedEvent = new TimedEvent( + "", + Event.SAVE_NOTIFICATIONS_TO_DATA, + expectedTime, + "IA", + "Asylum", + 0L + ); + verify(scheduler).schedule(refEq(expectedTimedEvent)); + verify(asylumCaseCallbackApiDelegator, times(1)) + .delegate(callback, ENDPOINT + CCD_SUBMITTED_PATH); + + assertEquals(notifiedAsylumCase, callbackResponse); + } }