diff --git a/src/functionalTest/resources/scenarios/DIAC-528-upload-hearing-recording-details.json b/src/functionalTest/resources/scenarios/DIAC-528-upload-hearing-recording-details.json new file mode 100644 index 000000000..94d24b261 --- /dev/null +++ b/src/functionalTest/resources/scenarios/DIAC-528-upload-hearing-recording-details.json @@ -0,0 +1,23 @@ +{ + "description": "Upload hearing recording confirmation", + "request": { + "uri": "/bail/ccdSubmitted", + "credentials": "AdminOfficer", + "input": { + "id": 1111, + "eventId": "uploadHearingRecording", + "state": "decisionDecided", + "caseData": { + "template": "minimal-application-submitted.json" + } + } + }, + "expectation": { + "status": 200, + "errors": [], + "confirmation": { + "header": "# You’ve uploaded the hearing recording", + "body": "#### What happens next\nThis file is now available in the Documents tab and the Hearing and appointment tab." + } + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinition.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinition.java index 8352e8662..02dbca1c8 100644 --- a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinition.java +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinition.java @@ -627,9 +627,18 @@ public enum BailCaseFieldDefinition { LIST_CASE_HEARING_DATE( "listingHearingDate", new TypeReference(){}), + LISTING_HEARING_DURATION( + "listingHearingDuration", new TypeReference(){}), + LISTING_LOCATION( "listingLocation", new TypeReference(){}), + PREVIOUS_LISTING_DETAILS( + "previousListingDetails", new TypeReference>>() {}), + HAS_BEEN_RELISTED( + "hasBeenRelisted", new TypeReference() {}), + PREVIOUS_DECISION_DETAILS( + "previousDecisionDetails", new TypeReference>>() {}), HO_HAS_IMA_STATUS( "hoHasImaStatus", new TypeReference(){}), ADMIN_HAS_IMA_STATUS( @@ -654,7 +663,10 @@ public enum BailCaseFieldDefinition { IS_BAILS_LOCATION_REFERENCE_DATA_ENABLED_FT( "isBailsLocationReferenceDataEnabledFt", new TypeReference() {}), HAS_CASE_BEEN_FORCED_TO_HEARING( - "hasCaseBeenForcedToHearing", new TypeReference() {}); + "hasCaseBeenForcedToHearing", new TypeReference() {}), + + HEARING_RECORDING_DOCUMENTS( + "hearingRecordingDocuments", new TypeReference>>(){}); private final String value; private final TypeReference typeReference; diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/HearingRecordingDocument.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/HearingRecordingDocument.java new file mode 100644 index 000000000..7e6a04b1c --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/HearingRecordingDocument.java @@ -0,0 +1,17 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.entities; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.Document; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.HasDocument; + +@Value +@Builder +@Jacksonized +@AllArgsConstructor +public class HearingRecordingDocument implements HasDocument { + Document document; + String description; +} diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/Event.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/Event.java index c67e23a94..4e93dd3c1 100644 --- a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/Event.java +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/Event.java @@ -39,6 +39,7 @@ public enum Event { UPLOAD_SIGNED_DECISION_NOTICE("uploadSignedDecisionNotice"), VIEW_PREVIOUS_APPLICATIONS("viewPreviousApplications"), TEST_TIMED_EVENT_SCHEDULE("testTimedEventSchedule"), + UPLOAD_HEARING_RECORDING("uploadHearingRecording"), @JsonEnumDefaultValue UNKNOWN("unknown"); diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousDecisionDetails.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousDecisionDetails.java new file mode 100644 index 000000000..af3724e44 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousDecisionDetails.java @@ -0,0 +1,17 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PreviousDecisionDetails { + + private String decisionDetailsDate; + private String recordDecisionType; + private Document uploadSignedDecisionNoticeDocument; +} diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousListingDetails.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousListingDetails.java new file mode 100644 index 000000000..2d2d81155 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousListingDetails.java @@ -0,0 +1,20 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingHearingCentre; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PreviousListingDetails { + + private ListingEvent listingEvent; + private ListingHearingCentre listingLocation; + private String listingHearingDate; + private String listingHearingDuration; +} diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/postsubmit/UploadHearingRecordingConfirmation.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/postsubmit/UploadHearingRecordingConfirmation.java new file mode 100644 index 000000000..e07855d2c --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/postsubmit/UploadHearingRecordingConfirmation.java @@ -0,0 +1,42 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.postsubmit; + +import static java.util.Objects.requireNonNull; + +import org.springframework.stereotype.Component; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCase; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.Event; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PostSubmitCallbackResponse; +import uk.gov.hmcts.reform.bailcaseapi.domain.handlers.PostSubmitCallbackHandler; + +@Component +public class UploadHearingRecordingConfirmation implements PostSubmitCallbackHandler { + + public boolean canHandle( + Callback callback + ) { + requireNonNull(callback, "callback must not be null"); + + return callback.getEvent() == Event.UPLOAD_HEARING_RECORDING; + } + + public PostSubmitCallbackResponse handle( + Callback callback + ) { + if (!canHandle(callback)) { + throw new IllegalStateException("Cannot handle callback"); + } + + PostSubmitCallbackResponse postSubmitResponse = + new PostSubmitCallbackResponse(); + + postSubmitResponse.setConfirmationHeader( + """ + # You’ve uploaded the hearing recording"""); + postSubmitResponse.setConfirmationBody(""" + #### What happens next + This file is now available in the Documents tab and the Hearing and appointment tab."""); + + return postSubmitResponse; + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandler.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandler.java index 895d55c1e..30ef44074 100644 --- a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandler.java +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandler.java @@ -1,17 +1,9 @@ package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.presubmit; import static java.time.format.DateTimeFormatter.ISO_DATE_TIME; +import static java.util.Collections.emptyList; import static java.util.Objects.requireNonNull; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.DATE_OF_COMPLIANCE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.IS_BAILS_LOCATION_REFERENCE_DATA_ENABLED; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.LISTING_EVENT; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.LISTING_LOCATION; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.LIST_CASE_HEARING_DATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.REF_DATA_LISTING_LOCATION; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.REF_DATA_LISTING_LOCATION_DETAIL; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.SEND_DIRECTION_DESCRIPTION; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.SEND_DIRECTION_LIST; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.UPLOAD_BAIL_SUMMARY_ACTION_AVAILABLE; +import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.*; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent.INITIAL_LISTING; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo.NO; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo.YES; @@ -20,22 +12,23 @@ import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.util.List; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; +import com.microsoft.applicationinsights.boot.dependencies.apachecommons.lang3.StringUtils; import org.springframework.stereotype.Component; import uk.gov.hmcts.reform.bailcaseapi.domain.RequiredFieldMissingException; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCase; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.DynamicList; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingHearingCentre; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.Value; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.*; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.CaseDetails; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.Event; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.PreviousListingDetails; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo; import uk.gov.hmcts.reform.bailcaseapi.domain.handlers.PreSubmitCallbackHandler; +import uk.gov.hmcts.reform.bailcaseapi.domain.service.Appender; import uk.gov.hmcts.reform.bailcaseapi.domain.service.DueDateService; import uk.gov.hmcts.reform.bailcaseapi.domain.service.LocationRefDataService; import uk.gov.hmcts.reform.bailcaseapi.infrastructure.clients.model.refdata.CourtVenue; @@ -43,11 +36,17 @@ @Component public class CaseListingHandler implements PreSubmitCallbackHandler { + private final Appender previousListingDetailsAppender; private final DueDateService dueDateService; private final LocationRefDataService locationRefDataService; - public CaseListingHandler(DueDateService dueDateService, LocationRefDataService locationRefDataService) { + public CaseListingHandler( + Appender previousListingDetailsAppender, + DueDateService dueDateService, + LocationRefDataService locationRefDataService + ) { this.dueDateService = dueDateService; + this.previousListingDetailsAppender = previousListingDetailsAppender; this.locationRefDataService = locationRefDataService; } @@ -62,6 +61,7 @@ public boolean canHandle( && callback.getEvent() == Event.CASE_LISTING; } + @Override public PreSubmitCallbackResponse handle( PreSubmitCallbackStage callbackStage, Callback callback @@ -69,15 +69,9 @@ public PreSubmitCallbackResponse handle( if (!canHandle(callbackStage, callback)) { throw new IllegalStateException("Cannot handle callback"); } - - final BailCase bailCase = - callback - .getCaseDetails() - .getCaseData(); - + BailCase bailCase = callback.getCaseDetails().getCaseData(); ListingEvent listingEvent = bailCase.read(LISTING_EVENT, ListingEvent.class) .orElseThrow(() -> new RequiredFieldMissingException("listingEvent is not present")); - if (listingEvent == INITIAL_LISTING) { String hearingDate = bailCase.read(LIST_CASE_HEARING_DATE, String.class) .orElseThrow(() -> new RequiredFieldMissingException("listingHearingDate is not present")); @@ -111,7 +105,41 @@ public PreSubmitCallbackResponse handle( bailCase.write(SEND_DIRECTION_LIST, "Home Office"); bailCase.write(DATE_OF_COMPLIANCE, dueDate); - bailCase.write(UPLOAD_BAIL_SUMMARY_ACTION_AVAILABLE, YesOrNo.YES); + bailCase.write(UPLOAD_BAIL_SUMMARY_ACTION_AVAILABLE, YES); + } else { + CaseDetails caseDetailsBefore = callback.getCaseDetailsBefore().orElse(null); + BailCase bailCaseBefore = caseDetailsBefore == null ? null : caseDetailsBefore.getCaseData(); + if (bailCaseBefore != null) { + ListingEvent prevListingEvent = bailCaseBefore.read(LISTING_EVENT, ListingEvent.class) + .orElse(null); + ListingHearingCentre prevListingLocation = bailCaseBefore.read(LISTING_LOCATION, + ListingHearingCentre.class) + .orElse(null); + String prevListingHearingDate = bailCaseBefore.read(LIST_CASE_HEARING_DATE, String.class) + .orElse(null); + String prevListingHearingDuration = bailCaseBefore.read(LISTING_HEARING_DURATION, String.class) + .orElse(null); + + if (prevListingEvent == null || prevListingLocation == null || prevListingHearingDate == null || prevListingHearingDuration == null) { + PreSubmitCallbackResponse response = new PreSubmitCallbackResponse<>(bailCase); + response.addError("Relisting is only available after an initial listing."); + return response; + } + + Optional>> maybeExistingPreviousListingDetails = + bailCase.read(PREVIOUS_LISTING_DETAILS); + final PreviousListingDetails newPreviousListingDetails = + new PreviousListingDetails(prevListingEvent, + prevListingLocation, + prevListingHearingDate, + prevListingHearingDuration); + List> allPreviousListingDetails = + previousListingDetailsAppender.append(newPreviousListingDetails, + maybeExistingPreviousListingDetails.orElse(emptyList())); + + bailCase.write(PREVIOUS_LISTING_DETAILS, allPreviousListingDetails); + bailCase.write(HAS_BEEN_RELISTED, YES); + } } updateListingLocValueByUsingRefDataLocValue(bailCase); @@ -125,7 +153,7 @@ private void updateListingLocValueByUsingRefDataLocValue(BailCase bailCase) { if (isBailsLocationRefDataEnabled == YES) { Value selectedRefDataLocation = bailCase.read(REF_DATA_LISTING_LOCATION, DynamicList.class) - .map(dynamicList -> dynamicList.getValue()).orElse(null); + .map(DynamicList::getValue).orElse(null); if (selectedRefDataLocation != null) { saveRefDataListingLocationDetail(bailCase, selectedRefDataLocation.getCode()); @@ -147,9 +175,7 @@ private void updateListingLocValueByUsingRefDataLocValue(BailCase bailCase) { private void saveRefDataListingLocationDetail(BailCase bailCase, String epimmsId) { if (!StringUtils.isEmpty(epimmsId)) { Optional courtVenue = locationRefDataService.getCourtVenuesByEpimmsId(epimmsId); - if (courtVenue.isPresent()) { - bailCase.write(REF_DATA_LISTING_LOCATION_DETAIL, courtVenue.get()); - } + courtVenue.ifPresent(venue -> bailCase.write(REF_DATA_LISTING_LOCATION_DETAIL, venue)); } } } diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppender.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppender.java index fd14bc550..9486908e8 100644 --- a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppender.java +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppender.java @@ -1,5 +1,6 @@ package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.presubmit; +import static java.util.Collections.emptyList; import static java.util.Objects.requireNonNull; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.*; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo.NO; @@ -9,25 +10,38 @@ import uk.gov.hmcts.reform.bailcaseapi.domain.BailCaseUtils; import uk.gov.hmcts.reform.bailcaseapi.domain.DateProvider; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCase; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingHearingCentre; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.CaseDetails; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.DecisionType; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.Event; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.DispatchPriority; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.*; import uk.gov.hmcts.reform.bailcaseapi.domain.handlers.PreSubmitCallbackHandler; +import uk.gov.hmcts.reform.bailcaseapi.domain.service.Appender; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; @Component public class DecisionTypeAppender implements PreSubmitCallbackHandler { + private final Appender previousDecisionDetailsAppender; private final DateProvider dateProvider; private static final String REFUSED = "refused"; private static final String GRANTED = "granted"; private static final String REFUSED_UNDER_IMA = "refusedUnderIma"; - public DecisionTypeAppender(DateProvider dateProvider) { + public DecisionTypeAppender( + Appender previousDecisionDetailsAppender, + DateProvider dateProvider + ) { + this.previousDecisionDetailsAppender = previousDecisionDetailsAppender; this.dateProvider = dateProvider; } @@ -75,7 +89,7 @@ public PreSubmitCallbackResponse handle( if ( BailCaseUtils.isImaEnabled(bailCase) && (decisionGrantedOrRefused.equals(REFUSED_UNDER_IMA) - || recordTheDecisionList.equals(REFUSED_UNDER_IMA))) { + || recordTheDecisionList.equals(REFUSED_UNDER_IMA))) { bailCase.write(RECORD_DECISION_TYPE, DecisionType.REFUSED_UNDER_IMA); } else if (decisionGrantedOrRefused.equals(REFUSED) || recordTheDecisionList.equals(REFUSED) @@ -87,7 +101,7 @@ public PreSubmitCallbackResponse handle( bailCase.write(RECORD_DECISION_TYPE, DecisionType.GRANTED); } else if ((decisionGrantedOrRefused.equals(GRANTED) && releaseStatusYesOrNo == NO) - || (ssConsentDecision == YES && releaseStatusYesOrNo == NO)) { + || (ssConsentDecision == YES && releaseStatusYesOrNo == NO)) { bailCase.write(RECORD_DECISION_TYPE, DecisionType.CONDITIONAL_GRANT); } else { @@ -98,10 +112,37 @@ public PreSubmitCallbackResponse handle( // Following two definitions are needed for UI only. // It is to have different section for Unsigned Decision Details for Admin and Judges. bailCase.write(DECISION_UNSIGNED_DETAILS_DATE, decisionDate); - bailCase.write(RECORD_UNSIGNED_DECISION_TYPE, - bailCase.read(RECORD_DECISION_TYPE, String.class) - .orElseThrow(() -> new IllegalStateException("Record decision type missing"))); + bailCase.write( + RECORD_UNSIGNED_DECISION_TYPE, + bailCase.read(RECORD_DECISION_TYPE, String.class) + .orElseThrow(() -> new IllegalStateException("Record decision type missing")) + ); bailCase.clear(HAS_CASE_BEEN_FORCED_TO_HEARING); + CaseDetails caseDetailsBefore = callback.getCaseDetailsBefore().orElse(null); + BailCase bailCaseBefore = caseDetailsBefore == null ? null : caseDetailsBefore.getCaseData(); + if (bailCaseBefore != null) { + String prevDecisionDetailsDate = bailCaseBefore.read(DECISION_DETAILS_DATE, String.class) + .orElse(null); + String prevRecordDecisionType = bailCaseBefore.read(RECORD_DECISION_TYPE, String.class) + .orElse(null); + Document prevUploadSignedDecisionNoticeDocument = bailCaseBefore.read( + UPLOAD_SIGNED_DECISION_NOTICE_DOCUMENT, Document.class) + .orElse(null); + if (prevDecisionDetailsDate != null && prevRecordDecisionType != null && prevUploadSignedDecisionNoticeDocument != null) { + Optional>> maybeExistingPreviousDecisionDetails = + bailCase.read(PREVIOUS_DECISION_DETAILS); + final PreviousDecisionDetails newPreviousDecisionDetails = new PreviousDecisionDetails( + prevDecisionDetailsDate, prevRecordDecisionType, prevUploadSignedDecisionNoticeDocument); + List> allPreviousDecisionDetails = previousDecisionDetailsAppender + .append( + newPreviousDecisionDetails, + maybeExistingPreviousDecisionDetails.orElseGet(Collections::emptyList) + ); + bailCase.write(PREVIOUS_DECISION_DETAILS, allPreviousDecisionDetails); + bailCase.clear(UPLOAD_SIGNED_DECISION_NOTICE_DOCUMENT); + } + } + return new PreSubmitCallbackResponse<>(bailCase); } diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadHearingRecordingDocumentsMidEvent.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadHearingRecordingDocumentsMidEvent.java new file mode 100644 index 000000000..16708b86c --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadHearingRecordingDocumentsMidEvent.java @@ -0,0 +1,62 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.presubmit; + +import static java.util.Objects.requireNonNull; +import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.*; + +import java.util.List; +import java.util.Optional; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.*; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.Event; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.bailcaseapi.domain.handlers.PreSubmitCallbackHandler; + +@Component +public class UploadHearingRecordingDocumentsMidEvent implements PreSubmitCallbackHandler { + + public boolean canHandle( + PreSubmitCallbackStage callbackStage, + Callback callback + ) { + requireNonNull(callbackStage, "callbackStage must not be null"); + requireNonNull(callback, "callback must not be null"); + + return callbackStage == PreSubmitCallbackStage.MID_EVENT + && callback.getEvent() == Event.UPLOAD_HEARING_RECORDING; + } + + public PreSubmitCallbackResponse handle( + PreSubmitCallbackStage callbackStage, + Callback callback + ) { + if (!canHandle(callbackStage, callback)) { + throw new IllegalStateException("Cannot handle callback"); + } + + BailCase bailCase = callback.getCaseDetails().getCaseData(); + + Optional>> maybeHearingRecordingDocuments = bailCase.read(HEARING_RECORDING_DOCUMENTS); + + if (maybeHearingRecordingDocuments.isPresent()) { + List> hearingRecordingDocuments = maybeHearingRecordingDocuments.get(); + + for (IdValue doc : hearingRecordingDocuments) { + + String filename = doc.getValue().getDocument().getDocumentFilename(); + + System.out.println("Processing file: " + filename); + + if (filename == null || filename.isEmpty() || !filename.toLowerCase().endsWith(".mp3")) { + PreSubmitCallbackResponse response = new PreSubmitCallbackResponse<>(bailCase); + response.addError("All documents must be an mp3 file"); + return response; + } + } + } + + return new PreSubmitCallbackResponse<>(bailCase); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandler.java b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandler.java index 7330f14cb..d586b7bf5 100644 --- a/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandler.java +++ b/src/main/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandler.java @@ -1,9 +1,7 @@ package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.presubmit; import static java.util.Objects.requireNonNull; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.OUTCOME_DATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.OUTCOME_STATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.TRIBUNAL_DOCUMENTS_WITH_METADATA; +import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.*; import java.util.ArrayList; import java.util.Collections; @@ -21,6 +19,7 @@ import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo; import uk.gov.hmcts.reform.bailcaseapi.domain.handlers.PreSubmitCallbackHandler; @Component @@ -82,6 +81,8 @@ public PreSubmitCallbackResponse handle( // & SIGNED_DECISION_DOCUMENT_WITH_METADATA. bailCase.write(OUTCOME_DATE, dateProvider.nowWithTime().toString()); bailCase.write(OUTCOME_STATE, State.DECISION_DECIDED); + bailCase.write(HAS_BEEN_RELISTED, YesOrNo.NO); + bailCase.clear(DECISION_UNSIGNED_DOCUMENT); return new PreSubmitCallbackResponse<>(bailCase); } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 96e38f59d..c9e42ba3e 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -120,6 +120,7 @@ security: - "forceCaseToHearing" - "changeTribunalCentre" - "testTimedEventSchedule" + - "uploadHearingRecording" caseworker-ia-homeofficebail: - "startApplication" - "uploadBailSummary" @@ -151,6 +152,7 @@ security: - "maintainBailCaseLinks" - "createFlag" - "forceCaseToHearing" + - "uploadHearingRecording" ### dependency configuration ccdGatewayUrl: ${CCD_GW_URL:http://localhost:3453} diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinitionTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinitionTest.java index 08820ce33..514680942 100644 --- a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinitionTest.java +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/BailCaseFieldDefinitionTest.java @@ -15,7 +15,7 @@ public class BailCaseFieldDefinitionTest { */ @Test void fail_if_changes_needed_after_modifying_bail_case_definition() { - assertEquals(294, BailCaseFieldDefinition.values().length); + assertEquals(299, BailCaseFieldDefinition.values().length); } @Test diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/EventTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/EventTest.java index c36ef1a54..18cf6e43c 100644 --- a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/EventTest.java +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/EventTest.java @@ -40,6 +40,7 @@ void has_correct_values() { assertEquals("changeTribunalCentre", Event.CHANGE_TRIBUNAL_CENTRE.toString()); assertEquals("testTimedEventSchedule", Event.TEST_TIMED_EVENT_SCHEDULE.toString()); assertEquals("unknown", Event.UNKNOWN.toString()); + assertEquals("uploadHearingRecording", Event.UPLOAD_HEARING_RECORDING.toString()); } @Test diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousDecisionDetailsTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousDecisionDetailsTest.java new file mode 100644 index 000000000..11cd87cf1 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousDecisionDetailsTest.java @@ -0,0 +1,26 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +class PreviousDecisionDetailsTest { + + private final String decisionDetailsDate = "2023-02-21"; + private final String recordDecisionType = "conditionalBail"; + private final Document uploadSignedDecisionNoticeDocument = mock(Document.class); + + private final PreviousDecisionDetails previousDecisionDetails = new PreviousDecisionDetails( + decisionDetailsDate, + recordDecisionType, + uploadSignedDecisionNoticeDocument + ); + + @Test + void should_hold_onto_values() { + assertEquals(decisionDetailsDate, previousDecisionDetails.getDecisionDetailsDate()); + assertEquals(recordDecisionType, previousDecisionDetails.getRecordDecisionType()); + assertEquals(uploadSignedDecisionNoticeDocument, previousDecisionDetails.getUploadSignedDecisionNoticeDocument()); + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousListingDetailsTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousListingDetailsTest.java new file mode 100644 index 000000000..d832f3644 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/entities/ccd/field/PreviousListingDetailsTest.java @@ -0,0 +1,31 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field; + +import org.junit.jupiter.api.Test; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingHearingCentre; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PreviousListingDetailsTest { + + private final ListingEvent listingEvent = ListingEvent.INITIAL_LISTING; + private final ListingHearingCentre listingLocation = ListingHearingCentre.BIRMINGHAM; + private final String listingHearingDate = "2023-02-21"; + private final String listingHearingDuration = "100"; + + private final PreviousListingDetails previousListingDetails = new PreviousListingDetails( + listingEvent, + listingLocation, + listingHearingDate, + listingHearingDuration + ); + + @Test + void should_hold_onto_values() { + assertEquals(listingEvent, previousListingDetails.getListingEvent()); + assertEquals(listingLocation, previousListingDetails.getListingLocation()); + assertEquals(listingHearingDate, previousListingDetails.getListingHearingDate()); + assertEquals(listingHearingDuration, previousListingDetails.getListingHearingDuration()); + } + +} diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/postsubmit/UploadHearingRecordingConfirmationTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/postsubmit/UploadHearingRecordingConfirmationTest.java new file mode 100644 index 000000000..8366d259c --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/postsubmit/UploadHearingRecordingConfirmationTest.java @@ -0,0 +1,88 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.postsubmit; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; + +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.bailcaseapi.domain.entities.BailCase; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.Event; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PostSubmitCallbackResponse; + +@ExtendWith(MockitoExtension.class) +@SuppressWarnings("unchecked") +class UploadHearingRecordingConfirmationTest { + + @Mock private Callback callback; + + private UploadHearingRecordingConfirmation uploadHearingRecordingConfirmation = + new UploadHearingRecordingConfirmation(); + + @Test + void should_return_confirmation() { + + when(callback.getEvent()).thenReturn(Event.UPLOAD_HEARING_RECORDING); + + PostSubmitCallbackResponse callbackResponse = + uploadHearingRecordingConfirmation.handle(callback); + + assertNotNull(callbackResponse); + assertTrue(callbackResponse.getConfirmationHeader().isPresent()); + assertTrue(callbackResponse.getConfirmationBody().isPresent()); + + assertTrue( + callbackResponse.getConfirmationHeader().orElse("").contains("You’ve uploaded the hearing recording"), + "Confirmation header should contain 'You’ve uploaded the hearing recording'" + ); + + assertTrue( + callbackResponse.getConfirmationBody().orElse("").contains("This file is now available in the Documents tab and the Hearing and appointment tab."), + "Confirmation body should contain 'This file is now available in the Documents tab and the Hearing and appointment tab.'" + ); + } + + @Test + void handling_should_throw_if_cannot_actually_handle() { + + assertThatThrownBy(() -> uploadHearingRecordingConfirmation.handle(callback)) + .hasMessage("Cannot handle callback") + .isExactlyInstanceOf(IllegalStateException.class); + } + + @Test + void it_can_handle_callback() { + + for (Event event : Event.values()) { + + when(callback.getEvent()).thenReturn(event); + + boolean canHandle = uploadHearingRecordingConfirmation.canHandle(callback); + + if (event == Event.UPLOAD_HEARING_RECORDING) { + + assertTrue(canHandle); + } else { + assertFalse(canHandle); + } + + reset(callback); + } + } + + @Test + void should_not_allow_null_arguments() { + + assertThatThrownBy(() -> uploadHearingRecordingConfirmation.canHandle(null)) + .hasMessage("callback must not be null") + .isExactlyInstanceOf(NullPointerException.class); + + assertThatThrownBy(() -> uploadHearingRecordingConfirmation.handle(null)) + .hasMessage("callback must not be null") + .isExactlyInstanceOf(NullPointerException.class); + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandlerTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandlerTest.java index ce0880f0f..2af78aa5a 100644 --- a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandlerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/CaseListingHandlerTest.java @@ -1,24 +1,19 @@ package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.presubmit; + import static java.time.format.DateTimeFormatter.ISO_DATE_TIME; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.DATE_OF_COMPLIANCE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.IS_BAILS_LOCATION_REFERENCE_DATA_ENABLED; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.LISTING_EVENT; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.LISTING_LOCATION; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.LIST_CASE_HEARING_DATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.REF_DATA_LISTING_LOCATION; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.REF_DATA_LISTING_LOCATION_DETAIL; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.SEND_DIRECTION_DESCRIPTION; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.SEND_DIRECTION_LIST; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.UPLOAD_BAIL_SUMMARY_ACTION_AVAILABLE; +import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.*; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent.INITIAL_LISTING; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent.RELISTING; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingHearingCentre.NEWCASTLE; @@ -27,8 +22,12 @@ import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -39,17 +38,16 @@ import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import uk.gov.hmcts.reform.bailcaseapi.domain.RequiredFieldMissingException; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCase; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.DynamicList; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ListingEvent; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.Value; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.*; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.CaseDetails; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.Event; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.PreviousListingDetails; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo; +import uk.gov.hmcts.reform.bailcaseapi.domain.service.Appender; import uk.gov.hmcts.reform.bailcaseapi.domain.service.DueDateService; import uk.gov.hmcts.reform.bailcaseapi.domain.service.LocationRefDataService; import uk.gov.hmcts.reform.bailcaseapi.infrastructure.clients.model.refdata.CourtVenue; @@ -61,8 +59,11 @@ class CaseListingHandlerTest { @Mock private Callback callback; @Mock private CaseDetails caseDetails; + @Mock private CaseDetails caseDetailsBefore; @Mock private BailCase bailCase; + @Mock private BailCase bailCaseBefore; @Mock private DueDateService dueDateService; + @Mock private Appender previousListingDetailsAppender; @Mock private LocationRefDataService locationRefDataService; @Captor @@ -77,7 +78,7 @@ class CaseListingHandlerTest { @BeforeEach public void setUp() { - caseListingHandler = new CaseListingHandler(dueDateService, locationRefDataService); + caseListingHandler = new CaseListingHandler(previousListingDetailsAppender, dueDateService, locationRefDataService); when(callback.getCaseDetails()).thenReturn(caseDetails); when(callback.getEvent()).thenReturn(Event.CASE_LISTING); @@ -247,4 +248,160 @@ void should_not_allow_null_arguments() { .isExactlyInstanceOf(NullPointerException.class); } + @Test + void should_handle_relisting_without_previous_hearing_details_list() { + when(bailCase.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.RELISTING)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.INITIAL_LISTING)); + when(bailCaseBefore.read(LISTING_LOCATION, ListingHearingCentre.class)).thenReturn(Optional.of(ListingHearingCentre.BIRMINGHAM)); + when(bailCaseBefore.read(LIST_CASE_HEARING_DATE, String.class)).thenReturn(Optional.of(caseListHearingDate)); + when(bailCaseBefore.read(LISTING_HEARING_DURATION, String.class)).thenReturn(Optional.of("60")); + PreSubmitCallbackResponse response = caseListingHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + + assertNotNull(response); + assertEquals(bailCase, response.getData()); + verify(bailCaseBefore, times(1)).read(LISTING_EVENT, ListingEvent.class); + verify(bailCaseBefore, times(1)).read(LISTING_LOCATION, ListingHearingCentre.class); + verify(bailCaseBefore, times(1)).read(LIST_CASE_HEARING_DATE, String.class); + verify(bailCaseBefore, times(1)).read(LISTING_HEARING_DURATION, String.class); + verify(bailCase, times(1)).read(PREVIOUS_LISTING_DETAILS); + final PreviousListingDetails newPreviousListingDetails = + new PreviousListingDetails(ListingEvent.INITIAL_LISTING, + ListingHearingCentre.BIRMINGHAM, + caseListHearingDate, + "60"); + verify(previousListingDetailsAppender, times(1)).append(newPreviousListingDetails, emptyList()); + verify(bailCase, times(1)).write(eq(PREVIOUS_LISTING_DETAILS), any(List.class)); + verify(bailCase, times(1)).write(HAS_BEEN_RELISTED, YesOrNo.YES); + } + + @Test + void should_handle_relisting_with_previous_hearing_details_list() { + when(bailCase.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.RELISTING)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.RELISTING)); + when(bailCaseBefore.read(LISTING_LOCATION, ListingHearingCentre.class)) + .thenReturn(Optional.of(ListingHearingCentre.BELFAST)); + when(bailCaseBefore.read(LIST_CASE_HEARING_DATE, String.class)).thenReturn(Optional.of(caseListHearingDate)); + when(bailCaseBefore.read(LISTING_HEARING_DURATION, String.class)).thenReturn(Optional.of("100")); + List storedPrevListingDetails = + List.of(new PreviousListingDetails(ListingEvent.INITIAL_LISTING, + ListingHearingCentre.BIRMINGHAM, + caseListHearingDate, + "60")); + List> idValueStoredPrevListingDetails = new ArrayList<>(); + idValueStoredPrevListingDetails.add(new IdValue<>("1", storedPrevListingDetails.get(0))); + when(bailCase.read(PREVIOUS_LISTING_DETAILS)).thenReturn(Optional.of(idValueStoredPrevListingDetails)); + + PreSubmitCallbackResponse response = caseListingHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + + assertNotNull(response); + assertEquals(bailCase, response.getData()); + verify(bailCaseBefore, times(1)).read(LISTING_EVENT, ListingEvent.class); + verify(bailCaseBefore, times(1)).read(LISTING_LOCATION, ListingHearingCentre.class); + verify(bailCaseBefore, times(1)).read(LIST_CASE_HEARING_DATE, String.class); + verify(bailCaseBefore, times(1)).read(LISTING_HEARING_DURATION, String.class); + verify(bailCase, times(1)).read(PREVIOUS_LISTING_DETAILS); + final PreviousListingDetails newPreviousListingDetails = + new PreviousListingDetails(ListingEvent.RELISTING, + ListingHearingCentre.BELFAST, + caseListHearingDate, + "100"); + verify(previousListingDetailsAppender, times(1)).append(newPreviousListingDetails, + idValueStoredPrevListingDetails); + verify(bailCase, times(1)).write(eq(PREVIOUS_LISTING_DETAILS), any(List.class)); + verify(bailCase, times(1)).write(HAS_BEEN_RELISTED, YesOrNo.YES); + } + + @Test + void should_throw_exception_when_initial_listing_event_is_missing() { + when(bailCase.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.RELISTING)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.empty()); + + PreSubmitCallbackResponse response = + caseListingHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + + assertNotNull(response); + assertEquals(bailCase, response.getData()); + verify(bailCaseBefore, times(1)).read(LISTING_EVENT, ListingEvent.class); + verify(bailCaseBefore, times(1)).read(LISTING_LOCATION, ListingHearingCentre.class); + verify(bailCaseBefore, times(1)).read(LIST_CASE_HEARING_DATE, String.class); + verify(bailCaseBefore, times(1)).read(LISTING_HEARING_DURATION, String.class); + Set expectedErrors = new HashSet<>(); + expectedErrors.add("Relisting is only available after an initial listing."); + assertEquals(response.getErrors(), expectedErrors); + } + + @Test + void should_throw_exception_when_initial_listing_location_is_missing() { + when(bailCase.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.RELISTING)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.INITIAL_LISTING)); + when(bailCaseBefore.read(LISTING_LOCATION, ListingHearingCentre.class)).thenReturn(Optional.empty()); + + PreSubmitCallbackResponse response = + caseListingHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + + assertNotNull(response); + assertEquals(bailCase, response.getData()); + verify(bailCaseBefore, times(1)).read(LISTING_EVENT, ListingEvent.class); + verify(bailCaseBefore, times(1)).read(LISTING_LOCATION, ListingHearingCentre.class); + verify(bailCaseBefore, times(1)).read(LIST_CASE_HEARING_DATE, String.class); + verify(bailCaseBefore, times(1)).read(LISTING_HEARING_DURATION, String.class); + Set expectedErrors = new HashSet<>(); + expectedErrors.add("Relisting is only available after an initial listing."); + assertEquals(response.getErrors(), expectedErrors); + } + + @Test + void should_throw_exception_when_initial_listing_hearing_date_is_missing() { + when(bailCase.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.RELISTING)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.INITIAL_LISTING)); + when(bailCaseBefore.read(LISTING_LOCATION, ListingHearingCentre.class)).thenReturn(Optional.of(ListingHearingCentre.BIRMINGHAM)); + when(bailCaseBefore.read(LIST_CASE_HEARING_DATE, String.class)).thenReturn(Optional.empty()); + + PreSubmitCallbackResponse response = + caseListingHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + + assertNotNull(response); + assertEquals(bailCase, response.getData()); + verify(bailCaseBefore, times(1)).read(LISTING_EVENT, ListingEvent.class); + verify(bailCaseBefore, times(1)).read(LISTING_LOCATION, ListingHearingCentre.class); + verify(bailCaseBefore, times(1)).read(LIST_CASE_HEARING_DATE, String.class); + verify(bailCaseBefore, times(1)).read(LISTING_HEARING_DURATION, String.class); + Set expectedErrors = new HashSet<>(); + expectedErrors.add("Relisting is only available after an initial listing."); + assertEquals(response.getErrors(), expectedErrors); + } + + @Test + void should_throw_exception_when_initial_listing_hearing_duration_is_missing() { + when(bailCase.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.RELISTING)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(LISTING_EVENT, ListingEvent.class)).thenReturn(Optional.of(ListingEvent.INITIAL_LISTING)); + when(bailCaseBefore.read(LISTING_LOCATION, ListingHearingCentre.class)).thenReturn(Optional.of(ListingHearingCentre.BIRMINGHAM)); + when(bailCaseBefore.read(LIST_CASE_HEARING_DATE, String.class)).thenReturn(Optional.of(caseListHearingDate)); + when(bailCaseBefore.read(LISTING_HEARING_DURATION, String.class)).thenReturn(Optional.empty()); + + PreSubmitCallbackResponse response = + caseListingHandler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback); + + assertNotNull(response); + assertEquals(bailCase, response.getData()); + verify(bailCaseBefore, times(1)).read(LISTING_EVENT, ListingEvent.class); + verify(bailCaseBefore, times(1)).read(LISTING_LOCATION, ListingHearingCentre.class); + verify(bailCaseBefore, times(1)).read(LIST_CASE_HEARING_DATE, String.class); + verify(bailCaseBefore, times(1)).read(LISTING_HEARING_DURATION, String.class); + Set expectedErrors = new HashSet<>(); + expectedErrors.add("Relisting is only available after an initial listing."); + assertEquals(response.getErrors(), expectedErrors); + } } diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppenderTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppenderTest.java index f5eb47695..66f7ab290 100644 --- a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppenderTest.java +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/DecisionTypeAppenderTest.java @@ -1,34 +1,30 @@ package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.presubmit; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.DECISION_DETAILS_DATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.DECISION_GRANTED_OR_REFUSED; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.DECISION_GRANTED_OR_REFUSED_IMA; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.DECISION_UNSIGNED_DETAILS_DATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.IS_IMA_ENABLED; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.RECORD_DECISION_TYPE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.RECORD_THE_DECISION_LIST; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.RECORD_THE_DECISION_LIST_IMA; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.RECORD_UNSIGNED_DECISION_TYPE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.RELEASE_STATUS_YES_OR_NO; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.SECRETARY_OF_STATE_YES_OR_NO; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.SS_CONSENT_DECISION; +import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.*; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage.ABOUT_TO_START; import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage.ABOUT_TO_SUBMIT; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import org.assertj.core.api.Assertions; 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.CsvSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; @@ -41,7 +37,8 @@ import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; -import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.*; +import uk.gov.hmcts.reform.bailcaseapi.domain.service.Appender; @MockitoSettings(strictness = Strictness.LENIENT) @ExtendWith(MockitoExtension.class) @@ -52,11 +49,21 @@ class DecisionTypeAppenderTest { @Mock private BailCase bailCase; @Mock + private BailCase bailCaseBefore; + @Mock private CaseDetails caseDetails; @Mock + private CaseDetails caseDetailsBefore; + @Mock private DecisionTypeAppender decisionTypeAppender; @Mock private DateProvider dateProvider; + @Mock + private Appender previousDecisionDetailsAppender; + @Mock + private Document previousSignedDecisionDocument; + @Mock + private Document previousOldSignedDecisionDocument; private final LocalDate now = LocalDate.now(); private static final String REFUSED = "refused"; @@ -67,7 +74,7 @@ class DecisionTypeAppenderTest { @BeforeEach public void setUp() { - decisionTypeAppender = new DecisionTypeAppender(dateProvider); + decisionTypeAppender = new DecisionTypeAppender(previousDecisionDetailsAppender, dateProvider); when(callback.getCaseDetails()).thenReturn(caseDetails); when(caseDetails.getCaseData()).thenReturn(bailCase); when(callback.getEvent()).thenReturn(Event.RECORD_THE_DECISION); @@ -95,6 +102,7 @@ void set_decision_type_to_refused_branch_without_ss_consent() { .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -131,6 +139,7 @@ void set_decision_type_to_refused_branch_with_ss_consent() { .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -155,6 +164,7 @@ void set_decision_type_to_refused_branch_with_ss_consent_minded_then_refused() { .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -180,6 +190,7 @@ void set_decision_type_to_granted_branch_without_ss_consent() { .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -205,6 +216,7 @@ void set_decision_type_to_granted_branch_with_ss_consent_minded_then_granted() { .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -229,6 +241,7 @@ void set_decision_type_to_conditional_grant_branch_without_ss_consent() { .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -254,6 +267,7 @@ void set_decision_type_to_conditional_grant_branch_with_ss_consent_minded_then_c .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -276,6 +290,7 @@ void set_decision_type_to_refused_under_ima_when_record_the_decision_option_sele .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -298,6 +313,7 @@ void set_decision_type_to_refused_under_ima_when_granted_or_refused_option_selec .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -320,6 +336,7 @@ void set_decision_type_to_refused_under_ima_when_refused_option_selected_as_refu .write(DECISION_DETAILS_DATE, now.toString()); verify(bailCase, times(1)) .write(DECISION_UNSIGNED_DETAILS_DATE, now.toString()); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); } @Test @@ -384,4 +401,94 @@ void should_not_allow_null_args() { } + @ParameterizedTest + @CsvSource({ + "false, true, true", + "true, false, true", + "true, true, false", + "false, false, true", + "true, false, false", + "false, true, false", + "false, false, false", + }) + void should_not_append_previous_decision_when_any_previous_decision_details_are_missing(boolean decisionDetailsDateMocked, boolean recordDecisionTypeMocked, boolean uploadSignedDecisionNoticeDocumentMocked) { + when(bailCase.read(DECISION_GRANTED_OR_REFUSED, String.class)).thenReturn(Optional.of(GRANTED)); + when(bailCase.read(RELEASE_STATUS_YES_OR_NO, YesOrNo.class)).thenReturn(Optional.of(YesOrNo.YES)); + when(bailCase.read(SECRETARY_OF_STATE_YES_OR_NO, YesOrNo.class)).thenReturn(Optional.of(YesOrNo.NO)); + when(bailCase.read(RECORD_DECISION_TYPE, String.class)).thenReturn(Optional.of(GRANTED)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + if (decisionDetailsDateMocked) { + when(bailCaseBefore.read(DECISION_DETAILS_DATE, String.class)).thenReturn(Optional.of("some-date")); + } + if (recordDecisionTypeMocked) { + when(bailCaseBefore.read(RECORD_DECISION_TYPE, String.class)).thenReturn(Optional.of("some-type")); + } + if (uploadSignedDecisionNoticeDocumentMocked) { + when(bailCaseBefore.read(UPLOAD_SIGNED_DECISION_NOTICE_DOCUMENT, Document.class)).thenReturn(Optional.of( + previousSignedDecisionDocument)); + } + decisionTypeAppender.handle(ABOUT_TO_SUBMIT, callback); + verify(bailCase, times(1)) + .write(eq(RECORD_DECISION_TYPE), any(DecisionType.class)); + verify(bailCase, times(0)).read(PREVIOUS_DECISION_DETAILS); + verify(bailCase, times(0)).write(eq(PREVIOUS_DECISION_DETAILS), any(List.class)); + } + + @Test + void should_append_previous_decision_when_previous_decision_details_present_with_no_previous_list() { + when(bailCase.read(DECISION_GRANTED_OR_REFUSED, String.class)).thenReturn(Optional.of(GRANTED)); + when(bailCase.read(RELEASE_STATUS_YES_OR_NO, YesOrNo.class)).thenReturn(Optional.of(YesOrNo.YES)); + when(bailCase.read(SECRETARY_OF_STATE_YES_OR_NO, YesOrNo.class)).thenReturn(Optional.of(YesOrNo.NO)); + when(bailCase.read(RECORD_DECISION_TYPE, String.class)).thenReturn(Optional.of(GRANTED)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(DECISION_DETAILS_DATE, String.class)).thenReturn(Optional.of("some-date")); + when(bailCaseBefore.read(RECORD_DECISION_TYPE, String.class)).thenReturn(Optional.of("some-type")); + when(bailCaseBefore.read(UPLOAD_SIGNED_DECISION_NOTICE_DOCUMENT, Document.class)).thenReturn(Optional.of(previousSignedDecisionDocument)); + + decisionTypeAppender.handle(ABOUT_TO_SUBMIT, callback); + + verify(bailCase, times(1)) + .write(RECORD_DECISION_TYPE, DecisionType.GRANTED); + verify(bailCase, times(1)).read(PREVIOUS_DECISION_DETAILS); + final PreviousDecisionDetails newPreviousDecisionDetails = new PreviousDecisionDetails( + "some-date", "some-type", previousSignedDecisionDocument); + verify(previousDecisionDetailsAppender, times(1)).append(newPreviousDecisionDetails, emptyList()); + verify(bailCase, times(1)).write(eq(PREVIOUS_DECISION_DETAILS), any(List.class)); + verify(bailCase, times(1)).clear(UPLOAD_SIGNED_DECISION_NOTICE_DOCUMENT); + } + + @Test + void should_append_previous_decision_when_previous_decision_details_present_with_previous_decision_details() { + when(bailCase.read(DECISION_GRANTED_OR_REFUSED, String.class)).thenReturn(Optional.of(GRANTED)); + when(bailCase.read(RELEASE_STATUS_YES_OR_NO, YesOrNo.class)).thenReturn(Optional.of(YesOrNo.YES)); + when(bailCase.read(SECRETARY_OF_STATE_YES_OR_NO, YesOrNo.class)).thenReturn(Optional.of(YesOrNo.NO)); + when(bailCase.read(RECORD_DECISION_TYPE, String.class)).thenReturn(Optional.of(GRANTED)); + when(callback.getCaseDetailsBefore()).thenReturn(Optional.of(caseDetailsBefore)); + when(caseDetailsBefore.getCaseData()).thenReturn(bailCaseBefore); + when(bailCaseBefore.read(DECISION_DETAILS_DATE, String.class)).thenReturn(Optional.of("some-date")); + when(bailCaseBefore.read(RECORD_DECISION_TYPE, String.class)).thenReturn(Optional.of("some-type")); + when(bailCaseBefore.read(UPLOAD_SIGNED_DECISION_NOTICE_DOCUMENT, Document.class)).thenReturn(Optional.of(previousSignedDecisionDocument)); + List storedPrevDecisionDetails = + List.of(new PreviousDecisionDetails( + "some-old-date", + "some-old-type", + previousOldSignedDecisionDocument)); + List> idValueStoredPrevDecisionDetails = new ArrayList<>(); + idValueStoredPrevDecisionDetails.add(new IdValue<>("1", storedPrevDecisionDetails.get(0))); + when(bailCase.read(PREVIOUS_DECISION_DETAILS)).thenReturn(Optional.of(idValueStoredPrevDecisionDetails)); + + decisionTypeAppender.handle(ABOUT_TO_SUBMIT, callback); + + verify(bailCase, times(1)) + .write(RECORD_DECISION_TYPE, DecisionType.GRANTED); + verify(bailCase, times(1)).read(PREVIOUS_DECISION_DETAILS); + final PreviousDecisionDetails newPreviousDecisionDetails = new PreviousDecisionDetails( + "some-date", "some-type", previousSignedDecisionDocument); + verify(previousDecisionDetailsAppender, times(1)).append(newPreviousDecisionDetails, idValueStoredPrevDecisionDetails); + verify(bailCase, times(1)).write(eq(PREVIOUS_DECISION_DETAILS), any(List.class)); + verify(bailCase, times(1)).clear(UPLOAD_SIGNED_DECISION_NOTICE_DOCUMENT); + } + } diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadHearingRecordingDocumentsMidEventTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadHearingRecordingDocumentsMidEventTest.java new file mode 100644 index 000000000..e2429ae4f --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadHearingRecordingDocumentsMidEventTest.java @@ -0,0 +1,120 @@ +package uk.gov.hmcts.reform.bailcaseapi.domain.handlers.presubmit; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.*; +import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.HEARING_RECORDING_DOCUMENTS; + +import java.util.List; +import java.util.Optional; + +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.bailcaseapi.domain.entities.BailCase; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.HearingRecordingDocument; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.CaseDetails; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.Event; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.Callback; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.Document; + +@ExtendWith(MockitoExtension.class) +@SuppressWarnings("unchecked") +class UploadHearingRecordingDocumentsMidEventTest { + + @Mock + private Callback callback; + @Mock + private CaseDetails caseDetails; + @Mock + private BailCase bailCase; + + private UploadHearingRecordingDocumentsMidEvent handler; + + @BeforeEach + public void setUp() { + handler = new UploadHearingRecordingDocumentsMidEvent(); + } + + @Test + void should_return_error_when_non_mp3_file_is_uploaded() { + + List> hearingRecordingDocuments = + List.of( + new IdValue<>("1", new HearingRecordingDocument( + new Document("http://example.com/document.pdf", "document.pdf", "document.pdf", "hash"), "Some description")) + ); + + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(callback.getEvent()).thenReturn(Event.UPLOAD_HEARING_RECORDING); + when(caseDetails.getCaseData()).thenReturn(bailCase); + when(bailCase.read(HEARING_RECORDING_DOCUMENTS)).thenReturn(Optional.of(hearingRecordingDocuments)); + + PreSubmitCallbackResponse response = handler.handle(PreSubmitCallbackStage.MID_EVENT, callback); + + assertEquals(1, response.getErrors().size()); + assertTrue(response.getErrors().contains("All documents must be an mp3 file")); + + verify(bailCase, times(1)).read(HEARING_RECORDING_DOCUMENTS); + } + + + @Test + void should_allow_upload_when_all_files_are_mp3() { + + List> hearingRecordingDocuments = + List.of( + new IdValue<>("1", new HearingRecordingDocument( + new Document("http://example.com/file.mp3", "document.mp3/binary", "docuument.mp3", "hash"), "Some description")) + ); + + when(callback.getCaseDetails()).thenReturn(caseDetails); + when(callback.getEvent()).thenReturn(Event.UPLOAD_HEARING_RECORDING); + when(caseDetails.getCaseData()).thenReturn(bailCase); + when(bailCase.read(HEARING_RECORDING_DOCUMENTS)).thenReturn(Optional.of(hearingRecordingDocuments)); + + PreSubmitCallbackResponse response = handler.handle(PreSubmitCallbackStage.MID_EVENT, callback); + + assertEquals(0, response.getErrors().size()); + + verify(bailCase, times(1)).read(HEARING_RECORDING_DOCUMENTS); + } + + @Test + void should_throw_exception_when_callback_cannot_be_handled() { + + assertThatThrownBy(() -> handler.handle(PreSubmitCallbackStage.ABOUT_TO_SUBMIT, callback)) + .isExactlyInstanceOf(IllegalStateException.class) + .hasMessage("Cannot handle callback"); + + assertThatThrownBy(() -> handler.handle(PreSubmitCallbackStage.ABOUT_TO_START, callback)) + .isExactlyInstanceOf(IllegalStateException.class) + .hasMessage("Cannot handle callback"); + } + + @Test + void should_not_allow_null_arguments() { + + assertThatThrownBy(() -> handler.canHandle(null, callback)) + .hasMessage("callbackStage must not be null") + .isExactlyInstanceOf(NullPointerException.class); + + assertThatThrownBy(() -> handler.canHandle(PreSubmitCallbackStage.MID_EVENT, null)) + .hasMessage("callback must not be null") + .isExactlyInstanceOf(NullPointerException.class); + + assertThatThrownBy(() -> handler.handle(null, callback)) + .hasMessage("callbackStage must not be null") + .isExactlyInstanceOf(NullPointerException.class); + + assertThatThrownBy(() -> handler.handle(PreSubmitCallbackStage.MID_EVENT, null)) + .hasMessage("callback must not be null") + .isExactlyInstanceOf(NullPointerException.class); + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandlerTest.java b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandlerTest.java index 822031bd2..a3067a537 100644 --- a/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandlerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/bailcaseapi/domain/handlers/presubmit/UploadSignedDecisionNoticeHandlerTest.java @@ -6,9 +6,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.OUTCOME_DATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.OUTCOME_STATE; -import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.TRIBUNAL_DOCUMENTS_WITH_METADATA; +import static uk.gov.hmcts.reform.bailcaseapi.domain.entities.BailCaseFieldDefinition.*; import java.time.LocalDateTime; import java.util.ArrayList; @@ -36,6 +34,7 @@ import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackResponse; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.callback.PreSubmitCallbackStage; import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.IdValue; +import uk.gov.hmcts.reform.bailcaseapi.domain.entities.ccd.field.YesOrNo; @MockitoSettings(strictness = Strictness.LENIENT) @ExtendWith(MockitoExtension.class) @@ -79,7 +78,6 @@ public void setUp() { when(unsignedDecisionNoticeMetadata1.getTag()).thenReturn(DocumentTag.BAIL_DECISION_UNSIGNED); when(tribunalDocument1.getTag()).thenReturn(DocumentTag.UPLOAD_DOCUMENT); when(tribunalDocument2.getTag()).thenReturn(DocumentTag.BAIL_SUBMISSION); - } @Test @@ -104,6 +102,8 @@ void should_add_outcome_date_state_and_remove_unsigned_doc_from_tribunal() { .write(TRIBUNAL_DOCUMENTS_WITH_METADATA, tribunalDocumentsWithoutUnSignedDoc); verify(bailCase).write(OUTCOME_DATE, nowWithTime.toString()); verify(bailCase, times(1)).write(OUTCOME_STATE, State.DECISION_DECIDED); + verify(bailCase, times(1)).write(HAS_BEEN_RELISTED, YesOrNo.NO); + verify(bailCase, times(1)).clear(DECISION_UNSIGNED_DOCUMENT); } @Test @@ -124,6 +124,7 @@ void should_handle_when_tribunal_collection_not_contains_unsigned_document() { .write(TRIBUNAL_DOCUMENTS_WITH_METADATA, tribunalDocuments); verify(bailCase).write(OUTCOME_DATE, nowWithTime.toString()); verify(bailCase, times(1)).write(OUTCOME_STATE, State.DECISION_DECIDED); + verify(bailCase, times(1)).write(HAS_BEEN_RELISTED, YesOrNo.NO); } @Test @@ -142,6 +143,7 @@ void should_handle_when_tribunal_collection_is_empty() { .write(TRIBUNAL_DOCUMENTS_WITH_METADATA, tribunalDocuments); verify(bailCase).write(OUTCOME_DATE, nowWithTime.toString()); verify(bailCase, times(1)).write(OUTCOME_STATE, State.DECISION_DECIDED); + verify(bailCase, times(1)).write(HAS_BEEN_RELISTED, YesOrNo.NO); } @Test @@ -155,7 +157,6 @@ void should_get_dispatch_priority_as_latest() { @Test void handling_should_throw_if_cannot_actually_handle() { - assertThatThrownBy( () -> uploadSignedDecisionNoticeHandler.handle(PreSubmitCallbackStage.ABOUT_TO_START, callback)) .hasMessage("Cannot handle callback")