From 2a0d9ce3f9afeaa05e7bbaaf14903485a754f990 Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Mon, 19 Aug 2024 14:27:38 +0200 Subject: [PATCH] RED-9717 - Add warnings on approval --- .../api/impl/controller/StatusController.java | 66 +++--- .../api/external/resource/StatusResource.java | 18 +- .../service/ApprovalVerificationService.java | 89 +++++++++ .../integration/tests/ApprovalTest.java | 189 ++++++++++++++++++ .../tests/DownloadPreparationTest.java | 2 +- .../integration/tests/DownloadTest.java | 2 +- .../v1/server/integration/tests/FileTest.java | 4 +- .../integration/tests/ReportTemplateTest.java | 2 +- .../shared/model/warning/ApproveResponse.java | 39 ++++ .../shared/model/warning/WarningModel.java | 26 +++ .../api/shared/model/warning/WarningType.java | 16 ++ .../warning/WarningsComparatorUtils.java | 16 ++ 12 files changed, 435 insertions(+), 34 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ApprovalVerificationService.java create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ApprovalTest.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/ApproveResponse.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningModel.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningType.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningsComparatorUtils.java diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/StatusController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/StatusController.java index 626d7bd66..39c42fd8b 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/StatusController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/StatusController.java @@ -26,6 +26,7 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.BadRe import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException; import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService; +import com.iqser.red.service.persistence.management.v1.processor.service.ApprovalVerificationService; import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusMapper; @@ -42,6 +43,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import jakarta.transaction.Transactional; @@ -64,6 +66,7 @@ public class StatusController implements StatusResource { private final AccessControlService accessControlService; private final NotificationPersistenceService notificationPersistenceService; private final DossierACLService dossierACLService; + private final ApprovalVerificationService approvalVerificationService; @Override @@ -299,31 +302,40 @@ public class StatusController implements StatusResource { @PreAuthorize("hasAuthority('" + SET_STATUS_APPROVED + "')") - public void setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { + public ApproveResponse setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force) { accessControlService.checkAccessPermissionsToDossier(dossierId); accessControlService.verifyUserIsApprover(dossierId); - setStatusApprovedForFile(dossierId, fileId); - auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Document status was changed to Approved") - .details(Map.of(DOSSIER_ID, dossierId)) - .build()); - - var dossier = dossierACLService.enhanceDossierWithACLData(dossierManagementService.getDossierById(dossierId, false, false)); - if (!dossier.getOwnerId().equals(KeycloakSecurity.getUserId())) { - - var fileStatus = fileStatusManagementService.getFileStatus(fileId); - - notificationPersistenceService.insertNotification(AddNotificationRequest.builder() - .userId(dossier.getOwnerId()) - .issuerId(KeycloakSecurity.getUserId()) - .notificationType(NotificationType.DOCUMENT_APPROVED.name()) - .target(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, FILE_NAME, fileStatus.getFilename())) - .build()); + ApproveResponse approveResponse = new ApproveResponse(false, new HashMap<>()); + if (!force) { + approveResponse = approvalVerificationService.verifyApprovalOfFile(dossierId, fileId); } + if (!approveResponse.isHasWarnings()) { + setStatusApprovedForFile(dossierId, fileId); + auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Document status was changed to Approved") + .details(Map.of(DOSSIER_ID, dossierId)) + .build()); + + var dossier = dossierACLService.enhanceDossierWithACLData(dossierManagementService.getDossierById(dossierId, false, false)); + if (!dossier.getOwnerId().equals(KeycloakSecurity.getUserId())) { + + var fileStatus = fileStatusManagementService.getFileStatus(fileId); + + notificationPersistenceService.insertNotification(AddNotificationRequest.builder() + .userId(dossier.getOwnerId()) + .issuerId(KeycloakSecurity.getUserId()) + .notificationType(NotificationType.DOCUMENT_APPROVED.name()) + .target(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, FILE_NAME, fileStatus.getFilename())) + .build()); + } + } + return approveResponse; } @@ -398,14 +410,22 @@ public class StatusController implements StatusResource { @Override @PreAuthorize("hasAuthority('" + SET_STATUS_APPROVED + "')") - public void setStatusApprovedForList(String dossierId, List fileIds) { + public List setStatusApprovedForList(String dossierId, + List fileIds, + @RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force) { + List approveResponses = new ArrayList<>(); accessControlService.checkAccessPermissionsToDossier(dossierId); accessControlService.verifyUserIsApprover(dossierId); dossierManagementService.getDossierById(dossierId, false, false); - fileIds.forEach(fileId -> setStatusApproved(dossierId, fileId)); + if (fileIds.size() > 50) { + throw new BadRequestException("Maximum amount of files that can be approved at once is 50."); + } + + fileIds.forEach(fileId -> approveResponses.add(setStatusApproved(dossierId, fileId, force))); + return approveResponses; } diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java index fb5372bc9..6abd5cb84 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java @@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; +import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -35,6 +36,7 @@ public interface StatusResource { String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}"; String ASSIGNEE_ID_REQUEST_PARAM = "assigneeId"; + String FORCE_REQUEST_PARAM = "force"; String DELETED_PATH = "/softdeleted"; @@ -105,11 +107,13 @@ public interface StatusResource { @RequestParam(value = ASSIGNEE_ID_REQUEST_PARAM, required = false) String assigneeId); - @ResponseStatus(value = HttpStatus.NO_CONTENT) + @ResponseStatus(value = HttpStatus.OK) @PostMapping(value = STATUS_REST_PATH + "/approved" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE) @Operation(summary = "Sets the status APPROVED for a file.", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")}) - void setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")}) + ApproveResponse setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force); @ResponseStatus(value = HttpStatus.NO_CONTENT) @@ -139,11 +143,13 @@ public interface StatusResource { @RequestParam(value = ASSIGNEE_ID_REQUEST_PARAM, required = false) String assigneeId); - @ResponseStatus(value = HttpStatus.NO_CONTENT) + @ResponseStatus(value = HttpStatus.OK) @PostMapping(value = STATUS_REST_PATH + "/approved" + DOSSIER_ID_PATH_VARIABLE + BULK_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Sets the status APPROVED for a list of files.", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "403", description = "Forbidden")}) - void setStatusApprovedForList(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody List fileIds); + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "403", description = "Forbidden")}) + List setStatusApprovedForList(@PathVariable(DOSSIER_ID) String dossierId, + @RequestBody List fileIds, + @RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force); @ResponseStatus(value = HttpStatus.NO_CONTENT) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ApprovalVerificationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ApprovalVerificationService.java new file mode 100644 index 000000000..d8ee82816 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ApprovalVerificationService.java @@ -0,0 +1,89 @@ +package com.iqser.red.service.persistence.management.v1.processor.service; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisEntity; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; +import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse; +import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningType; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Service +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class ApprovalVerificationService { + + EntityLogService entityLogService; + LegalBasisMappingPersistenceService legalBasisMappingPersistenceService; + DossierRepository dossierRepository; + + + public ApproveResponse verifyApprovalOfFile(String dossierId, String fileId) { + + ApproveResponse approveResponse = new ApproveResponse(); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, true); + List entityLogEntries = entityLog.getEntityLogEntry(); + List legalBasisMappings = legalBasisMappingPersistenceService.getLegalBasisMapping(dossierRepository.findDossierTemplateId(dossierId)); + + for (EntityLogEntry entry : entityLogEntries) { + if (entry.getState().equals(EntryState.APPLIED) && !entry.getEntryType().equals(EntryType.IMAGE) && !entry.getEntryType().equals(EntryType.IMAGE_HINT)) { + if (StringUtils.isEmpty(entry.getLegalBasis())) { + addWarning(entry, fileId, WarningType.LEGAL_BASIS_MISSING, approveResponse); + } else { + var legalBasisEntity = legalBasisMappings.stream() + .filter(mapping -> mapping.getReason().equals(entry.getLegalBasis())) + .findFirst(); + if (legalBasisEntity.isEmpty() || StringUtils.isEmpty(legalBasisEntity.get().getTechnicalName())) { + addWarning(entry, fileId, WarningType.UNMAPPED_JUSTIFICATION, approveResponse); + } + } + } + if (entry.getState().equals(EntryState.PENDING)) { + addWarning(entry, fileId, WarningType.PENDING_CHANGE, approveResponse); + } + } + + approveResponse.setHasWarnings(approveResponse.getFileWarnings() != null && !approveResponse.getFileWarnings().isEmpty()); + return approveResponse; + } + + + private void addWarning(EntityLogEntry entry, String fileId, WarningType warningType, ApproveResponse approveResponse) { + + approveResponse.addFileWarning(fileId, + WarningModel.builder() + .id(entry.getId()) + .pages(entry.getPositions() + .stream() + .map(Position::getPageNumber) + .collect(Collectors.toSet())) + .value(shortenValue(entry.getValue())) + .warningType(warningType) + .type(entry.getType()) + .build()); + } + + + private String shortenValue(String value) { + + if (value.length() > 100) { + return value.substring(0, 97) + "..."; + } + return value; + } + +} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ApprovalTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ApprovalTest.java new file mode 100644 index 000000000..d888cf6ad --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ApprovalTest.java @@ -0,0 +1,189 @@ +package com.iqser.red.service.peristence.v1.server.integration.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; + +import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.TypeProvider; +import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisEntity; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; +import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse; +import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningType; + +public class ApprovalTest extends AbstractPersistenceServerServiceTest { + + @Autowired + private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider; + + @Autowired + private FileTesterAndProvider fileTesterAndProvider; + + @Autowired + private DossierTesterAndProvider dossierTesterAndProvider; + + @Autowired + private TypeProvider typeProvider; + + @Autowired + private FileClient fileClient; + + @SpyBean + private LegalBasisMappingPersistenceService legalBasisMappingPersistenceService; + + + @Test + public void testApprovalNoWarnings() { + + DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate(); + Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel); + FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file"); + fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId()); + + when(legalBasisMappingPersistenceService.getLegalBasisMapping(anyString())).thenReturn(List.of(LegalBasisEntity.builder() + .technicalName("legal_basis") + .reason("legalBasis") + .build())); + EntityLog entityLog = new EntityLog(); + entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder() + .id("id1") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .state(EntryState.APPLIED) + .legalBasis("legalBasis") + .entryType(EntryType.ENTITY) + .value("value") + .build())); + when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog); + + ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false); + + assertFalse(approveResponse.isHasWarnings()); + assertTrue(approveResponse.getFileWarnings().isEmpty()); + } + + + @Test + public void testApprovalWithWarnings() { + + DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate(); + Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel); + FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file"); + fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId()); + + EntityLog entityLog = new EntityLog(); + entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder() + .id("id1") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .state(EntryState.APPLIED) + .entryType(EntryType.ENTITY) + .value("value") + .build(), + EntityLogEntry.builder() + .id("id2") + .positions(List.of(new Position(1, 1, 1, 1, 2))) + .state(EntryState.PENDING) + .entryType(EntryType.ENTITY) + .legalBasis("legalBasis") + .value("value") + .build())); + + when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog); + + ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false); + + assertTrue(approveResponse.isHasWarnings()); + assertFalse(approveResponse.getFileWarnings().isEmpty()); + assertEquals(approveResponse.getFileWarnings() + .get(file.getFileId()) + .stream() + .filter(c -> c.getWarningType().equals(WarningType.PENDING_CHANGE)) + .count(), 1); + assertEquals(approveResponse.getFileWarnings() + .get(file.getFileId()) + .stream() + .filter(c -> c.getWarningType().equals(WarningType.LEGAL_BASIS_MISSING)) + .count(), 1); + } + + + @Test + public void testApprovalWithWarningValueTooLoong() { + + DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate(); + Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel); + FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file"); + fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId()); + + EntityLog entityLog = new EntityLog(); + entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder() + .id("id2") + .positions(List.of(new Position(1, 1, 1, 1, 2))) + .state(EntryState.PENDING) + .legalBasis("legalBasis") + .value(StringUtils.repeat("a", 1000)) + .build())); + + when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog); + + ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false); + + assertTrue(approveResponse.isHasWarnings()); + assertFalse(approveResponse.getFileWarnings().isEmpty()); + assertEquals(approveResponse.getFileWarnings() + .get(file.getFileId()) + .get(0).getValue().length(), 100); + assertEquals(approveResponse.getFileWarnings() + .get(file.getFileId()) + .get(0).getWarningType(), WarningType.PENDING_CHANGE); + } + + + @Test + public void testForceApprovalWithIssues() { + + DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate(); + Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel); + FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file"); + fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId()); + + EntityLog entityLog = new EntityLog(); + entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder() + .id("id2") + .positions(List.of(new Position(1, 1, 1, 1, 2))) + .state(EntryState.PENDING) + .legalBasis("legalBasis") + .value(StringUtils.repeat("a", 1000)) + .build())); + + when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog); + + ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), true); + + assertFalse(approveResponse.isHasWarnings()); + assertTrue(approveResponse.getFileWarnings().isEmpty()); + } + +} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java index c6c01c5f3..2e99eb959 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java @@ -255,7 +255,7 @@ public class DownloadPreparationTest extends AbstractPersistenceServerServiceTes fileTesterAndProvider.markFileAsProcessed(getDossierId(), getFileId()); - fileClient.setStatusApproved(getDossierId(), getFileId()); + fileClient.setStatusApproved(getDossierId(), getFileId(), true); assertThatTestFileIsApproved(); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java index fcc4bb7d2..694534471 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java @@ -83,7 +83,7 @@ public class DownloadTest extends AbstractPersistenceServerServiceTest { fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file2.getFileId()); - fileClient.setStatusApproved(dossier.getId(), file2.getId()); + fileClient.setStatusApproved(dossier.getId(), file2.getId(), true); var file22 = fileClient.getFileStatus(dossier.getId(), file2.getId()); assertThat(file22.getWorkflowStatus()).isEqualTo(WorkflowStatus.APPROVED); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java index 52d363861..0d6cae8a6 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java @@ -299,7 +299,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { assertThat(loadedFile.getLastApprover()).isEqualTo(userId); fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId()); - fileClient.setStatusApproved(dossier.getId(), file.getId()); + fileClient.setStatusApproved(dossier.getId(), file.getId(), true); loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.APPROVED); assertThat(loadedFile.getAssignee()).isEqualTo(userId); @@ -322,7 +322,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { assertThat(loadedFile.getLastReviewer()).isEqualTo(userId); assertThat(loadedFile.getLastApprover()).isEqualTo(altUserId); - fileClient.setStatusApproved(dossier.getId(), file.getId()); + fileClient.setStatusApproved(dossier.getId(), file.getId(), true); loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.APPROVED); assertThat(loadedFile.getAssignee()).isEqualTo(userId); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ReportTemplateTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ReportTemplateTest.java index 4a8b6c7cc..2363b396c 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ReportTemplateTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ReportTemplateTest.java @@ -373,7 +373,7 @@ public class ReportTemplateTest extends AbstractPersistenceServerServiceTest { var file = fileTesterAndProvider.testAndProvideFile(dossier); fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId()); - fileClient.setStatusApproved(dossier.getId(), file.getId()); + fileClient.setStatusApproved(dossier.getId(), file.getId(), true); // Act & Assert var availableTemplates = reportTemplateClient.getAvailableReportTemplates(dossier.getDossierTemplateId()); diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/ApproveResponse.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/ApproveResponse.java new file mode 100644 index 000000000..3659143c0 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/ApproveResponse.java @@ -0,0 +1,39 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.warning; + +import static com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningsComparatorUtils.WARNING_MODEL_COMPARATOR; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class ApproveResponse { + + private boolean hasWarnings; + + private Map> fileWarnings = new HashMap<>(); + + + public void addFileWarning(String fileId, WarningModel warningModel) { + + if (fileWarnings.containsKey(fileId)) { + fileWarnings.get(fileId).add(warningModel); + } else { + List warningModels = new ArrayList<>(); + warningModels.add(warningModel); + fileWarnings.put(fileId, warningModels); + } + + fileWarnings.get(fileId).sort(WARNING_MODEL_COMPARATOR); + } + +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningModel.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningModel.java new file mode 100644 index 000000000..33827292f --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningModel.java @@ -0,0 +1,26 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.warning; + +import java.util.List; +import java.util.Set; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class WarningModel { + + private String id; + + private String value; + + private Set pages; + + private String type; + + private WarningType warningType; +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningType.java new file mode 100644 index 000000000..954a3c003 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningType.java @@ -0,0 +1,16 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.warning; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum WarningType { + + PENDING_CHANGE("pending change"), + LEGAL_BASIS_MISSING("legal basis missing"), + UNMAPPED_JUSTIFICATION("unmapped justification"); + + private final String name; + +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningsComparatorUtils.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningsComparatorUtils.java new file mode 100644 index 000000000..acf97bc6c --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/warning/WarningsComparatorUtils.java @@ -0,0 +1,16 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.warning; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Set; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class WarningsComparatorUtils { + + + public static final Comparator> LIST_COMPARATOR = Comparator.comparingInt(Collections::min); + + public static final Comparator WARNING_MODEL_COMPARATOR = (wm1, wm2) -> LIST_COMPARATOR.compare(wm1.getPages(), wm2.getPages()); +}