diff --git a/src/main/java/org/ilgcc/app/data/TransmissionRepository.java b/src/main/java/org/ilgcc/app/data/TransmissionRepository.java index cac7f183..b4d0038e 100644 --- a/src/main/java/org/ilgcc/app/data/TransmissionRepository.java +++ b/src/main/java/org/ilgcc/app/data/TransmissionRepository.java @@ -2,13 +2,22 @@ import formflow.library.data.Submission; import java.util.List; -import java.util.Optional; import java.util.UUID; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @Repository public interface TransmissionRepository extends JpaRepository { - + @Query(value = + "SELECT s FROM Submission s " + + "LEFT JOIN Transmission t ON t.submissionId = s " + + "WHERE s.submittedAt IS NOT NULL " + + "AND s.flow = 'gcc' " + + "AND t.transmissionId IS NULL " + + "ORDER BY s.updatedAt ASC") + + List findSubmissionsWithoutTransmission(); + List findAllBySubmissionId(Submission submission); } diff --git a/src/main/java/org/ilgcc/app/data/TransmissionRepositoryService.java b/src/main/java/org/ilgcc/app/data/TransmissionRepositoryService.java index 623edb51..132da65f 100644 --- a/src/main/java/org/ilgcc/app/data/TransmissionRepositoryService.java +++ b/src/main/java/org/ilgcc/app/data/TransmissionRepositoryService.java @@ -12,9 +12,9 @@ @Service @Transactional public class TransmissionRepositoryService { - + TransmissionRepository transmissionRepository; - + public TransmissionRepositoryService(TransmissionRepository transmissionRepository) { this.transmissionRepository = transmissionRepository; } @@ -22,7 +22,7 @@ public TransmissionRepositoryService(TransmissionRepository transmissionReposito public Transmission save(Transmission transmission) { return transmissionRepository.save(transmission); } - + public Transmission findById(UUID id) { return this.transmissionRepository.findById(id).orElse(null); } @@ -30,7 +30,11 @@ public Transmission findById(UUID id) { public List findAllBySubmissionId(Submission submission) { return this.transmissionRepository.findAllBySubmissionId(submission); } - + + public List findSubmissionsWithoutTransmission(){ + return this.transmissionRepository.findSubmissionsWithoutTransmission(); + } + public void updateStatus(Transmission transmission, TransmissionStatus status) { transmission.setStatus(status); this.transmissionRepository.save(transmission); diff --git a/src/main/java/org/ilgcc/app/pdf/ProviderApplicationPreparer.java b/src/main/java/org/ilgcc/app/pdf/ProviderApplicationPreparer.java new file mode 100644 index 00000000..a64a0c3b --- /dev/null +++ b/src/main/java/org/ilgcc/app/pdf/ProviderApplicationPreparer.java @@ -0,0 +1,46 @@ +package org.ilgcc.app.pdf; + +import static org.ilgcc.app.utils.SubmissionUtilities.formatToStringFromLocalDate; + +import formflow.library.data.Submission; +import formflow.library.pdf.PdfMap; +import formflow.library.pdf.SingleField; +import formflow.library.pdf.SubmissionField; +import formflow.library.pdf.SubmissionFieldPreparer; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.ilgcc.app.utils.PreparerUtilities; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +@ConditionalOnProperty(name="il-gcc.dts.wait-for-provider-response", havingValue = "true") +@Component +public class ProviderApplicationPreparer implements SubmissionFieldPreparer { + + @Override + public Map prepareSubmissionFields(Submission submission, PdfMap pdfMap) { + var results = new HashMap(); + var inputData = submission.getInputData(); + + boolean hasProviderResponse = inputData.containsKey("providerResponseSubmissionId"); + + if(!hasProviderResponse){ + results.put("providerNameCorporate", + new SingleField("providerNameCorporate", inputData.getOrDefault("familyIntendedProviderName", "").toString(), null)); + results.put("providerPhoneNumber", + new SingleField("providerPhoneNumber", inputData.getOrDefault("familyIntendedProviderPhoneNumber", "").toString(), null)); + results.put("providerEmail", + new SingleField("providerEmail", inputData.getOrDefault("familyIntendedProviderEmail", "").toString(), null)); + results.put("providerResponse", + new SingleField("providerResponse", "No response from provider", null)); + } + + return results; + } +} diff --git a/src/main/java/org/ilgcc/app/submission/actions/CheckClientSubmissionForProvider.java b/src/main/java/org/ilgcc/app/submission/actions/CheckClientSubmissionForProvider.java index 69bd4f72..e628ef4f 100644 --- a/src/main/java/org/ilgcc/app/submission/actions/CheckClientSubmissionForProvider.java +++ b/src/main/java/org/ilgcc/app/submission/actions/CheckClientSubmissionForProvider.java @@ -1,18 +1,20 @@ package org.ilgcc.app.submission.actions; -import static java.time.temporal.ChronoUnit.DAYS; import formflow.library.config.submission.Action; import formflow.library.data.Submission; import formflow.library.data.SubmissionRepositoryService; import jakarta.servlet.http.HttpSession; import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Locale; import java.util.Optional; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.ilgcc.app.utils.ChildCareProvider; -import org.ilgcc.app.utils.ProviderSubmissionUtilities; +import static org.ilgcc.app.utils.ProviderSubmissionUtilities.providerApplicationHasExpired; import org.ilgcc.app.utils.enums.ProviderSubmissionStatus; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; @@ -61,12 +63,12 @@ public void run(Submission submission) { if (submittedAtDate == null) { log.warn("No submittedAt date found for submission " + submission.getId()); } - - LocalDate todaysDate = LocalDate.now(); - if (submittedAtDate != null && DAYS.between(ProviderSubmissionUtilities.threeBusinessDaysFromSubmittedAtDate(submittedAtDate), todaysDate) > 0) { + ZoneId chicagoTimeZone = ZoneId.of("America/Chicago"); + ZonedDateTime todaysDate = OffsetDateTime.now().atZoneSameInstant(chicagoTimeZone); + if (providerApplicationHasExpired(clientSubmissionInfo, todaysDate)) { httpSession.setAttribute(SESSION_KEY_CLIENT_SUBMISSION_STATUS, ProviderSubmissionStatus.EXPIRED.name()); } else { - boolean hasResponse = false; + boolean hasResponse = false; if (clientSubmissionInfo.getInputData().get("providerResponseSubmissionId") != null) { // The above value should be set on the client submission whenever a provider first submits // their response. diff --git a/src/main/java/org/ilgcc/app/submission/actions/SendUploadedFileToDocumentTransferService.java b/src/main/java/org/ilgcc/app/submission/actions/SendUploadedFileToDocumentTransferService.java index 543e0c1a..6b0e98ae 100644 --- a/src/main/java/org/ilgcc/app/submission/actions/SendUploadedFileToDocumentTransferService.java +++ b/src/main/java/org/ilgcc/app/submission/actions/SendUploadedFileToDocumentTransferService.java @@ -1,16 +1,12 @@ package org.ilgcc.app.submission.actions; -import com.google.common.io.Files; import formflow.library.config.submission.Action; import formflow.library.data.Submission; -import formflow.library.data.UserFile; import formflow.library.data.UserFileRepositoryService; -import java.util.List; -import java.util.concurrent.CompletableFuture; import lombok.extern.slf4j.Slf4j; import org.ilgcc.app.file_transfer.S3PresignService; -import org.ilgcc.app.utils.enums.FileNameUtility; +import org.ilgcc.jobs.EnqueueDocumentTransfer; import org.ilgcc.jobs.UploadedDocumentTransmissionJob; import org.springframework.beans.factory.annotation.Value; @@ -23,41 +19,27 @@ public class SendUploadedFileToDocumentTransferService implements Action { private final UserFileRepositoryService userFileRepositoryService; private final UploadedDocumentTransmissionJob uploadedDocumentTransmissionJob; private final S3PresignService s3PresignService; - private final String enableBackgroundJobs; + private final String waitForProviderResponseFlag; + + private final EnqueueDocumentTransfer enqueueDocumentTransfer; public SendUploadedFileToDocumentTransferService(UserFileRepositoryService userFileRepositoryService, - UploadedDocumentTransmissionJob uploadedDocumentTransmissionJob, S3PresignService s3PresignService, - @Value("${il-gcc.dts.enable-background-jobs}") String enableBackgroundJobs) { + UploadedDocumentTransmissionJob uploadedDocumentTransmissionJob, S3PresignService s3PresignService, EnqueueDocumentTransfer enqueueDocumentTransfer, + @Value("${il-gcc.dts.enable-background-jobs}") String enableBackgroundJobs, + @Value("${il-gcc.dts.wait-for-provider-response}") String waitForProviderResponseFlag) { this.userFileRepositoryService = userFileRepositoryService; this.uploadedDocumentTransmissionJob = uploadedDocumentTransmissionJob; this.s3PresignService = s3PresignService; + this.enqueueDocumentTransfer = enqueueDocumentTransfer; this.enableBackgroundJobs = enableBackgroundJobs; + this.waitForProviderResponseFlag=waitForProviderResponseFlag; } @Override public void run(Submission submission) { - if (!enableBackgroundJobs.equals("false")) { - log.info("Sending uploaded files to document transfer service for submission with ID: {}", submission.getId()); - List userFiles = userFileRepositoryService.findAllBySubmission(submission); - if (!userFiles.isEmpty()) { - for (int i = 0; i < userFiles.size(); i++) { - UserFile userFile = userFiles.get(i); - String fileExtension = Files.getFileExtension(userFile.getOriginalName()); - String fileName = FileNameUtility.getFileNameForUploadedDocument(submission, i + 1, userFiles.size(), fileExtension); - CompletableFuture scannedAndCleanFuture = s3PresignService.isObjectScannedAndClean(userFile.getRepositoryPath()); - int currentFileIndex = i; - scannedAndCleanFuture.thenAccept(scannedAndClean -> { - if (scannedAndClean) { - log.info("Sending file {} of {} to document transfer service for submission with ID: {}", currentFileIndex + 1, userFiles.size(), submission.getId()); - uploadedDocumentTransmissionJob.enqueueUploadedDocumentTransmissionJob(submission, userFile, fileName); - } - }).exceptionally(e -> { - log.error("There was an error when attempting to send uploaded file with id: {} in submission with id: {} to the document transfer service. It's possible the file had a virus, or could not be scanned.", userFile.getFileId(), submission.getId(), e); - return null; - }); - } - } + if (enableBackgroundJobs.equals("true") && waitForProviderResponseFlag.equals("false")) { + enqueueDocumentTransfer.enqueueUploadedDocumentBySubmission(userFileRepositoryService, uploadedDocumentTransmissionJob, s3PresignService, submission); } } } diff --git a/src/main/java/org/ilgcc/app/submission/actions/UploadSubmissionToS3.java b/src/main/java/org/ilgcc/app/submission/actions/UploadSubmissionToS3.java index fe773b72..0a706150 100644 --- a/src/main/java/org/ilgcc/app/submission/actions/UploadSubmissionToS3.java +++ b/src/main/java/org/ilgcc/app/submission/actions/UploadSubmissionToS3.java @@ -5,18 +5,13 @@ import formflow.library.data.Submission; import formflow.library.file.CloudFileRepository; import formflow.library.pdf.PdfService; -import java.util.concurrent.CompletableFuture; import lombok.extern.slf4j.Slf4j; -import org.ilgcc.app.utils.ByteArrayMultipartFile; -import org.ilgcc.app.utils.SubmissionUtilities; import org.ilgcc.app.utils.enums.FileNameUtility; +import org.ilgcc.jobs.EnqueueDocumentTransfer; import org.ilgcc.jobs.PdfTransmissionJob; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; @Slf4j @Component @@ -24,53 +19,33 @@ public class UploadSubmissionToS3 implements Action { private final PdfService pdfService; private final CloudFileRepository cloudFileRepository; - + private final PdfTransmissionJob pdfTransmissionJob; - private final String CONTENT_TYPE = "application/pdf"; - + + private final EnqueueDocumentTransfer enqueueDocumentTransfer; + private final String enableBackgroundJobs; + private final String waitForProviderResponseFlag; public UploadSubmissionToS3(PdfService pdfService, CloudFileRepository cloudFileRepository, PdfTransmissionJob pdfTransmissionJob, - @Value("${il-gcc.dts.enable-background-jobs}") String enableBackgroundJobs) { + EnqueueDocumentTransfer enqueueDocumentTransfer, + @Value("${il-gcc.dts.enable-background-jobs}") String enableBackgroundJobs, + @Value("${il-gcc.dts.wait-for-provider-response}") String waitForProviderResponseFlag) { this.pdfService = pdfService; this.cloudFileRepository = cloudFileRepository; this.pdfTransmissionJob = pdfTransmissionJob; + this.enqueueDocumentTransfer = enqueueDocumentTransfer; this.enableBackgroundJobs = enableBackgroundJobs; + this.waitForProviderResponseFlag = waitForProviderResponseFlag; } @Override public void run(Submission submission) { - - try { - byte[] pdfFile = pdfService.getFilledOutPDF(submission); - String pdfFileName = String.format(FileNameUtility.getFileNameForPdf(submission)); - MultipartFile multipartFile = new ByteArrayMultipartFile(pdfFile, pdfFileName, CONTENT_TYPE); - String s3ZipPath = SubmissionUtilities.generatePdfPath(submission); - - CompletableFuture.runAsync(() -> { - try { - cloudFileRepository.upload(s3ZipPath, multipartFile); - } catch (IOException | InterruptedException e) { - log.error("Error uploading submission to S3", e); - throw new RuntimeException(e); - } - }).thenRun(() -> { - try { - if (enableBackgroundJobs.equals("true")) { - pdfTransmissionJob.enqueuePdfTransmissionJob(s3ZipPath, submission); - } - } catch (IOException e) { - log.error("An error occurred when enqueuing a job with the document transfer service.", e); - } - }).exceptionally(e -> { - log.error("Error uploading submission to S3 for submission with ID: {}", submission.getId(), e); - return null; - }); - - } catch (IOException e) { - log.error("Error uploading submission to S3 for submission with ID: {}", submission.getId(), e); + if (enableBackgroundJobs.equals("true") && waitForProviderResponseFlag.equals("false")) { + enqueueDocumentTransfer.enqueuePDFDocumentBySubmission(pdfService, cloudFileRepository, pdfTransmissionJob, + submission, FileNameUtility.getFileNameForPdf(submission)); } } } \ No newline at end of file diff --git a/src/main/java/org/ilgcc/app/utils/ProviderSubmissionUtilities.java b/src/main/java/org/ilgcc/app/utils/ProviderSubmissionUtilities.java index 9bf547fe..190a4150 100644 --- a/src/main/java/org/ilgcc/app/utils/ProviderSubmissionUtilities.java +++ b/src/main/java/org/ilgcc/app/utils/ProviderSubmissionUtilities.java @@ -1,10 +1,15 @@ package org.ilgcc.app.utils; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MINUTES; import static org.ilgcc.app.utils.SubmissionUtilities.MM_DD_YYYY; import formflow.library.data.Submission; import java.time.LocalDate; +import java.time.OffsetDateTime; import java.time.Period; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -102,8 +107,14 @@ private static String hoursRequested(Map child) { return String.join("", dateString); } - public static LocalDate threeBusinessDaysFromSubmittedAtDate(LocalDate submittedAtDate) { - Integer dayOffset = weekWithOffset.get(submittedAtDate.getDayOfWeek().toString()); - return submittedAtDate.plusDays(dayOffset); + public static ZonedDateTime threeBusinessDaysFromSubmittedAtDate(OffsetDateTime submittedAtDate) { + ZoneId chicagoTimeZone = ZoneId.of("America/Chicago"); + ZonedDateTime submissionInChicagoTime = submittedAtDate.atZoneSameInstant(chicagoTimeZone); + Integer dayOffset = weekWithOffset.get(submissionInChicagoTime.getDayOfWeek().toString()); + return submissionInChicagoTime.plusDays(dayOffset); + } + + public static boolean providerApplicationHasExpired(Submission submission, ZonedDateTime todaysDate){ + return submission.getSubmittedAt() != null && MINUTES.between(ProviderSubmissionUtilities.threeBusinessDaysFromSubmittedAtDate(submission.getSubmittedAt()), todaysDate) > 0; } } diff --git a/src/main/java/org/ilgcc/app/utils/enums/FileNameUtility.java b/src/main/java/org/ilgcc/app/utils/enums/FileNameUtility.java index dc041513..4fa88ff4 100644 --- a/src/main/java/org/ilgcc/app/utils/enums/FileNameUtility.java +++ b/src/main/java/org/ilgcc/app/utils/enums/FileNameUtility.java @@ -21,6 +21,13 @@ public static String getFileNameForPdf(Submission submission) { return String.format("%s-%s-CCAP-Application-Form.pdf", formattedApplicantName, dashFormattedSubmittedAtDate); } + public static String getFileNameForPdf(Submission submission, String suffix) { + String applicantNameLastToFirst = SubmissionUtilities.getApplicantNameLastToFirst(submission); + String formattedApplicantName = formatApplicantNameForFileName(applicantNameLastToFirst); + String dashFormattedSubmittedAtDate = SubmissionUtilities.getDashFormattedSubmittedAtDate(submission); + return String.format("%s-%s-CCAP-Application-Form-%s.pdf", formattedApplicantName, dashFormattedSubmittedAtDate, suffix); + } + public static String getFileNameForUploadedDocument(Submission submission, int fileNumber, int totalFiles, String fileExtension) { String applicantNameLastToFirst = SubmissionUtilities.getApplicantNameLastToFirst(submission); String formattedApplicantName = formatApplicantNameForFileName(applicantNameLastToFirst); diff --git a/src/main/java/org/ilgcc/jobs/EnqueueDocumentTransfer.java b/src/main/java/org/ilgcc/jobs/EnqueueDocumentTransfer.java new file mode 100644 index 00000000..89919a85 --- /dev/null +++ b/src/main/java/org/ilgcc/jobs/EnqueueDocumentTransfer.java @@ -0,0 +1,87 @@ +package org.ilgcc.jobs; + +import com.google.common.io.Files; +import formflow.library.data.Submission; +import formflow.library.data.UserFile; +import formflow.library.data.UserFileRepositoryService; +import formflow.library.file.CloudFileRepository; +import formflow.library.pdf.PdfService; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import lombok.extern.slf4j.Slf4j; +import org.ilgcc.app.file_transfer.S3PresignService; +import org.ilgcc.app.utils.ByteArrayMultipartFile; +import org.ilgcc.app.utils.SubmissionUtilities; +import org.ilgcc.app.utils.enums.FileNameUtility; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +@Slf4j +@Component +public class EnqueueDocumentTransfer { + private final static String CONTENT_TYPE = "application/pdf"; + + public void enqueuePDFDocumentBySubmission(PdfService pdfService, CloudFileRepository cloudFileRepository, + PdfTransmissionJob pdfTransmissionJob, Submission submission, String fileNameForPdf) { + try { + byte[] pdfFile = pdfService.getFilledOutPDF(submission); + String pdfFileName = String.format(fileNameForPdf); + MultipartFile multipartFile = new ByteArrayMultipartFile(pdfFile, pdfFileName, CONTENT_TYPE); + String s3ZipPath = SubmissionUtilities.generatePdfPath(submission); + + CompletableFuture.runAsync(() -> { + try { + cloudFileRepository.upload(s3ZipPath, multipartFile); + } catch (IOException | InterruptedException e) { + log.error("Error uploading submission to S3", e); + throw new RuntimeException(e); + } + }).thenRun(() -> { + try { + pdfTransmissionJob.enqueuePdfTransmissionJob(s3ZipPath, submission); + } catch (IOException e) { + log.error("An error occurred when enqueuing a job with the document transfer service.", e); + } + }).exceptionally(e -> { + log.error("Error uploading submission to S3 for submission with ID: {}", submission.getId(), e); + return null; + }); + + } catch (IOException e) { + log.error("Error uploading submission to S3 for submission with ID: {}", submission.getId(), e); + } + + } + + public void enqueueUploadedDocumentBySubmission(UserFileRepositoryService userFileRepositoryService, + UploadedDocumentTransmissionJob uploadedDocumentTransmissionJob, S3PresignService s3PresignService, Submission submission) { + log.info("Sending uploaded files to document transfer service for submission with ID: {}", submission.getId()); + List userFiles = userFileRepositoryService.findAllBySubmission(submission); + if (!userFiles.isEmpty()) { + for (int i = 0; i < userFiles.size(); i++) { + UserFile userFile = userFiles.get(i); + String fileExtension = Files.getFileExtension(userFile.getOriginalName()); + String fileName = FileNameUtility.getFileNameForUploadedDocument(submission, i + 1, userFiles.size(), + fileExtension); + CompletableFuture scannedAndCleanFuture = s3PresignService.isObjectScannedAndClean( + userFile.getRepositoryPath()); + int currentFileIndex = i; + scannedAndCleanFuture.thenAccept(scannedAndClean -> { + if (scannedAndClean) { + log.info("Sending file {} of {} to document transfer service for submission with ID: {}", + currentFileIndex + 1, userFiles.size(), submission.getId()); + uploadedDocumentTransmissionJob.enqueueUploadedDocumentTransmissionJob(submission, userFile, fileName); + } + }).exceptionally(e -> { + log.error( + "There was an error when attempting to send uploaded file with id: {} in submission with id: {} to the document transfer service. It's possible the file had a virus, or could not be scanned.", + userFile.getFileId(), submission.getId(), e); + return null; + }); + } + } + + } +} + diff --git a/src/main/java/org/ilgcc/jobs/TransmissionsRecurringJob.java b/src/main/java/org/ilgcc/jobs/TransmissionsRecurringJob.java new file mode 100644 index 00000000..1fa80fef --- /dev/null +++ b/src/main/java/org/ilgcc/jobs/TransmissionsRecurringJob.java @@ -0,0 +1,89 @@ +package org.ilgcc.jobs; + + +import formflow.library.data.Submission; +import formflow.library.data.UserFileRepositoryService; +import formflow.library.file.CloudFileRepository; +import formflow.library.pdf.PdfService; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; +import lombok.extern.slf4j.Slf4j; + +import static org.ilgcc.app.utils.ProviderSubmissionUtilities.providerApplicationHasExpired; + +import org.ilgcc.app.data.TransmissionRepositoryService; +import org.ilgcc.app.file_transfer.S3PresignService; +import org.ilgcc.app.utils.enums.FileNameUtility; +import org.jobrunr.jobs.annotations.Job; +import org.jobrunr.jobs.annotations.Recurring; +import org.jobrunr.scheduling.JobScheduler; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class TransmissionsRecurringJob { + + private final S3PresignService s3PresignService; + private final TransmissionRepositoryService transmissionRepositoryService; + private final UserFileRepositoryService userFileRepositoryService; + private final UploadedDocumentTransmissionJob uploadedDocumentTransmissionJob; + private final PdfService pdfService; + private final CloudFileRepository cloudFileRepository; + private final String waitForProviderResponseFlag; + private final PdfTransmissionJob pdfTransmissionJob; + private final EnqueueDocumentTransfer enqueueDocumentTransfer; + + public TransmissionsRecurringJob(S3PresignService s3PresignService, + TransmissionRepositoryService transmissionRepositoryService, UserFileRepositoryService userFileRepositoryService, + UploadedDocumentTransmissionJob uploadedDocumentTransmissionJob, PdfService pdfService, + CloudFileRepository cloudFileRepository, PdfTransmissionJob pdfTransmissionJob, + @Value("${il-gcc.dts.wait-for-provider-response}") String waitForProviderResponseFlag, + EnqueueDocumentTransfer enqueueDocumentTransfer) { + this.s3PresignService = s3PresignService; + this.transmissionRepositoryService = transmissionRepositoryService; + this.userFileRepositoryService = userFileRepositoryService; + this.uploadedDocumentTransmissionJob = uploadedDocumentTransmissionJob; + this.pdfService = pdfService; + this.cloudFileRepository = cloudFileRepository; + this.pdfTransmissionJob = pdfTransmissionJob; + this.waitForProviderResponseFlag = waitForProviderResponseFlag; + this.enqueueDocumentTransfer = enqueueDocumentTransfer; + } + + @Recurring(id = "no-provider-response-job", cron = "* * * * *") + @Job(name = "No provider response job") + public void noProviderResponseJob() { + List submissionsWithoutTransmissions = transmissionRepositoryService.findSubmissionsWithoutTransmission(); + + ZoneId chicagoTimeZone = ZoneId.of("America/Chicago"); + ZonedDateTime todaysDate = OffsetDateTime.now().atZoneSameInstant(chicagoTimeZone); + + List expiredSubmissionsWithNoTransmission = submissionsWithoutTransmissions.stream() + .filter(submission -> providerApplicationHasExpired(submission, todaysDate)).toList(); + if (expiredSubmissionsWithNoTransmission.isEmpty() || waitForProviderResponseFlag.equals("false")) { + return; + } else { + log.info(String.format("Running the 'No provider response job' for %s expired submissions", + expiredSubmissionsWithNoTransmission.size())); + for (Submission submission : expiredSubmissionsWithNoTransmission) { + if (!hasProviderResponse(submission)) { + enqueueDocumentTransfer.enqueuePDFDocumentBySubmission(pdfService, cloudFileRepository, pdfTransmissionJob, + submission, FileNameUtility.getFileNameForPdf(submission, "No-Provider-Response")); + enqueueDocumentTransfer.enqueueUploadedDocumentBySubmission(userFileRepositoryService, + uploadedDocumentTransmissionJob, s3PresignService, submission); + } else { + log.error( + String.format("The provider response exists but the provider response expired. Check submission: %s", + submission.getId())); + } + } + } + } + + private boolean hasProviderResponse(Submission submission) { + return submission.getInputData().containsKey("providerResponseSubmissionId"); + } +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 6ff3fc38..3d731bd5 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -118,5 +118,5 @@ il-gcc: consumer-id: ${DOCUMENT_TRANSFER_SERVICE_CONSUMER_ID} auth-token: ${DOCUMENT_TRANSFER_SERVICE_AUTH_TOKEN} presigned-url-Duration: 5 # Minutes - enable-background-jobs: true + enable-background-jobs: ${ENABLE_BACKGROUND_JOBS_FLAG:true} wait-for-provider-response: ${WAIT_FOR_PROVIDER_RESPONSE_FLAG:false} diff --git a/src/main/resources/pdf-map.yaml b/src/main/resources/pdf-map.yaml index ceb67a20..bff9f7f9 100644 --- a/src/main/resources/pdf-map.yaml +++ b/src/main/resources/pdf-map.yaml @@ -146,6 +146,12 @@ inputFields: partnerSignedName: PARTNER_SIGNATURE partnerSignedAt: PARTNER_SIGNATURE_DATE receivedTimestamp: RECEIVED_TIMESTAMP + + providerNameCorporate: PROVIDER_NAME_CORPORATE + providerPhoneNumber: PROVIDER_PHONE_NUMBER + providerEmail: PROVIDER_EMAIL + providerResponse: PROVIDER_RESPONSE + dbFields: submittedAt: APPLICANT_SIGNATURE_DATE diff --git a/src/test/java/org/ilgcc/app/journeys/ProviderresponseFlowJourneyTest.java b/src/test/java/org/ilgcc/app/journeys/ProviderresponseFlowJourneyTest.java index e54736d9..023dbbe8 100644 --- a/src/test/java/org/ilgcc/app/journeys/ProviderresponseFlowJourneyTest.java +++ b/src/test/java/org/ilgcc/app/journeys/ProviderresponseFlowJourneyTest.java @@ -56,7 +56,7 @@ void ProviderresponseJourneyTest() { assertThat(testPage.findElementTextById("parent-name")).isEqualTo("FirstName parent last"); assertThat(testPage.findElementTextById("child-name-0")).isEqualTo("First Child"); - assertThat(testPage.findElementTextById("child-age-0")).isEqualTo("Age 23"); + assertThat(testPage.findElementTextById("child-age-0")).isEqualTo("Age 22"); assertThat(testPage.findElementTextById("child-schedule-0")).isNotNull(); assertThat(testPage.findElementTextById("child-start-0")).isEqualTo("01/10/2025"); diff --git a/src/test/java/org/ilgcc/app/utils/SubmissionTestBuilder.java b/src/test/java/org/ilgcc/app/utils/SubmissionTestBuilder.java index 6f89a1a9..8b07ebad 100644 --- a/src/test/java/org/ilgcc/app/utils/SubmissionTestBuilder.java +++ b/src/test/java/org/ilgcc/app/utils/SubmissionTestBuilder.java @@ -36,6 +36,11 @@ public SubmissionTestBuilder withSubmittedAtDate(OffsetDateTime date) { return this; } + public SubmissionTestBuilder withFlow(String flow){ + submission.setFlow(flow); + return this; + } + public SubmissionTestBuilder withShortCode(String shortCode) { submission.setShortCode(shortCode); return this; @@ -159,7 +164,7 @@ public SubmissionTestBuilder withChild(String firstName, String lastName, String child.put("childInCare", "true"); child.put("childDateOfBirthMonth", "10"); child.put("childDateOfBirthDay", "11"); - child.put("childDateOfBirthYear", "2001"); + child.put("childDateOfBirthYear", "2002"); child.put("needFinancialAssistanceForChild", needFinancialAssistanceForChild); child.put("childIsUsCitizen", "Yes"); child.put("ccapStartDate", "01/10/2025"); diff --git a/src/test/java/org/ilgcc/jobs/TransmissionsRecurringJobTest.java b/src/test/java/org/ilgcc/jobs/TransmissionsRecurringJobTest.java new file mode 100644 index 00000000..9fa7c27a --- /dev/null +++ b/src/test/java/org/ilgcc/jobs/TransmissionsRecurringJobTest.java @@ -0,0 +1,194 @@ +package org.ilgcc.jobs; + +import formflow.library.data.Submission; +import formflow.library.data.SubmissionRepository; +import formflow.library.data.UserFileRepositoryService; +import formflow.library.file.CloudFileRepository; +import formflow.library.pdf.PdfService; +import java.util.Date; +import org.ilgcc.app.IlGCCApplication; +import org.ilgcc.app.data.Transmission; +import org.ilgcc.app.data.TransmissionRepository; +import org.ilgcc.app.data.TransmissionRepositoryService; +import org.ilgcc.app.file_transfer.S3PresignService; +import org.ilgcc.app.utils.SubmissionTestBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.time.OffsetDateTime; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.ilgcc.app.utils.enums.TransmissionStatus.Queued; +import static org.ilgcc.app.utils.enums.TransmissionType.APPLICATION_PDF; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@SpringBootTest(classes = IlGCCApplication.class) +@ActiveProfiles("test") +public class TransmissionsRecurringJobTest { + + @Autowired + private SubmissionRepository submissionRepository; + + @Autowired + private TransmissionRepository transmissionRepository; + + @Autowired + private TransmissionRepositoryService transmissionRepositoryService; + @Mock + private S3PresignService s3PresignService; + + @Mock + private UserFileRepositoryService userFileRepositoryService; + + @Mock + private UploadedDocumentTransmissionJob uploadedDocumentTransmissionJob; + + @Mock + private PdfService pdfService; + + @Mock + private CloudFileRepository cloudFileRepository; + + @Mock + private PdfTransmissionJob pdfTransmissionJob; + + @Mock + private EnqueueDocumentTransfer enqueueDocumentTransfer; + + @InjectMocks + private TransmissionsRecurringJob transmissionsRecurringJob; + + private Submission expiredSubmission; + private Submission transmittedSubmission; + private Submission unsubmittedSubmission; + private Submission unexpiredSubmission; + private Submission expiredUntransmittedSubmissionWithProviderResponse; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + transmissionsRecurringJob = new TransmissionsRecurringJob( + s3PresignService, + transmissionRepositoryService, + userFileRepositoryService, + uploadedDocumentTransmissionJob, + pdfService, + cloudFileRepository, + pdfTransmissionJob, + "true", + enqueueDocumentTransfer + ); + } + + @AfterEach + protected void clearSubmissions() { + transmissionRepository.deleteAll(); + submissionRepository.deleteAll(); + } + + @Test + void enqueueDocumentTransferWillNotRunIfFlagIsOff() { + expiredSubmission = new SubmissionTestBuilder() + .withParentDetails() + .withSubmittedAtDate(OffsetDateTime.now().minusDays(7)) + .withFlow("gcc") + .build(); + submissionRepository.save(expiredSubmission); + + transmissionsRecurringJob = new TransmissionsRecurringJob( + s3PresignService, + transmissionRepositoryService, + userFileRepositoryService, + uploadedDocumentTransmissionJob, + pdfService, + cloudFileRepository, + pdfTransmissionJob, + "false", + enqueueDocumentTransfer + ); + + transmissionsRecurringJob.noProviderResponseJob(); + + verifyNoInteractions(enqueueDocumentTransfer); + } + @Test + void enqueueDocumentTransferIsOnlyCalledOnExpiredSubmissions() { + unexpiredSubmission = new SubmissionTestBuilder() + .withParentDetails() + .withSubmittedAtDate(OffsetDateTime.now()) + .withFlow("gcc") + .build(); + submissionRepository.save(unexpiredSubmission); + + expiredSubmission = new SubmissionTestBuilder() + .withParentDetails() + .withSubmittedAtDate(OffsetDateTime.now().minusDays(7)) + .withFlow("gcc") + .build(); + submissionRepository.save(expiredSubmission); + + unsubmittedSubmission = new SubmissionTestBuilder() + .withParentDetails() + .withFlow("gcc") + .build(); + submissionRepository.save(unsubmittedSubmission); + + transmissionsRecurringJob.noProviderResponseJob(); + + //Confirms that the method was called on the expired submission + verify(enqueueDocumentTransfer, times(1)).enqueuePDFDocumentBySubmission(eq(pdfService), eq(cloudFileRepository), + eq(pdfTransmissionJob), eq(expiredSubmission), any()); + verify(enqueueDocumentTransfer, times(1)).enqueueUploadedDocumentBySubmission(eq(userFileRepositoryService), + eq(uploadedDocumentTransmissionJob), eq(s3PresignService), eq(expiredSubmission)); + + verify(enqueueDocumentTransfer, never()).enqueuePDFDocumentBySubmission(eq(pdfService), eq(cloudFileRepository), + eq(pdfTransmissionJob), eq(unexpiredSubmission), any()); + verify(enqueueDocumentTransfer, never()).enqueueUploadedDocumentBySubmission(eq(userFileRepositoryService), + eq(uploadedDocumentTransmissionJob), eq(s3PresignService), eq(unexpiredSubmission)); + + verify(enqueueDocumentTransfer, never()).enqueuePDFDocumentBySubmission(eq(pdfService), eq(cloudFileRepository), + eq(pdfTransmissionJob), eq(unsubmittedSubmission), any()); + verify(enqueueDocumentTransfer, never()).enqueueUploadedDocumentBySubmission(eq(userFileRepositoryService), + eq(uploadedDocumentTransmissionJob), eq(s3PresignService), eq(unsubmittedSubmission)); + } + + @Test + void enqueueDocumentTransferWillNotBeCalledIfSubmissionHasTransmission() { + transmittedSubmission = new SubmissionTestBuilder() + .withParentDetails() + .withSubmittedAtDate(OffsetDateTime.now().minusDays(7)) + .with("providerResponseSubmissionId", "123124") + .withFlow("gcc") + .build(); + submissionRepository.save(transmittedSubmission); + transmissionRepositoryService.save(new Transmission(transmittedSubmission, null, Date.from(OffsetDateTime.now() + .toInstant()), Queued, APPLICATION_PDF, null)); + + transmissionsRecurringJob.noProviderResponseJob(); + + verifyNoInteractions(enqueueDocumentTransfer, pdfService, userFileRepositoryService); + } + + @Test + void enqueueDocumentTransferIsNotCalledOnExpiredUntransmittedSubmission() { + expiredUntransmittedSubmissionWithProviderResponse = new SubmissionTestBuilder() + .withParentDetails() + .withSubmittedAtDate(OffsetDateTime.now().minusDays(7)) + .withFlow("gcc") + .with("providerResponseSubmissionId", "123124") + .build(); + submissionRepository.save(expiredUntransmittedSubmissionWithProviderResponse); + + transmissionsRecurringJob.noProviderResponseJob(); + + verify(enqueueDocumentTransfer, never()).enqueuePDFDocumentBySubmission(any(), any(), any(), any(), any()); + verify(enqueueDocumentTransfer, never()).enqueueUploadedDocumentBySubmission(any(), any(), any(), any()); + } +}