diff --git a/src/main/java/uk/gov/hmcts/cmc/claimstore/jobs/cron/ScheduleCaseStayedStateTransition.java b/src/main/java/uk/gov/hmcts/cmc/claimstore/jobs/cron/ScheduleCaseStayedStateTransition.java new file mode 100644 index 0000000000..5fdcfe9af8 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/cmc/claimstore/jobs/cron/ScheduleCaseStayedStateTransition.java @@ -0,0 +1,36 @@ +package uk.gov.hmcts.cmc.claimstore.jobs.cron; + +import lombok.Getter; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.cmc.claimstore.services.ccd.callbacks.caseworker.transfercase.TransferCaseStayedService; +import uk.gov.hmcts.cmc.scheduler.model.CronJob; + +@Component +@Getter +@DisallowConcurrentExecution +public class ScheduleCaseStayedStateTransition implements CronJob { + + @Value("${schedule.transfer-stayed-claims}") + private String cronExpression; + + private TransferCaseStayedService caseStayedTransferService; + + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + try { + caseStayedTransferService.findCasesForTransfer(); + } catch (Exception e) { + throw new JobExecutionException(e); + } + } + + @Autowired + public void setCaseStayedTransferService(TransferCaseStayedService caseStayedTransferService) { + this.caseStayedTransferService = caseStayedTransferService; + } +} diff --git a/src/main/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataService.java b/src/main/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataService.java index e8d2edeb7d..e6d5100129 100644 --- a/src/main/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataService.java +++ b/src/main/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataService.java @@ -55,6 +55,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; import java.util.Optional; import static java.util.Objects.requireNonNull; @@ -915,6 +916,46 @@ public CaseDetails update(String authorisation, CCDCase ccdCase, CaseEvent caseE } } + public CaseDetails caseTransferUpdate(String authorisation, CCDCase ccdCase, CaseEvent caseEvent) { + try { + UserDetails userDetails = userService.getUserDetails(authorisation); + Long caseId = ccdCase.getId(); + EventRequestData eventRequestData = EventRequestData.builder() + .userId(userDetails.getId()) + .jurisdictionId(JURISDICTION_ID) + .caseTypeId(CASE_TYPE_ID) + .eventId(caseEvent.getValue()) + .ignoreWarning(true) + .build(); + + StartEventResponse startEventResponse = startUpdate( + authorisation, + eventRequestData, + caseId, + isRepresented(userDetails) + ); + + CaseDataContent caseDataContent = CaseDataContentBuilder.build( + startEventResponse, + CMC_CASE_UPDATE_SUMMARY, + SUBMITTING_CMC_CASE_UPDATE_DESCRIPTION, + ccdCase + ); + + return submitUpdate(authorisation, eventRequestData, caseDataContent, caseId, + isRepresented(userDetails)); + } catch (Exception exception) { + logger.error("Error communicating with CCD API"); + throw new CoreCaseDataStoreException( + String.format( + "Failed updating claim in CCD store for claim %s on event %s", + ccdCase.getPreviousServiceCaseReference(), + caseEvent + ), exception + ); + } + } + private StartEventResponse startUpdate( String authorisation, EventRequestData eventRequestData, @@ -1368,4 +1409,33 @@ public Claim saveBreathingSpaceDetails(Claim claim, BreathingSpace breathingSpac } return caseDetailsConverter.extractClaim(update(authorisation, ccdCase, CaseEvent.BREATHING_SPACE_LIFTED)); } + + public List searchCases(String authorisation, + String userId, + Map searchCriteria) { + + return coreCaseDataApi.searchForCaseworker( + authorisation, + authTokenGenerator.generate(), + userId, + JURISDICTION_ID, + CASE_TYPE_ID, + searchCriteria + ); + } + + public Integer getPaginationInfo(String authorisation, + String userId, + Map searchCriteria + ) { + return coreCaseDataApi.getPaginationInfoForSearchForCaseworkers( + authorisation, + authTokenGenerator.generate(), + userId, + JURISDICTION_ID, + CASE_TYPE_ID, + searchCriteria + ).getTotalPagesCount(); + } + } diff --git a/src/main/java/uk/gov/hmcts/cmc/claimstore/services/ccd/callbacks/caseworker/transfercase/TransferCaseStayedService.java b/src/main/java/uk/gov/hmcts/cmc/claimstore/services/ccd/callbacks/caseworker/transfercase/TransferCaseStayedService.java new file mode 100644 index 0000000000..e103b980e0 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/cmc/claimstore/services/ccd/callbacks/caseworker/transfercase/TransferCaseStayedService.java @@ -0,0 +1,151 @@ +package uk.gov.hmcts.cmc.claimstore.services.ccd.callbacks.caseworker.transfercase; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONArray; +import org.springframework.stereotype.Service; +import uk.gov.hmcts.cmc.ccd.domain.CCDCase; +import uk.gov.hmcts.cmc.ccd.domain.CaseEvent; +import uk.gov.hmcts.cmc.claimstore.models.idam.User; +import uk.gov.hmcts.cmc.claimstore.requests.idam.IdamApi; +import uk.gov.hmcts.cmc.claimstore.services.UserService; +import uk.gov.hmcts.cmc.claimstore.services.ccd.CoreCaseDataService; +import uk.gov.hmcts.cmc.domain.models.ClaimState; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@AllArgsConstructor +@Service +@Slf4j +public class TransferCaseStayedService { + + private final CoreCaseDataService coreCaseDataService; + private final UserService userService; + private final IdamApi idamApi; + + private static final int MAX_ALLOWED_PAGE_PROCESS = 1000; + + public void findCasesForTransfer() { + + User user = userService.authenticateAnonymousCaseWorker(); + String authorisation = user.getAuthorisation(); + String userId = idamApi.retrieveUserDetails(authorisation).getId(); + + Integer numberOfPages = getNumberOfPages(authorisation, userId); + int pageNumber = 1; + + log.info("Comparing cases to update into ccd"); + + do { + compareCases(authorisation, userId, pageNumber); + pageNumber++; + if (pageNumber == (MAX_ALLOWED_PAGE_PROCESS + 1)) { + break; + } + } while (pageNumber <= numberOfPages); + } + + public void compareCases(String authorisation, String userId, Integer pageNumber) { + Integer numberOfPages = getNumberOfPages(authorisation, userId); + + var listOfCases = listCasesWithDeadLIne( + authorisation, + userId, + pageNumber <= numberOfPages && pageNumber > 0 + ? pageNumber : 1 + ); + + LocalDate currentDate = LocalDate.now(); + + JSONArray listOfCasesJson = !listOfCases.isEmpty() + ? new JSONArray(listOfCases) : null; + + for (int caseIndex = 0; caseIndex < listOfCases.size(); caseIndex++) { + String intentionToProceedDeadline = null; + Long caseId = null; + + if (listOfCasesJson.get(caseIndex) != null + && !listOfCasesJson.isEmpty() + && listOfCasesJson != null + ) { + + intentionToProceedDeadline = listOfCasesJson + .getJSONObject(caseIndex) + .get("intentionToProceedDeadline").toString(); + + caseId = Long.parseLong( + listOfCasesJson + .getJSONObject(caseIndex) + .get("id").toString()); + } + + boolean currentDateAfter = intentionToProceedDeadline != null && currentDate + .isAfter(LocalDate + .parse(intentionToProceedDeadline)); + + CCDCase ccdStayClaim = caseId != null ? CCDCase.builder() + .id(caseId) + .build() : null; + + if (currentDateAfter && ccdStayClaim != null) { + coreCaseDataService.caseTransferUpdate( + authorisation, + ccdStayClaim, + CaseEvent.STAY_CLAIM + ); + } + } + } + + private Integer getNumberOfPages(String authorisation, String userId) { + return coreCaseDataService.getPaginationInfo( + authorisation, + userId, + getSearchCriteria(false, null) + ); + } + + private Map getSearchCriteria(boolean isSearchingPerPageEnabled, Integer pageNumber) { + Map searchCriteria = new HashMap<>(); + + if (isSearchingPerPageEnabled && pageNumber != null) { + searchCriteria.put("page", pageNumber.toString()); + } + + searchCriteria.put("sortDirection", "asc"); + searchCriteria.put("state", ClaimState.OPEN.getValue()); + + return searchCriteria; + } + + private List listCasesWithDeadLIne(String authorisation, String userId, Integer pageNumber) { + var searchedCases = new ArrayList<>(coreCaseDataService.searchCases( + authorisation, + userId, + getSearchCriteria( + true, + pageNumber + ) + )); + + List claimsList = new ArrayList<>(); + List generatedList = new ArrayList<>(); + int index = -1; + + for (var searchedCase : searchedCases) { + Map searchedCaseDataMap = searchedCase.getData(); + index++; + claimsList.add(searchedCaseDataMap); + for (Map.Entry entry : searchedCaseDataMap.entrySet()) { + if (entry.getKey().contains("intentionToProceedDeadline")) { + generatedList.add(claimsList.get(index)); + } + } + } + return generatedList; + } +} diff --git a/src/main/java/uk/gov/hmcts/cmc/claimstore/utils/CaseDataContentBuilder.java b/src/main/java/uk/gov/hmcts/cmc/claimstore/utils/CaseDataContentBuilder.java index f3f7188965..3f93396cfa 100644 --- a/src/main/java/uk/gov/hmcts/cmc/claimstore/utils/CaseDataContentBuilder.java +++ b/src/main/java/uk/gov/hmcts/cmc/claimstore/utils/CaseDataContentBuilder.java @@ -1,5 +1,6 @@ package uk.gov.hmcts.cmc.claimstore.utils; +import uk.gov.hmcts.cmc.ccd.domain.CCDCase; import uk.gov.hmcts.reform.ccd.client.model.CaseDataContent; import uk.gov.hmcts.reform.ccd.client.model.Event; import uk.gov.hmcts.reform.ccd.client.model.StartEventResponse; @@ -34,6 +35,23 @@ public static CaseDataContent build( .build(); } + public static CaseDataContent build( + StartEventResponse startEventResponse, + String eventSummary, + String eventDescription, + CCDCase ccdCase) { + + return CaseDataContent.builder() + .eventToken(startEventResponse.getToken()) + .event(Event.builder() + .id(startEventResponse.getEventId()) + .summary(eventSummary) + .description(eventDescription) + .build()) + .data(ccdCase) + .build(); + } + private static HashMap initHashMap(StartEventResponse startEventResponse) { return hasCaseData(startEventResponse) ? new HashMap<>(startEventResponse.getCaseDetails().getData()) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 08577e6486..83fec7a7eb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -175,6 +175,7 @@ schedule: transfer-claims: "" issue-created-claims: "0 0 8,17,23 ? * * *" close-hwf-claims-in-awaiting-state: "${SCHEDULE_CLOSE_HWF_CLAIMS_IN_AWAITING_STATE:}" + transfer-stayed-claims: "0 0 23,2,5 ? * * *" state-transition: waiting-transfer: "" stay-claim: "" diff --git a/src/test/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataServiceTest.java b/src/test/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataServiceTest.java index d151b2149c..9f91f419cd 100644 --- a/src/test/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataServiceTest.java +++ b/src/test/java/uk/gov/hmcts/cmc/claimstore/services/ccd/CoreCaseDataServiceTest.java @@ -50,6 +50,7 @@ import uk.gov.hmcts.reform.ccd.client.model.CaseDataContent; import uk.gov.hmcts.reform.ccd.client.model.CaseDetails; import uk.gov.hmcts.reform.ccd.client.model.EventRequestData; +import uk.gov.hmcts.reform.ccd.client.model.PaginatedSearchMetadata; import uk.gov.hmcts.reform.ccd.client.model.StartEventResponse; import java.math.BigInteger; @@ -974,4 +975,92 @@ public void saveUpdateRepresentedClaimThrowsException() { assertThatExceptionOfType(CoreCaseDataStoreException.class); } } + + @Test + public void coreCaseDataApiShouldReturnPaginationInfoWhenInvoked() { + var pagination = new PaginatedSearchMetadata(); + pagination.setTotalPagesCount(1); + pagination.getTotalPagesCount(); + + when(coreCaseDataApi.getPaginationInfoForSearchForCaseworkers( + eq(AUTHORISATION), + eq(AUTH_TOKEN), + eq(USER_DETAILS.getId()), + eq(JURISDICTION_ID), + eq(CASE_TYPE_ID), + eq( + Map.of("key", "value") + ) + )).thenReturn(pagination); + + Integer expected = 1; + + var actual = service.getPaginationInfo( + AUTHORISATION, + USER_DETAILS.getId(), + Map.of( + "key", "value" + )); + + verify(coreCaseDataApi, atLeastOnce()).getPaginationInfoForSearchForCaseworkers( + AUTHORISATION, + AUTH_TOKEN, + USER_DETAILS.getId(), + JURISDICTION_ID, + CASE_TYPE_ID, + Map.of("key", "value") + ); + assertEquals(expected, actual); + + } + + @Test + public void caseTransferUpdateShouldReturnCaseDetails() { + CCDCase providedCCDCase = CCDCase.builder().id(SampleClaim.CLAIM_ID).build(); + + CaseDetails caseDetails = service.caseTransferUpdate(AUTHORISATION, providedCCDCase, CaseEvent.PART_ADMISSION); + + assertNotNull(caseDetails); + } + + @Test + public void coreCaseDataApiShouldGetSearchedCasesWhenInvoked() { + when(coreCaseDataApi.searchForCaseworker( + eq(AUTHORISATION), + eq(AUTH_TOKEN), + eq(USER_DETAILS.getId()), + eq(JURISDICTION_ID), + eq(CASE_TYPE_ID), + eq( + Map.of("key", "value")) + ) + ).thenReturn( + List.of(CaseDetails.builder() + .caseTypeId(CASE_TYPE_ID) + .jurisdiction(JURISDICTION_ID) + .build()) + ); + + var expected = List.of(CaseDetails.builder() + .caseTypeId(CASE_TYPE_ID) + .jurisdiction(JURISDICTION_ID) + .build()); + + var actual = service.searchCases( + AUTHORISATION, + USER_DETAILS.getId(), + Map.of("key", "value") + ); + + verify(coreCaseDataApi, atLeastOnce()).searchForCaseworker( + AUTHORISATION, + AUTH_TOKEN, + USER_DETAILS.getId(), + JURISDICTION_ID, + CASE_TYPE_ID, + Map.of("key", "value") + ); + + assertEquals(expected, actual); + } } diff --git a/src/test/java/uk/gov/hmcts/cmc/claimstore/services/ccd/callbacks/caseworker/transfercase/TransferCaseStayedServiceTest.java b/src/test/java/uk/gov/hmcts/cmc/claimstore/services/ccd/callbacks/caseworker/transfercase/TransferCaseStayedServiceTest.java new file mode 100644 index 0000000000..1c1a5f53d1 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/cmc/claimstore/services/ccd/callbacks/caseworker/transfercase/TransferCaseStayedServiceTest.java @@ -0,0 +1,132 @@ +package uk.gov.hmcts.cmc.claimstore.services.ccd.callbacks.caseworker.transfercase; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.cmc.ccd.domain.CCDCase; +import uk.gov.hmcts.cmc.ccd.domain.CaseEvent; +import uk.gov.hmcts.cmc.claimstore.models.idam.User; +import uk.gov.hmcts.cmc.claimstore.models.idam.UserDetails; +import uk.gov.hmcts.cmc.claimstore.requests.idam.IdamApi; +import uk.gov.hmcts.cmc.claimstore.services.UserService; +import uk.gov.hmcts.cmc.claimstore.services.ccd.CoreCaseDataService; +import uk.gov.hmcts.cmc.claimstore.services.ccd.Role; +import uk.gov.hmcts.cmc.claimstore.services.notifications.fixtures.SampleUserDetails; +import uk.gov.hmcts.cmc.domain.models.sampledata.SampleClaim; +import uk.gov.hmcts.reform.ccd.client.model.CaseDetails; + +import java.util.List; +import java.util.Map; + +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class TransferCaseStayedServiceTest { + + protected static final String BEARER_TOKEN = "Bearer letmein"; + + private static final UserDetails USER_DETAILS = SampleUserDetails.builder() + .withRoles(Role.CASEWORKER.getRole()) + .withUserId(SampleClaim.USER_ID).build(); + + private static final User CASEWORKER = new User(BEARER_TOKEN, SampleUserDetails.builder() + .withRoles(Role.CASEWORKER.getRole()).build()); + + private static final Map TRUE_SORT_DIRECTION_MAP = Map.of( + "sortDirection", "asc", + "page", "1", + "state", "open" + ); + + private static final Map SORT_DIRECTION_MAP = Map.of( + "sortDirection", "asc", + "state", "open" + ); + + private static final Map INTENTION_TO_PROCEED = Map.of( + "intentionToProceedDeadline", "2021-12-12", + "id", 1L + ); + + @Mock + private IdamApi idamApi; + + @Mock + private UserService userService; + + @Mock + private CoreCaseDataService coreCaseDataService; + + @InjectMocks + private TransferCaseStayedService service; + + @Test + public void findCasesForTransferShouldInvokeCorrectly() { + + when(userService.authenticateAnonymousCaseWorker()).thenReturn(CASEWORKER); + when(idamApi.retrieveUserDetails(BEARER_TOKEN)).thenReturn(USER_DETAILS); + + when(coreCaseDataService.getPaginationInfo( + BEARER_TOKEN, + USER_DETAILS.getId(), + SORT_DIRECTION_MAP + ) + ).thenReturn(1); + + service.findCasesForTransfer(); + + verify(userService, atLeastOnce()).authenticateAnonymousCaseWorker(); + verify(idamApi, atLeastOnce()).retrieveUserDetails(BEARER_TOKEN); + + } + + @Test + public void compareCasesShouldProduceCorrectResultsWhenInvoked() { + + var ccdStayClaim = CCDCase.builder() + .id(1L) + .build(); + + CaseDetails caseDetails = CaseDetails.builder() + .data(INTENTION_TO_PROCEED) + .build(); + + when(coreCaseDataService.searchCases( + BEARER_TOKEN, + USER_DETAILS.getId(), + TRUE_SORT_DIRECTION_MAP + )).thenReturn( + List.of( + caseDetails + )); + + when(coreCaseDataService.caseTransferUpdate( + BEARER_TOKEN, + ccdStayClaim, + CaseEvent.STAY_CLAIM + )).thenReturn( + caseDetails + ); + + service.compareCases(BEARER_TOKEN, USER_DETAILS.getId(), 1); + + verify(coreCaseDataService, atLeastOnce()) + .caseTransferUpdate( + BEARER_TOKEN, + ccdStayClaim, + CaseEvent.STAY_CLAIM + ); + + verify(coreCaseDataService, atLeastOnce()) + .searchCases( + BEARER_TOKEN, + USER_DETAILS.getId(), + TRUE_SORT_DIRECTION_MAP + ); + + } +}