package net.gepafin.tendermanagement.dao; import com.amazonaws.services.dynamodbv2.xspec.S; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.itextpdf.text.BaseColor; import com.itextpdf.text.Font; import com.itextpdf.text.FontFactory; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.*; import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.entities.SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum; import net.gepafin.tendermanagement.enums.*; import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.request.ApplicationFormFieldRequestBean; import net.gepafin.tendermanagement.model.request.ApplicationRequest; import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.request.EmailLogRequest; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.SortBy; import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.AmazonS3Service; import net.gepafin.tendermanagement.service.ApplicationEvaluationService; import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.DocumentService; import net.gepafin.tendermanagement.service.FormService; import net.gepafin.tendermanagement.service.HubService; import net.gepafin.tendermanagement.service.SystemEmailTemplatesService; import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.util.*; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.commons.lang3.StringUtils; import org.h2.util.IOUtils; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import jakarta.servlet.http.HttpServletRequest; import java.io.*; import java.lang.reflect.Method; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.sql.Timestamp; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static org.apache.commons.lang3.StringUtils.isEmpty; @Component public class ApplicationDao { private final Logger log = LoggerFactory.getLogger(ApplicationDao.class); @Autowired private CallService callService; @Autowired private ApplicationRepository applicationRepository; @Autowired private DocumentRepository documentRepository; @Autowired private ApplicationFormRepository applicationFormRepository; @Autowired private ApplicationFormFieldRepository applicationFormFieldRepository; @Autowired private FormService formService; @Autowired private DocumentService documentService; @Autowired private CallDao callDao; @Autowired private FlowFormDao flowFormDao; @Autowired private FlowEdgesRepository flowEdgesRepository; @Autowired private FlowDataRepository flowDataRepository; @Autowired private UserCompanyDelegationRepository userCompanyDelegationRepository; @Autowired private Validator validator; @Autowired private CompanyService companyService; @Autowired private S3PathConfig s3PathConfig; @Autowired private SystemEmailTemplatesService systemEmailTemplatesService; @Autowired private AssignedApplicationsRepository assignedApplicationsRepository; // @Value("${default_System_Receiver_Email}") // private String defaultSystemReceiverEmail; @Value("${rinaldo_email}") private String rinaldoEmail; @Value("${call.id}") private String callId; @Value("${sviluppumbriaUuid}") private String sviluppumbriaUuid; @Autowired private AmazonS3Service amazonS3Service; @Autowired private ApplicationSignedDocumentRepository applicationSignedDocumentRepository; // @Value("${aws.s3.url.folder.signed.document}") // private String signedDocumentS3Folder; @Value("${default.hub.uuid}") private String defaultHubUuid; @Autowired private UserService userService; @Autowired private S3PathConfig s3ConfigBean; @Autowired private ProtocolDao protocolDao; @Autowired private HubService hubService; @Autowired private EmailNotificationDao emailNotificationDao; @Autowired private FormDao formDao; @Autowired private EmailLogDao emailLogDao; @Autowired private UserWithCompanyRepository userWithCompanyRepository; @Autowired private LoggingUtil loggingUtil; @Autowired private HttpServletRequest request; @Autowired private ApplicationEvaluationService applicationEvaluationService; @Autowired private NotificationDao notificationDao; @Autowired private UserRepository userRepository; @Autowired private RoleRepository roleRepository; @Autowired private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; @Autowired private ApplicationEvaluationRepository applicationEvaluationRepository; @Autowired private ApplicationViewRepository applicationViewRepository; @Autowired private ApplicationFormViewRepository applicationFormViewRepository; @Autowired private FormRepository formRepository; @Autowired private ApplicationEvaluationDao applicationEvaluationDao; @Autowired private EvaluationCriteriaRepository evaluationCriteriaRepository; public final Random random = new Random(); public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) { log.info("Starting createApplication: formId={}, applicationId={}", formId, applicationId); FormEntity formEntity = formService.validateForm(formId); // callService.validatePublishedCall(formEntity.getCall().getId()); validateFormFields(applicationRequestBean,formEntity); ApplicationEntity applicationEntity = validateApplication(applicationId); checkCallEndDate(applicationEntity.getCall()); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); log.info("Validated user-company association for company ID: {}", applicationEntity.getCompanyId()); if(Boolean.FALSE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.DRAFT.getValue()))) { log.warn("Application ID {} is not in DRAFT status", applicationId); throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.APPLICATION_NOT_IN_DRAFT_STATUS)); } formService.validateFormField(applicationRequestBean.getFormFields(),applicationEntity,formEntity); ApplicationFormEntity applicationFormEntity = getApplicationFormOrCreate(formEntity, applicationEntity); createOrUpdateMultipleFormFields(applicationRequestBean.getFormFields(), applicationFormEntity, formEntity); return getApplicationById(applicationEntity.getId(),formEntity.getId()); } public void validateDelegation(UserEntity user, UserWithCompanyEntity userWithCompany) { UserCompanyDelegationEntity userCompanyDelegationEntity = userCompanyDelegationRepository .findByUserIdAndUserWithCompanyIdAndStatus(user.getId(), userWithCompany.getId(), UserCompanyDelegationStatusEnum.ACTIVE.getValue()); if (!userWithCompany.getIsLegalRepresentant() && userCompanyDelegationEntity == null) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.USER_NOT_AUTHORIZED_TO_CREATE_APPLICATION)); } } public ApplicationFormEntity saveApplicationFormEntity(ApplicationFormEntity applicationFormEntity) { ApplicationFormEntity applicationFormEntity1 = applicationFormRepository.save(applicationFormEntity); return applicationFormEntity1; } public ApplicationFormEntity createApplicationFormEntity(ApplicationEntity application, FormEntity formEntity) { log.info("Creating ApplicationFormEntity for applicationId: {}, formId: {}", application.getId(), formEntity.getId()); ApplicationFormEntity applicationFormEntity = new ApplicationFormEntity(); applicationFormEntity.setApplication(application); applicationFormEntity.setForm(formEntity); applicationFormEntity = saveApplicationFormEntity(applicationFormEntity); log.info("Created ApplicationFormEntity with id: {}", applicationFormEntity.getId()); return applicationFormEntity; } public ApplicationEntity createApplicationEntity(UserEntity user, CallEntity call, UserWithCompanyEntity userWithCompany) { // validateDelegation(user,userWithCompany); ApplicationEntity entity = new ApplicationEntity(); entity.setUserId(user.getId()); entity.setCompanyId(userWithCompany.getCompanyId()); entity.setCall(call); entity.setHubId(call.getHub().getId()); entity.setUserWithCompany(userWithCompany); entity.setIsDeleted(false); entity.setStatus(ApplicationStatusTypeEnum.DRAFT.getValue()); entity.setEvaluationVersion(call.getEvaluationVersion()); return entity; } public ApplicationResponseBean getApplicationById(Long id,Long formId) { log.info("Fetching application with ID: {}", id); ApplicationEntity applicationEntity = validateApplication(id); ApplicationFormEntity applicationFormEntity = applicationFormRepository.findByApplicationIdAndFormId(applicationEntity.getId(),formId); List applicationFormFieldResponseBeans=new ArrayList<>(); List applicationFormFieldEntities = applicationFormFieldRepository.findByApplicationFormId(applicationFormEntity.getId()); applicationFormFieldResponseBeans=createApplicationFormFieldResponse(applicationFormFieldEntities, applicationFormEntity, applicationFormFieldResponseBeans); ApplicationResponseBean applicationResponseBean= convertApplicationEntityToApplicationResponseBean(applicationEntity); applicationResponseBean.setFormFields(applicationFormFieldResponseBeans); return applicationResponseBean; } private List createApplicationFormFieldResponse( List applicationFormFieldEntities, ApplicationFormEntity applicationFormEntity, List applicationFormFieldResponseBeans) { // List contentResponseBeans = Utils.convertJsonStringToList( // applicationFormEntity.getForm().getContent(), ContentResponseBean.class); List contentResponseBeans = formDao.convertFormEntityToFormResponseBean(applicationFormEntity.getForm()).getContent(); for (ApplicationFormFieldEntity applicationFormFieldEntity : applicationFormFieldEntities) { Optional fileUploadContent = contentResponseBeans.stream() .filter(contentResponseBean -> ("fileupload".equals(contentResponseBean.getName()) || "fileselect".equals(contentResponseBean.getName())) && contentResponseBean.getId().equals(applicationFormFieldEntity.getFieldId())) .findFirst(); List documentResponseBeans = new ArrayList<>(); if (fileUploadContent.isPresent()) { String documentId = applicationFormFieldEntity.getFieldValue(); log.debug("Field is file upload/select type. Document IDs: {}", documentId); if (documentId != null && !documentId.isEmpty()) { documentResponseBeans = Arrays.stream(documentId.split(",")) .map(String::trim) .map(Long::parseLong) .map(docId -> { DocumentEntity documentEntity = documentService.validateDocument(docId); if (Boolean.FALSE.equals(DocumentSourceTypeEnum.APPLICATION.getValue().equals(documentEntity.getSource()))) { log.warn("Document {} source type invalid: {}", docId, documentEntity.getSource()); throw new CustomValidationException(Status.NOT_FOUND,Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); } return documentEntity; }) .map(callDao::convertToDocumentResponseBean) .collect(Collectors.toList()); } } ApplicationFormFieldResponseBean responseBean = convertApplicationFormFieldEntityToApplicationFormFieldResponseBean( applicationFormFieldEntity, applicationFormEntity.getId()); if (!documentResponseBeans.isEmpty()) { responseBean.setFieldValue(documentResponseBeans); } applicationFormFieldResponseBeans.add(responseBean); } return applicationFormFieldResponseBeans; } public void deleteById(HttpServletRequest request, Long id) { log.info("Deleting application with ID: {}", id); ApplicationEntity applicationEntity= validateApplication(id); if (Boolean.FALSE.equals(ApplicationStatusTypeEnum.DRAFT.getValue().equals(applicationEntity.getStatus()))) { log.warn("Application with ID: {} is not in DRAFT status, cannot delete. Current status: {}", id, applicationEntity.getStatus()); throw new CustomValidationException( Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_NOT_IN_DRAFT_STATUS) ); } ApplicationEntity oldApplicationDataEntity = Utils.getClonedEntityForData(applicationEntity); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); applicationEntity.setIsDeleted(true); applicationEntity = applicationRepository.save(applicationEntity); log.info("Marked application as deleted and saved for ID: {}", id); /** This code is responsible for adding a version history log for the "Delete application" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldApplicationDataEntity).newData(applicationEntity).build()); log.info("Application deleted with ID: {}", id); } // public List getAllApplications(UserEntity userEntity, Long callId, CompanyEntity companyEntity) { // boolean isBeneficiary = validator.checkIsBeneficiary(); // // log.info("Fetching applications for RoleType: {}", userEntity.getRoleEntity().getRoleType()); // List applicationResponses = new ArrayList<>(); // // if (callId != null) { // // Fetch based on callId and user if role is BENEFICIARY, otherwise fetch all for the call // log.info("Fetching applications for callId: {}", callId); // CallEntity call = callService.validateCall(callId); // // // Use a single method to handle both conditions for consistency // List applicationEntities = isBeneficiary // ? applicationRepository.findByUserIdAndCallIdAndIsDeletedFalse(userEntity.getId(), call.getId()) // .map(List::of) // Convert Optional to a List of one element // .orElse(List.of()) // If not present, return an empty list // : applicationRepository.findByCallIdAndIsDeletedFalse(call.getId()); // // applicationResponses = applicationEntities.stream() // .map(this::getApplicationResponse) // .collect(Collectors.toList()); // // } else { // // Fetch all applications for the user if BENEFICIARY, or fetch all applications in general // List applicationEntities = isBeneficiary // ? applicationRepository.findByUserIdAndIsDeletedFalse(companyEntity.getId()) // : applicationRepository.findByIsDeletedFalse(); // // applicationResponses = applicationEntities.stream() // .map(this::getApplicationResponse) // .collect(Collectors.toList()); // } // // return applicationResponses; // } public List getAllApplications(UserEntity userEntity, Long callId, Long companyId,List statusList) { log.info("Fetching applications for RoleType: {}", userEntity.getRoleEntity().getRoleType()); Specification spec = search(userEntity, callId, companyId,statusList); List applicationEntities = applicationRepository.findAll(spec); return applicationEntities.stream() .map(this::getApplicationResponse) .collect(Collectors.toList()); } private Specification search(UserEntity userEntity, Long callId, Long companyId,List statusList) { return (root, query, builder) -> { Boolean isBeneficiary = validator.checkIsBeneficiary(); Predicate predicate = builder.isFalse(root.get("isDeleted")); if (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { predicate = builder.and(predicate, builder.equal(root.get("userId"), userEntity.getId())); } if (callId != null) { predicate = builder.and(predicate, builder.equal(root.get("call").get("id"), callId)); } if (companyId != null) { predicate = builder.and(predicate, builder.equal(root.get("companyId"), companyId)); } if (statusList != null && !statusList.isEmpty()) { List statusNames = statusList.stream() .map(Enum::name) .collect(Collectors.toList()); predicate = builder.and(predicate, root.get("status").in(statusNames)); } query.orderBy( builder.desc(builder.isNotNull(root.get(GepafinConstant.SUBMISSION_DATE))), builder.desc(root.get(GepafinConstant.SUBMISSION_DATE)) ); predicate = builder.and(predicate, builder.equal(root.get("hubId"), userEntity.getHub().getId())); return predicate; }; } private ApplicationResponse getApplicationResponse(ApplicationEntity applicationEntity) { log.info("Generating ApplicationResponse for application ID: {}", applicationEntity.getId()); ApplicationResponse responseBean = new ApplicationResponse(); List flowEdgesList = flowEdgesRepository.findByCallId(applicationEntity.getCall().getId()); Long totalFormSteps = flowFormDao.calculateTotalSteps(flowEdgesList); Long completedSteps= Long.valueOf(flowFormDao.getCompletedSteps(applicationEntity, false)); Integer progress = calculateProgress(totalFormSteps, completedSteps); responseBean.setId(applicationEntity.getId()); responseBean.setProgress(progress); responseBean.setCallTitle(applicationEntity.getCall().getName()); responseBean.setCallEndDate(applicationEntity.getCall().getEndDate()); responseBean.setCallEndTime(applicationEntity.getCall().getEndTime()); responseBean.setModifiedDate(applicationEntity.getUpdatedDate()); responseBean.setCallId(applicationEntity.getCall().getId()); responseBean.setSubmissionDate(applicationEntity.getSubmissionDate()); responseBean.setStatus(applicationEntity.getStatus()); responseBean.setEvaluationVersion(EvaluationVersionEnum.valueOf(applicationEntity.getCall().getEvaluationVersion())); responseBean.setComments(applicationEntity.getComments()); responseBean.setCompanyId(applicationEntity.getCompanyId()); Optional assignedApplicationsOptional = assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationEntity.getId()); if(assignedApplicationsOptional.isPresent()){ responseBean.setAssignedUserId(assignedApplicationsOptional.get().getUserId()); UserEntity user = userService.validateUser(assignedApplicationsOptional.get().getUserId()); String firstName = user.getFirstName() != null ? user.getFirstName() : ""; String lastName = user.getLastName() != null ? user.getLastName() : ""; String userName = String.join(" ", firstName, lastName).trim(); responseBean.setAssignedUserName(userName); } CompanyEntity company=companyService.validateCompany(applicationEntity.getCompanyId()); responseBean.setCompanyName(company.getCompanyName()); if(applicationEntity.getProtocol() != null) { responseBean.setProtocolNumber(applicationEntity.getProtocol().getProtocolNumber()); } responseBean.setAmountAccepted(applicationEntity.getAmountAccepted()); responseBean.setAmountRequested(applicationEntity.getAmountRequested()); responseBean.setDateAccepted(applicationEntity.getDateAccepted()); responseBean.setDateRejected(applicationEntity.getDateRejected()); return responseBean; } public ApplicationEntity validateApplication(Long id) { log.info("Validating existence of Application with ID: {}", id); ApplicationEntity applicationEntity = applicationRepository.findById(id) .orElseThrow(() -> { log.warn("Application not found for ID: {}", id); return new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG)); }); return applicationEntity; } private ApplicationResponseBean convertApplicationEntityToApplicationResponseBean(ApplicationEntity entity) { ApplicationResponseBean response = new ApplicationResponseBean(); response.setId(entity.getId()); response.setSubmissionDate(entity.getSubmissionDate()); response.setStatus(entity.getStatus()); response.setComments(entity.getComments()); response.setCallId(entity.getCall().getId()); response.setCreatedDate(entity.getCreatedDate()); response.setUpdatedDate(entity.getUpdatedDate()); response.setAmountAccepted(entity.getAmountAccepted()); response.setAmountRequested(entity.getAmountRequested()); response.setDateAccepted(entity.getDateAccepted()); response.setDateRejected(entity.getDateRejected()); if(entity.getProtocol() != null) { response.setProtocolNumber(entity.getProtocol().getProtocolNumber()); } return response; } private ApplicationFormEntity getApplicationFormOrCreate(FormEntity formEntity, ApplicationEntity applicationEntity) { log.info("Fetching ApplicationForm for Application ID: {} and Form ID: {}", applicationEntity.getId(), formEntity.getId()); ApplicationFormEntity applicationFormEntity = applicationFormRepository.findByApplicationIdAndFormId(applicationEntity.getId(), formEntity.getId()); ApplicationFormEntity oldApplicationFormEntity = Utils.getClonedEntityForData(applicationFormEntity); if (applicationFormEntity == null) { log.info("No existing ApplicationForm found. Creating new ApplicationForm for Application ID: {}, Form ID: {}", applicationEntity.getId(), formEntity.getId()); applicationFormEntity = createApplicationFormEntity(applicationEntity, formEntity); /** This code is responsible for adding a version history log for the "Create application form" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(oldApplicationFormEntity).newData(applicationFormEntity) .build()); } return applicationFormEntity; } public List createOrUpdateMultipleFormFields(List formFieldResponseBeans, ApplicationFormEntity applicationFormEntity, FormEntity formEntity) { FieldValidator fieldValidator = FieldValidator.create(); List existingFields = applicationFormFieldRepository.findByApplicationFormId(applicationFormEntity.getId()); List applicationFormFieldEntities=formFieldResponseBeans.stream().map(requestBean -> createOrUpdateApplicationFormField(requestBean, applicationFormEntity, existingFields, formEntity,fieldValidator)) .collect(Collectors.toList()); fieldValidator.validate(); return applicationFormFieldEntities; } public ApplicationFormFieldEntity createOrUpdateApplicationFormField(ApplicationFormFieldRequestBean applicationFormFieldRequestBean, ApplicationFormEntity applicationFormEntity, List applicationFormFieldEntities, FormEntity formEntity,FieldValidator fieldValidator) { log.info("Starting createOrUpdateApplicationFormField for ApplicationForm ID: {}", applicationFormEntity.getId()); ApplicationFormFieldEntity applicationFormFieldEntity = new ApplicationFormFieldEntity(); List newDocumentIds = validateFileUploadDocuments(applicationFormFieldRequestBean, formEntity); validateFileUploadDocuments(applicationFormFieldRequestBean, formEntity); VersionActionTypeEnum actionType = VersionActionTypeEnum.INSERT; List contentResponseBeans = formDao.convertFormEntityToFormResponseBean(formEntity).getContent(); // contentResponseBeans.stream() // .filter(content -> "numberinput".equals(content.getName()) && content.getId().toString().equals(applicationFormFieldRequestBean.getFieldId())) // .map(ContentResponseBean::getSettings) // .flatMap(List::stream) // .filter(setting -> "isRequestedAmount".equals(setting.getName()) && Boolean.TRUE.equals(setting.getValue())) // .findFirst() // .ifPresent(setting -> { // Object fieldValue = applicationFormFieldRequestBean.getFieldValue(); // if(fieldValue!=null) { // try { // BigDecimal amountRequested = new BigDecimal(fieldValue.toString()); // applicationFormEntity.getApplication().setAmountRequested(amountRequested); // log.info("Set amountRequested to {} for Application ID: {}", amountRequested, applicationFormEntity.getApplication().getId()); // } catch (NumberFormatException e) { // log.error("Invalid number format for requested amount: {}", fieldValue, e); // throw new IllegalArgumentException("Field value is not a valid number: " + fieldValue, e); // } // } // }); contentResponseBeans.stream() .filter(content -> content.getId().toString().equals(applicationFormFieldRequestBean.getFieldId())) .findFirst() .ifPresent(content -> { Object fieldValue = applicationFormFieldRequestBean.getFieldValue(); if (fieldValue == null) { return; } // Convert settings list to a map Map settingMap = content.getSettings().stream() .collect(Collectors.toMap(SettingResponseBean::getName, SettingResponseBean::getValue, (v1, v2) -> v1)); String fieldType = content.getName(); // Define handlers for different (fieldType + settingName) combinations Map handlers = new HashMap<>(); // Add handler for isRequestedAmount if ("numberinput".equals(fieldType) && Boolean.TRUE.equals(settingMap.get("isRequestedAmount"))) { handlers.put("isRequestedAmount", () -> { try { BigDecimal amountRequested = new BigDecimal(fieldValue.toString()); applicationFormEntity.getApplication().setAmountRequested(amountRequested); log.info("Set amountRequested to {} for Application ID: {}", amountRequested, applicationFormEntity.getApplication().getId()); } catch (NumberFormatException e) { log.error("Invalid number format for requested amount: {}", fieldValue, e); throw new IllegalArgumentException("Field value is not a valid number: " + fieldValue, e); } }); } // Add handler for isPecEmail if ("textinput".equals(fieldType) && Boolean.TRUE.equals(settingMap.get("isPecEmail"))) { handlers.put("isPecEmail", () -> { applicationFormEntity.getApplication().setPecEmail(fieldValue.toString()); log.info("Set PEC to {} for Application ID: {}", fieldValue, applicationFormEntity.getApplication().getId()); }); } // Run all applicable handlers handlers.values().forEach(Runnable::run); }); ApplicationFormFieldEntity oldApplicationFormFieldData = null; if (applicationFormFieldEntities == null || applicationFormFieldEntities.isEmpty()) { applicationFormFieldEntity.setApplicationForm(applicationFormEntity); } else { for (ApplicationFormFieldEntity applicationFormFieldEntity1 : applicationFormFieldEntities) { if (applicationFormFieldEntity1.getFieldId().equals(applicationFormFieldRequestBean.getFieldId())) { applicationFormFieldEntity = applicationFormFieldEntity1; oldApplicationFormFieldData = Utils.getClonedEntityForData(applicationFormFieldEntity); if (applicationFormEntity.getForm().getId().equals(applicationFormEntity.getApplication().getCall().getInitialForm()) && checkIfRequestFieldIsDifferent(applicationFormFieldEntity1, applicationFormFieldRequestBean)) { validateRequiredFields(applicationFormEntity.getForm(), applicationFormEntity.getApplication(), applicationFormFieldRequestBean.getFieldId()); } actionType = VersionActionTypeEnum.UPDATE; break; } else { applicationFormFieldEntity.setApplicationForm(applicationFormEntity); } } } calculationProcessForFormula(applicationFormEntity,contentResponseBeans,applicationFormFieldRequestBean,fieldValidator); Utils.setIfUpdated(applicationFormFieldEntity::getFieldId, applicationFormFieldEntity::setFieldId, applicationFormFieldRequestBean.getFieldId()); if (applicationFormFieldRequestBean.getFieldValue() != null) { updateDocumentDeletionStatus(applicationFormFieldEntity, applicationFormFieldRequestBean, formEntity, newDocumentIds, null, false); applicationFormFieldEntity.setFieldValue(Utils.convertObjectToJsonString(applicationFormFieldRequestBean.getFieldValue())); } if (applicationFormFieldRequestBean.getFieldValue() == null) { updateDocumentDeletionStatus(applicationFormFieldEntity, applicationFormFieldRequestBean, formEntity, newDocumentIds, null, false); } if (applicationFormFieldRequestBean.getFieldValue() != null) { applicationFormFieldEntity.setFieldValue(Utils.convertObjectToJsonString(applicationFormFieldRequestBean.getFieldValue())); } else { applicationFormFieldEntity.setFieldValue(null); } ApplicationFormFieldEntity applicationFormField = applicationFormFieldRepository.save(applicationFormFieldEntity); /** This code is responsible for adding a version history log for the "Create update application form" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(actionType).oldData(oldApplicationFormFieldData).newData(applicationFormField).build()); log.info("Version history logged for action: {}, Field ID: {}", actionType, applicationFormFieldEntity.getFieldId()); return applicationFormField; } private Boolean checkIfRequestFieldIsDifferent(ApplicationFormFieldEntity applicationFormFieldEntity, ApplicationFormFieldRequestBean applicationFormFieldRequestBean) { // Retrieve the field values from both objects String entityFieldValue = applicationFormFieldEntity.getFieldValue(); Object requestFieldValue = applicationFormFieldRequestBean.getFieldValue(); // Check if both are null if (entityFieldValue == null && requestFieldValue == null) { return false; // No difference if both are null } // Compare values Boolean check = !Objects.equals(entityFieldValue, requestFieldValue); // Additional comparison if both are non-null if (Boolean.TRUE.equals(check) && entityFieldValue != null && requestFieldValue != null) { check = !entityFieldValue.equals(requestFieldValue.toString()); } return check; } void updateDocumentDeletionStatus(ApplicationFormFieldEntity applicationFormFieldEntity, ApplicationFormFieldRequestBean applicationFormFieldRequestBean, FormEntity formEntity, List newDocumentIds, List preInstructorDocumentId,boolean isPreInstructor) { if (newDocumentIds == null) { newDocumentIds = Collections.emptyList(); } if (preInstructorDocumentId == null) { preInstructorDocumentId = Collections.emptyList(); } List contentResponseBeans = formDao.convertFormEntityToFormResponseBean(formEntity).getContent(); for (ContentResponseBean contentResponseBean : contentResponseBeans) { if (Boolean.FALSE.equals(contentResponseBean.getName().equals("fileupload") || contentResponseBean.getName().equals("fileselect"))) { return; } } if(!isPreInstructor){ List currentDocumentIds = parseDocumentIds(applicationFormFieldEntity.getFieldValue()); if (Boolean.TRUE.equals(newDocumentIds.isEmpty())) { currentDocumentIds.forEach(docId -> documentService.deleteFile(docId)); } else { List finalNewDocumentIds = newDocumentIds; List documentsToDelete = currentDocumentIds.stream() .filter(docId -> !finalNewDocumentIds.contains(docId)) .toList(); documentsToDelete.forEach(docId -> documentService.deleteFile(docId)); }} else{ List currentDocumentIds = parseDocumentIds(applicationFormFieldEntity.getFieldValue()); if (Boolean.TRUE.equals(preInstructorDocumentId.isEmpty())) { currentDocumentIds.forEach(docId -> documentService.deleteFile(docId)); } else { List preInstructorDocIds = preInstructorDocumentId.stream() .map(Long::valueOf) .collect(Collectors.toList()); List documentsToDelete = currentDocumentIds.stream() .filter(docId -> !preInstructorDocIds.contains(docId)) .toList(); documentsToDelete.forEach(docId -> documentService.deleteFile(docId)); }} } private List parseDocumentIds(String fieldValue) { if (fieldValue == null || fieldValue.isEmpty()) { return Collections.emptyList(); } if (fieldValue.contains(",")) { return Arrays.stream(fieldValue.split(",")) .map(String::trim) .map(Long::parseLong) .collect(Collectors.toList()); } else { try { return Collections.singletonList(Long.parseLong(fieldValue.trim())); } catch (NumberFormatException e) { e.printStackTrace(); return Collections.emptyList(); } } } private List validateFileUploadDocuments(ApplicationFormFieldRequestBean applicationFormFieldRequestBean, FormEntity formEntity) { List documentIds=null; // List contentResponseBeans=Utils.convertJsonStringToList(formEntity.getContent(),ContentResponseBean.class); List contentResponseBeans=formDao.convertFormEntityToFormResponseBean(formEntity).getContent(); log.debug("Validating file upload documents for field ID: {} in form ID: {}", applicationFormFieldRequestBean.getFieldId(), formEntity.getId()); for (ContentResponseBean contentResponseBean:contentResponseBeans){ if(Boolean.TRUE.equals(contentResponseBean.getName().equals("fileupload")) || Boolean.TRUE.equals(contentResponseBean.getName().equals("fileselect"))) { if (contentResponseBean.getId().equals(applicationFormFieldRequestBean.getFieldId())) { Object fieldValueObject = applicationFormFieldRequestBean.getFieldValue(); if (fieldValueObject instanceof String) { // Safely cast the object to a string String documentId = (String) fieldValueObject; // Now you can use documentId as needed documentIds = validateDocumentIds(documentId); log.info("Validated document IDs: {}", documentIds); } } } } return documentIds; } public List validateDocumentIds(String documentId) { if (documentId != null && !documentId.isEmpty()) { log.info("Validating document IDs: {}", documentId); return Arrays.stream(documentId.split(",")) .map(Long::parseLong) .peek(docId -> documentService.validateDocument(docId)) .collect(Collectors.toList()); } return Collections.emptyList(); } public ApplicationFormFieldEntity validateApplicationFormField(Long applicationFormFieldId) { Optional applicationFormFieldEntity = applicationFormFieldRepository.findById(applicationFormFieldId); if (applicationFormFieldEntity.isEmpty()) { throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_FORM_FIELD_NOT_FOUND)); } return applicationFormFieldEntity.get(); } public List saveApplicationFormFieldEntities(List applicationFormFieldEntities) { List applicationFormFieldEntities1 = applicationFormFieldRepository.saveAll(applicationFormFieldEntities); return applicationFormFieldEntities1; } public List convertApplicationFormFieldEntitiesToApplicationFormFieldResponseBeans(List applicationFormFieldEntities, Long applicationFormId) { return applicationFormFieldEntities.stream() .map(requestBean -> convertApplicationFormFieldEntityToApplicationFormFieldResponseBean(requestBean, applicationFormId)) .collect(Collectors.toList()); } public ApplicationFormFieldResponseBean convertApplicationFormFieldEntityToApplicationFormFieldResponseBean(ApplicationFormFieldEntity applicationFormFieldEntity, Long applicationFormId) { ApplicationFormFieldResponseBean applicationFormFieldResponseBean = new ApplicationFormFieldResponseBean(); applicationFormFieldResponseBean.setApplicationFormId(applicationFormId); applicationFormFieldResponseBean.setFieldId(applicationFormFieldEntity.getFieldId()); if(applicationFormFieldEntity.getFieldValue() != null) { applicationFormFieldResponseBean.setFieldValue(Utils.getFieldValueAsObject(applicationFormFieldEntity.getFieldValue())); } applicationFormFieldResponseBean.setId(applicationFormFieldEntity.getId()); applicationFormFieldResponseBean.setCreatedDate(applicationFormFieldEntity.getCreatedDate()); applicationFormFieldResponseBean.setUpdatedDate(applicationFormFieldEntity.getUpdatedDate()); return applicationFormFieldResponseBean; } public ApplicationEntity saveApplicationEntity(ApplicationEntity application) { ApplicationEntity applicationEntity = applicationRepository.save(application); /** This code is responsible for adding a version history log for "Create application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(applicationEntity).build()); return applicationEntity; } public ApplicationGetResponseBean getApplicationByFormId(HttpServletRequest request, Long applicationId, Long formId) { log.info("Received request to get application by formId. ApplicationId: {}, FormId: {}", applicationId, formId); List formApplicationResponses = new ArrayList<>(); List formEntities = new ArrayList<>(); UserEntity userEntity = validator.validateUser(request); boolean isBeneficiary = Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi()); ApplicationEntity applicationEntity = isBeneficiary ? applicationRepository.findByIdAndUserIdAndIsDeletedFalse(applicationId, userEntity.getId()) .orElseThrow(() -> new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG))) : applicationRepository.findById(applicationId) .stream().findFirst() .orElseThrow(() -> new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG))); if (formId != null) { FormEntity formEntity = formService.validateForm(formId); Optional application = applicationRepository.findByIdAndUserIdAndCallIdAndIsDeletedFalse(applicationId, userEntity.getId(), formEntity.getCall().getId()); applicationEntity=application.get(); formEntities.add(formEntity); addFormApplication(formEntity, applicationEntity, formApplicationResponses); } else { List applicationFormEntities = applicationFormRepository.findByApplicationId(applicationEntity.getId()); List sequencedApplicationFormEntity = new ArrayList<>(); Long formIdMiddle = null; List flowEdgesList = flowEdgesRepository.findBySourceIdAndCallId( applicationEntity.getCall().getInitialForm(), applicationEntity.getCall().getId()); if (!flowEdgesList.isEmpty()) { if (flowEdgesList.size() == 1) { formIdMiddle = flowEdgesList.get(0).getTargetId(); } else { List nextFormIds = flowEdgesList.stream() .map(FlowEdgesEntity::getTargetId) .toList(); FlowDataEntity flowDataEntity = flowDataRepository.findByFormIdAndCallId( applicationEntity.getCall().getInitialForm(), applicationEntity.getCall().getId()); ApplicationFormFieldEntity applicationFormFieldEntity = applicationFormFieldRepository .findByFieldIdAndApplicationFormFormIdAndApplicationFormApplicationId( flowDataEntity.getChoosenField(), applicationEntity.getCall().getInitialForm(), applicationEntity.getId()) .orElse(null); if (applicationFormFieldEntity != null) { formIdMiddle = flowDataRepository.findByChoosenValueAndFormIdIn( applicationFormFieldEntity.getFieldValue(), nextFormIds) .map(FlowDataEntity::getFormId) .orElse(null); } } } List applicationFormIds = new ArrayList<>(); applicationFormIds.add(applicationEntity.getCall().getInitialForm()); if (formIdMiddle != null && formIdMiddle > 0) { applicationFormIds.add(formIdMiddle); } applicationFormIds.add(applicationEntity.getCall().getFinalForm()); if (applicationFormEntities.size() == 3) { for (Long applicationFormId : applicationFormIds) { for (ApplicationFormEntity applicationFormEntity : applicationFormEntities) { if (applicationFormEntity.getForm().getId().equals(applicationFormId)) { sequencedApplicationFormEntity.add(applicationFormEntity); FormEntity form = formService.validateForm(applicationFormId); formEntities.add(form); addFormApplication(form, applicationEntity, formApplicationResponses); } } } }else { ApplicationFormEntity applicationFormEntity1=applicationFormRepository.findByApplicationIdAndFormId(applicationEntity.getId(),applicationEntity.getCall().getInitialForm()); sequencedApplicationFormEntity.add(applicationFormEntity1); FormEntity form1 = formService.validateForm(applicationFormEntity1.getForm().getId()); formEntities.add(form1); addFormApplication(form1, applicationEntity, formApplicationResponses); ApplicationFormEntity applicationFormEntity2=applicationFormRepository.findByApplicationIdAndFormId(applicationEntity.getId(),applicationEntity.getCall().getFinalForm()); sequencedApplicationFormEntity.add(applicationFormEntity2); FormEntity form2= formService.validateForm(applicationFormEntity2.getForm().getId()); formEntities.add(form2); addFormApplication(form2, applicationEntity, formApplicationResponses); } } return createApplicationGetResponseBean(applicationEntity, formEntities, formApplicationResponses); } private boolean isBeneficiary(UserEntity userEntity) { RoleStatusEnum roleStatus = RoleStatusEnum.valueOf(userEntity.getRoleEntity().getRoleType()); boolean isBeneficiary = RoleStatusEnum.ROLE_BENEFICIARY.equals(roleStatus); return isBeneficiary; } private void addFormApplication(FormEntity formEntity, ApplicationEntity applicationEntity, List formApplicationResponses) { FormApplicationResponse formApplicationResponse = processForm(formEntity, applicationEntity); if(formApplicationResponse.getContent() != null && formApplicationResponse.getFormFields() != null) { formApplicationResponses.add(formApplicationResponse); } } public FormApplicationResponse processForm(FormEntity formEntity, ApplicationEntity applicationEntity) { FormApplicationResponse formApplicationResponse = createFormApplicationResponse(formEntity); List applicationFormFieldResponseBeans =new ArrayList<>(); ApplicationFormEntity applicationFormEntity = applicationFormRepository.findByApplicationIdAndFormId(applicationEntity.getId(), formEntity.getId()); if(applicationFormEntity!=null) { List applicationFormFieldEntities = applicationFormFieldRepository.findByApplicationFormId(applicationFormEntity.getId()); // formApplicationResponse = createFormApplicationResponse(formEntity); applicationFormFieldResponseBeans = createApplicationFormFieldResponse(applicationFormFieldEntities, applicationFormEntity,applicationFormFieldResponseBeans); formApplicationResponse.setFormFields(applicationFormFieldResponseBeans); } return formApplicationResponse; } private ApplicationGetResponseBean createApplicationGetResponseBean(ApplicationEntity applicationEntity, List formEntities, List formApplicationResponses) { ApplicationGetResponseBean applicationGetResponseBean = createApplicationGetResponseBean(applicationEntity); applicationGetResponseBean.setForm(formApplicationResponses); return applicationGetResponseBean; } private ApplicationGetResponseBean createApplicationGetResponseBean(ApplicationEntity applicationEntity) { ApplicationGetResponseBean applicationGetResponseBean = new ApplicationGetResponseBean(); applicationGetResponseBean.setId(applicationEntity.getId()); applicationGetResponseBean.setStatus(applicationEntity.getStatus()); applicationGetResponseBean.setComments(applicationEntity.getComments()); applicationGetResponseBean.setSubmissionDate(applicationEntity.getSubmissionDate()); applicationGetResponseBean.setCallId(applicationEntity.getCall().getId()); applicationGetResponseBean.setCallTitle(applicationEntity.getCall().getName()); applicationGetResponseBean.setCompanyId(applicationEntity.getCompanyId()); applicationGetResponseBean.setAmountAccepted(applicationEntity.getAmountAccepted()); applicationGetResponseBean.setAmountRequested(applicationEntity.getAmountRequested()); applicationGetResponseBean.setDateAccepted(applicationEntity.getDateAccepted()); applicationGetResponseBean.setDateRejected(applicationEntity.getDateRejected()); if(applicationEntity.getProtocol() != null) { applicationGetResponseBean.setProtocolNumber(applicationEntity.getProtocol().getProtocolNumber()); } CompanyEntity company=companyService.validateCompany(applicationEntity.getCompanyId()); applicationGetResponseBean.setCompanyName(company.getCompanyName()); return applicationGetResponseBean; } private FormApplicationResponse createFormApplicationResponse(FormEntity formEntity) { FormApplicationResponse formApplicationResponse=new FormApplicationResponse(); formApplicationResponse.setId(formEntity.getId()); formApplicationResponse.setLabel(formEntity.getLabel()); formApplicationResponse.setCallId(formEntity.getCall().getId()); // formApplicationResponse.setContent(Utils.convertJsonStringToList(formEntity.getContent(), ContentResponseBean.class) formApplicationResponse.setContent(formDao.convertFormEntityToFormResponseBean(formEntity).getContent()); return formApplicationResponse; } public ApplicationResponse createApplicationByCallId(CompanyEntity companyEntity, ApplicationRequest applicationRequest, Long callId, UserEntity userEntity) { log.info("Start creating application for CallId: {}, UserId: {}, CompanyId: {}", callId, userEntity.getId(), companyEntity.getId()); CallEntity call = callService.validateCall(callId); UserWithCompanyEntity userWithCompanyEntity=companyService.getUserWithCompany(userEntity.getId(),companyEntity.getId()); checkCallEndDate(call); // call = callService.validatePublishedCall(call.getId()); // checkIfApplicationExists(call, userWithCompanyEntity, userEntity); HubEntity hubEntity = hubService.valdateHub(call.getHub().getId()); if(hubEntity.getUniqueUuid().equals(defaultHubUuid)){ checkIfApplicationExists(call, userWithCompanyEntity, userEntity); } ApplicationEntity applicationEntity = createApplicationEntity(userEntity, call, userWithCompanyEntity); applicationEntity.setComments(applicationRequest.getComments()); applicationEntity = saveApplicationEntity(applicationEntity); return getApplicationResponse(applicationEntity); } // public void checkIfApplicationExists(CallEntity call, UserWithCompanyEntity userWithCompanyEntity, UserEntity userEntity){ // Optional applicationEntity=applicationRepository.findByUserIdAndUserWithCompanyIdAndCallIdAndIsDeletedFalse(userEntity.getId(), userWithCompanyEntity.getId(),call.getId()); // if(applicationEntity.isPresent()){ // throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_EXISTS)); // } // } public void checkIfApplicationExists(CallEntity call, UserWithCompanyEntity userWithCompanyEntity, UserEntity userEntity){ log.info("Checking existing applications for UserId: {}, UserWithCompanyId: {}, CallId: {}", userEntity.getId(), userWithCompanyEntity.getId(), call.getId()); List applications = applicationRepository.findByUserIdAndUserWithCompany_IdAndCall_IdAndIsDeletedFalseAndStatusNot( userEntity.getId(), userWithCompanyEntity.getId(), call.getId(), ApplicationStatusTypeEnum.REJECTED.name() ); if (!applications.isEmpty()) { log.warn("Application already exists for UserId: {}, UserWithCompanyId: {}, CallId: {}. Applications found: {}", userEntity.getId(), userWithCompanyEntity.getId(), call.getId(), applications.size()); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_EXISTS)); } } public String generateRandomFiveDigitNumber() { int number = 10000 + random.nextInt(90000); // Generates a number from 10000 to 99999 return String.valueOf(number); } public ApplicationResponse updateApplicationStatus(HttpServletRequest request, Long applicationId, ApplicationStatusTypeEnum status) { log.info("Updating status for Application id : " + applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); //cloned entity for old application data ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(applicationEntity); HubEntity hub=hubService.valdateHub(applicationEntity.getHubId()); UserEntity userEntity = userService.validateUser(applicationEntity.getUserId()); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); if (ApplicationStatusTypeEnum.SUBMIT.getValue().equals(applicationEntity.getStatus())) { log.warn("Attempt to change status after submission denied | applicationId: {}", applicationId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_SUBMITTED_CANNOT_CHANGE)); } if (Boolean.TRUE.equals(applicationEntity.getStatus().equals(status.getValue()))) { log.warn("Requested status is the same as current status | applicationId: {}, status: {}", applicationId, status); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_IN_PREVIOUS_STATUS)); } if (status.equals(ApplicationStatusTypeEnum.APPOINTMENT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.NDG.getValue()))){ String appointmentId = generateRandomFiveDigitNumber(); applicationEntity.setAppointmentId(appointmentId); applicationEntity.setStatus(ApplicationStatusTypeEnum.APPOINTMENT.getValue()); } if (status.equals(ApplicationStatusTypeEnum.SUBMIT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.READY.getValue()))) { CompanyEntity company=companyService.validateCompany(applicationEntity.getCompanyId()); // callService.validatePublishedCall(applicationEntity.getCall().getId(), userEntity.getHub().getId()); checkCallEndDate(applicationEntity.getCall()); Long protocolNumber = protocolDao.getProtocolNumber(userEntity.getHub()); ProtocolEntity protocolEntity = protocolDao.createProtocolEntity(applicationEntity, protocolNumber, userEntity.getHub().getId(),true); protocolDao.saveProtocolEntity(protocolEntity); applicationEntity.setProtocol(protocolEntity); if(Boolean.TRUE.equals(hub.getUniqueUuid().equals(sviluppumbriaUuid))) { protocolEntity = protocolDao.createExternalProtocol(applicationEntity, company, protocolEntity); } applicationEntity.setStatus(ApplicationStatusTypeEnum.SUBMIT.getValue()); applicationEntity.setSubmissionDate(protocolEntity.getCreatedDate()); applicationEntity = applicationRepository.save(applicationEntity); Map placeHolders=notificationDao.sendNotificationToBeneficiary(applicationEntity,NotificationTypeEnum.APPLICATION_SUBMISSION); notificationDao.sendNotificationToSuperUser(applicationEntity,placeHolders,NotificationTypeEnum.APPLICATION_SUBMISSION); /** This code is responsible for adding a version history log for "Update application status" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEntity).newData(applicationEntity).build()); sendMailToUserAndCompany(userEntity, applicationEntity,company); sendMailTodefaultSystemAndGepafin(userEntity, applicationEntity); applicationEntity.setStatus(status.getValue()); log.info("Status updated to SUBMIT for applicationId: " + applicationId); } if (status.equals(ApplicationStatusTypeEnum.DRAFT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.AWAITING.getValue()))) { checkCallEndDate(applicationEntity.getCall()); applicationEntity.setStatus(status.getValue()); log.info("Status updated to DRAFT for applicationId: " + applicationId); } if (status.equals(ApplicationStatusTypeEnum.AWAITING) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.READY.getValue()))) { checkCallEndDate(applicationEntity.getCall()); ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository.findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); deleteSignedDocumentFromS3(applicationSignedDocument); applicationEntity.setStatus(status.getValue()); log.info("Status updated to AWAITING for applicationId: " + applicationId); } applicationEntity = applicationRepository.save(applicationEntity); log.info("Application status updated successfully | applicationId: {}, newStatus: {}", applicationId, applicationEntity.getStatus()); if (!status.equals(ApplicationStatusTypeEnum.SUBMIT)) { /** This code is responsible for adding a version history log for "Update application status" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEntity).newData(applicationEntity).build()); } return getApplicationResponse(applicationEntity); } public Integer calculateProgress(Long totalSteps, Long completedSteps) { if (FieldValidator.isNullOrZero(totalSteps)) { throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.TOTAL_STEPS_NOT_BE_ZERO)); } if (completedSteps < 0 || completedSteps > totalSteps) { throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.COMPLETED_STEPS_NOT_VALID)); } double progress = ((double) completedSteps / totalSteps) * 100; return (int) Math.round(progress); } public void validateFormFields(ApplicationRequestBean request, FormEntity formEntity) { // List contentResponseBeans=Utils.convertJsonStringToList(formEntity.getContent(),ContentResponseBean.class); List contentResponseBeans=formDao.convertFormEntityToFormResponseBean(formEntity).getContent(); List requestFields = request.getFormFields(); Map contentMap = contentResponseBeans.stream() .collect(Collectors.toMap(ContentResponseBean::getId, ContentResponseBean::getLabel)); // Change getLabel() if needed FieldValidator validator = FieldValidator.create(); for (ApplicationFormFieldRequestBean requestField : requestFields) { String fieldId = requestField.getFieldId(); if (!contentMap.containsKey(fieldId)) { validator.addError(MessageFormat.format(Translator.toLocale(GepafinConstant.FIELD_ID_NOT_FOUND), fieldId)); } } validator.validate(); } public void validateRequiredFields(FormEntity formEntity, ApplicationEntity applicationEntity, String fieldId) { FlowDataEntity flowDataEntity = flowDataRepository.findByFormIdAndCallId( formEntity.getId(), applicationEntity.getCall().getId()); if (flowDataEntity == null) { return; } ApplicationFormFieldEntity applicationFormFieldEntity = applicationFormFieldRepository .findByFieldIdAndApplicationFormFormIdAndApplicationFormApplicationId( flowDataEntity.getChoosenField(), formEntity.getId(), applicationEntity.getId()) .orElse(null); if (applicationFormFieldEntity == null || !fieldId.equals(applicationFormFieldEntity.getFieldId())) { return; } List nextFormIds = flowEdgesRepository.findBySourceIdAndCallId( formEntity.getId(), applicationEntity.getCall().getId()) .stream() .map(FlowEdgesEntity::getTargetId) .collect(Collectors.toList()); Optional nextFormIdOptional = flowDataRepository.findByChoosenValueAndFormIdIn( applicationFormFieldEntity.getFieldValue(), nextFormIds) .map(FlowDataEntity::getFormId); if (nextFormIdOptional.isPresent()) { Long nextFormId = nextFormIdOptional.get(); FormEntity nextForm = formService.validateForm(nextFormId); ApplicationFormEntity nextApplicationFormEntity = applicationFormRepository.findByApplicationIdAndFormId( applicationEntity.getId(), nextForm.getId()); if (nextApplicationFormEntity != null) { List nextApplicationFormFieldEntities = applicationFormFieldRepository.findByApplicationFormId(nextApplicationFormEntity.getId()); nextApplicationFormFieldEntities.forEach(applicationFormFieldEntityToDelete -> /** This code is responsible for adding a version history log for "Deleting application form field" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(applicationFormFieldEntityToDelete).build())); applicationFormFieldRepository.deleteAll(nextApplicationFormFieldEntities); /** This code is responsible for adding a version history log for the "Deleting next application form" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(nextApplicationFormEntity).build()); applicationFormRepository.delete(nextApplicationFormEntity); } } } private void sendMailToUserAndCompany(UserEntity userEntity, ApplicationEntity applicationEntity,CompanyEntity company) { log.info("Preparing to send submission email | applicationId: {}, userId: {}", applicationEntity.getId(), userEntity.getId()); CallEntity call =applicationEntity.getCall(); UserWithCompanyEntity userWithCompany=companyService.getUserWithCompany(userEntity.getId(),company.getId()); ProtocolEntity protocol= applicationEntity.getProtocol(); HubEntity hub = hubService.valdateHub(applicationEntity.getHubId()); SystemEmailTemplateResponse systemEmailTemplateResponse = systemEmailTemplatesService .retrieveTemplateByTypeAndCall(SystemEmailTemplatesEntityTypeEnum.APPLICATION_SUBMISSION_TO_USER_AND_COMPANY, hub, null); // Create the map for subject placeholders Map subjectPlaceholders = new HashMap<>(); subjectPlaceholders.put("{{call_name}}", call.getName()); subjectPlaceholders.put("{{company_name}}", company.getCompanyName()); // Create the map for body placeholders Map bodyPlaceholders = new HashMap<>(); bodyPlaceholders.put("{{call_name}}", call.getName()); String protocolNumber=applicationEntity.getProtocol().getExternalProtocolNumber(); if(protocolNumber==null){ protocolNumber= String.valueOf(applicationEntity.getProtocol().getProtocolNumber()); } bodyPlaceholders.put("{{protocol_number}}",protocolNumber); String protocolDate= DateTimeUtil.formatLocalDateTime(protocol.getCreatedDate(), GepafinConstant.DD_MM_YYYY); if(protocol.getExternalProtocolDate()!=null){ protocolDate= DateTimeUtil.formatLocalDateTime(protocol.getExternalProtocolDate(), GepafinConstant.DD_MM_YYYY); } bodyPlaceholders.put("{{date}}", protocolDate); bodyPlaceholders.put("{{time}}", DateTimeUtil.parseLocalTimeToString(protocol.getTime(), GepafinConstant.HH_MM_SS)); // Replace placeholders in the subject and body String subject = Utils.replacePlaceholders(systemEmailTemplateResponse.getSubject(), subjectPlaceholders); String body = Utils.replacePlaceholders(systemEmailTemplateResponse.getHtmlContent(), bodyPlaceholders); EmailLogRequest emailLogRequest=emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(),RecipientTypeEnum.USER,userEntity.getId(),userEntity.getEmail(),userEntity.getId(),applicationEntity.getId(),null,applicationEntity.getCall().getId()); String email = userEntity.getEmail(); if (userEntity.getBeneficiary() != null) { emailLogRequest.setRecipientType(RecipientTypeEnum.BENEFICIARY); if(Boolean.TRUE.equals(hub.getUniqueUuid().equals(defaultHubUuid))){ email=applicationEntity.getPecEmail(); }else { email = userEntity.getBeneficiary().getEmail(); } emailLogRequest.setRecipientId(userEntity.getBeneficiary().getId()); } emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email),emailLogRequest); List recipientEmails = new ArrayList<>(); // recipientEmails.add(email); String companyEmail = userWithCompany.getEmail(); String contactEmail = userWithCompany.getContactEmail(); if(Boolean.TRUE.equals(hub.getUniqueUuid().equals(defaultHubUuid))){ if (company.getPec()!=null) { recipientEmails.add(company.getPec()); }else { recipientEmails.add(userWithCompany.getPec()); } } else { if (companyEmail != null && !companyEmail.isEmpty()) { recipientEmails.add(companyEmail); } if (contactEmail != null && !contactEmail.isEmpty() && !contactEmail.equals(companyEmail)) { recipientEmails.add(contactEmail); } } if(Boolean.FALSE.equals(recipientEmails.isEmpty())){ emailLogRequest.setRecipientId(applicationEntity.getCompanyId()); emailLogRequest.setRecipientType(RecipientTypeEnum.COMPANY); emailLogRequest.setRecipientEmails(String.valueOf(recipientEmails)); } emailNotificationDao.sendMail(hub.getId(), subject, body, recipientEmails,emailLogRequest); } private void sendMailTodefaultSystemAndGepafin(UserEntity userEntity, ApplicationEntity applicationEntity) { CallEntity call = applicationEntity.getCall(); CompanyEntity company=companyService.validateCompany(applicationEntity.getCompanyId()); ProtocolEntity protocol = applicationEntity.getProtocol(); HubEntity hub = hubService.valdateHub(applicationEntity.getHubId()); SystemEmailTemplateResponse systemEmailTemplateResponse = systemEmailTemplatesService .retrieveTemplateByTypeAndCall(SystemEmailTemplatesEntityTypeEnum.APPLICATION_SUBMISSION_TO_GEPAFIN, hub, null); // Create the map for subject placeholders Map subjectPlaceholders = new HashMap<>(); subjectPlaceholders.put("{{call_name}}", call.getName()); subjectPlaceholders.put("{{company_name}}", company.getCompanyName()); // Create the map for body placeholders Map bodyPlaceholders = new HashMap<>(); bodyPlaceholders.put("{{call_name}}", call.getName()); String protocolNumber=applicationEntity.getProtocol().getExternalProtocolNumber(); if(protocolNumber==null){ protocolNumber= String.valueOf(applicationEntity.getProtocol().getProtocolNumber()); } String protocolDate= DateTimeUtil.formatLocalDateTime(protocol.getCreatedDate(), GepafinConstant.DD_MM_YYYY); if(protocol.getExternalProtocolDate()!=null){ protocolDate= DateTimeUtil.formatLocalDateTime(protocol.getExternalProtocolDate(), GepafinConstant.DD_MM_YYYY); } bodyPlaceholders.put("{{protocol_number}}", protocolNumber); bodyPlaceholders.put("{{date}}",protocolDate); bodyPlaceholders.put("{{time}}", DateTimeUtil.parseLocalTimeToString(protocol.getTime(), GepafinConstant.HH_MM_SS)); // Replace placeholders in the subject and body String subject = Utils.replacePlaceholders(systemEmailTemplateResponse.getSubject(), subjectPlaceholders); String body = Utils.replacePlaceholders(systemEmailTemplateResponse.getHtmlContent(), bodyPlaceholders); EmailLogRequest emailLogRequest=emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(),RecipientTypeEnum.PROPERTIES,null,userEntity.getEmail(),userEntity.getId(),applicationEntity.getId(),null,applicationEntity.getCall().getId()); List hubEmails = Arrays.stream(hub.getEmail().split(",")) .map(String::trim) .filter(email -> !email.isEmpty()) .toList(); emailLogRequest.setRecipientEmails(hub.getEmail()); emailNotificationDao.sendMail(hub.getId(), subject, body,hubEmails,emailLogRequest); emailLogRequest.setRecipientEmails(rinaldoEmail); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(rinaldoEmail),emailLogRequest); } public ApplicationSignedDocumentResponse uploadSignedDocument(HttpServletRequest request, Long applicationId, MultipartFile file) { log.info("Received request to upload signed document | applicationId: {}, fileName: {}", applicationId, file.getOriginalFilename()); ApplicationEntity applicationEntity = validateApplication(applicationId); checkCallEndDate(applicationEntity.getCall()); //cloned entity for old data ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(applicationEntity); validateFileTypeForCall(file, applicationEntity); ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository.findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); //cloned entity for old data ApplicationSignedDocumentEntity oldApplicationSingedDocumentData = Utils.getClonedEntityForData(applicationSignedDocument); if (applicationSignedDocument != null) { log.info("Existing active signed document found and will be deleted | applicationId: {}, fileName: {}", applicationId, applicationSignedDocument.getFileName()); deleteSignedDocumentFromS3(applicationSignedDocument); } String hash =""; try { hash = FileHashUtil.calculateSHA256(file.getInputStream()); } catch (IOException e) { throw new RuntimeException(e); } UploadFileOnAmazonS3Response uploadFileOnAmazonS3 = uploadFileOnAmazonS3ForUserSignedDocument(file, applicationEntity.getCall().getId(), applicationId); log.info("File uploaded to S3 successfully | applicationId: {}", applicationId); applicationSignedDocument = new ApplicationSignedDocumentEntity(); applicationSignedDocument.setApplication(applicationEntity); applicationSignedDocument.setFileName(uploadFileOnAmazonS3.getFileName()); applicationSignedDocument.setFilePath(uploadFileOnAmazonS3.getFilePath()); applicationSignedDocument.setStatus(ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); applicationSignedDocument.setFileHash(hash); applicationSignedDocument = applicationSignedDocumentRepository.save(applicationSignedDocument); /** This code is responsible for adding a version history log for the "assign application document" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(oldApplicationSingedDocumentData) .newData(applicationSignedDocument).build()); applicationEntity.setStatus(ApplicationStatusTypeEnum.READY.getValue()); applicationEntity = applicationRepository.save(applicationEntity); log.info("Application status updated to READY | applicationId: {}", applicationEntity.getId()); /** This code is responsible for adding a version history log for the "Create Call" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationData).newData(applicationEntity).build()); return convertApplicationSignedDocumentToApplicationSignedDocumentResponse(applicationSignedDocument); } public void deleteSignedDocumentFromS3(ApplicationSignedDocumentEntity applicationSignedDocumentEntity){ log.info("Starting soft delete of signed document | applicationSignedDocumentId: {}, fileName: {}", applicationSignedDocumentEntity.getId(), applicationSignedDocumentEntity.getFileName()); ApplicationSignedDocumentEntity oldApplicationSignedDocument = Utils.getClonedEntityForData(applicationSignedDocumentEntity); String oldS3Path = applicationSignedDocumentEntity.getFilePath(); log.debug("Old S3 path: {} ", oldS3Path); String newS3Path = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.DELETED_USER_SIGNED_DOCUMENT,applicationSignedDocumentEntity.getApplication().getCall().getId(),applicationSignedDocumentEntity.getApplication().getId(),0L); log.debug("Generated new S3 path for deleted document: {}", newS3Path); UploadFileOnAmazonS3Response response = amazonS3Service.moveFile(applicationSignedDocumentEntity.getFileName(), oldS3Path, newS3Path); log.info("Moved file in S3 from {} to {} | fileName: {}", oldS3Path, newS3Path, response.getFileName()); applicationSignedDocumentEntity.setStatus(ApplicationSignedDocumentStatusEnum.INACTIVE.getValue()); applicationSignedDocumentEntity.setFileName(response.getFileName()); applicationSignedDocumentEntity.setFilePath(response.getFilePath()); applicationSignedDocumentRepository.save(applicationSignedDocumentEntity); log.info("Updated signed document entity status to INACTIVE and saved | applicationSignedDocumentId: {}", applicationSignedDocumentEntity.getId()); loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldApplicationSignedDocument).newData(applicationSignedDocumentEntity).build()); } private void validateFileTypeForCall(MultipartFile file, ApplicationEntity applicationEntity) { List validCallIds = Arrays.asList(callId.split(",")); if (applicationEntity != null && validCallIds.contains(applicationEntity.getCall().getId().toString())) { return; } validateFileType(file); } private UploadFileOnAmazonS3Response uploadFileOnAmazonS3ForUserSignedDocument(MultipartFile file, Long callId, Long applicationId) { try { String s3Path = generateS3PathForDelegation(callId, applicationId); log.info("S3 Path {}", s3Path); return amazonS3Service.uploadFileOnAmazonS3(s3Path, file); } catch (Exception e) { log.error("Failed to upload user signed document | callId: {}, applicationId: {}, error: {}", callId, applicationId, e.getMessage(), e); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); } } private String generateS3PathForDelegation(Long callId, Long applicationId) { try { return s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_SIGNED_DOCUMENT, callId, applicationId,0L); } catch (IllegalArgumentException e) { log.error("Failed to generate S3 path for delegation | callId: {}, applicationId: {}, error: {}", callId, applicationId, e.getMessage(), e); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.S3_PATH_GENERATION_ERROR_MSG)); } } private ApplicationSignedDocumentResponse convertApplicationSignedDocumentToApplicationSignedDocumentResponse( ApplicationSignedDocumentEntity applicationSignedDocument) { ApplicationSignedDocumentResponse applicationSignedDocumentResponse = new ApplicationSignedDocumentResponse(); applicationSignedDocumentResponse.setId(applicationSignedDocument.getId()); applicationSignedDocumentResponse.setApplicationId(applicationSignedDocument.getApplication().getId()); applicationSignedDocumentResponse.setFileName(applicationSignedDocument.getFileName()); applicationSignedDocumentResponse.setFilePath(applicationSignedDocument.getFilePath()); applicationSignedDocumentResponse .setStatus(ApplicationSignedDocumentStatusEnum.valueOf(applicationSignedDocument.getStatus())); applicationSignedDocumentResponse.setCreatedDate(applicationSignedDocument.getCreatedDate()); applicationSignedDocumentResponse.setUpdatedDate(applicationSignedDocument.getUpdatedDate()); applicationSignedDocumentResponse.setFileHash(applicationSignedDocument.getFileHash()); return applicationSignedDocumentResponse; } private void validateFileType(MultipartFile file) { if (file.isEmpty()) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VALIDATION_ERROR_FILE_EMPTY)); } String filename = file.getOriginalFilename(); if (filename == null || !filename.endsWith(".p7m")) { log.warn("Invalid file type detected | filename: {}", filename); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VALIDATION_ERROR_FILE_INVALIDTYPE)); } } public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId) { log.info("Fetching signed document for applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); // validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); if (validator.checkIsPreInstructor()) { ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluationByApplicationId(applicationId); validator.validatePreInstructor(request, applicationEvaluationEntity.getUserId()); } else { validator.validateUserId(request, applicationEntity.getUserId()); } ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); if(applicationSignedDocument == null) { log.warn("No active signed document found for applicationId: {}", applicationId); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_SIGNED_DOCUMENT_NOT_FOUND)); } return convertApplicationSignedDocumentToApplicationSignedDocumentResponse(applicationSignedDocument); } public void deleteSignedDocument(HttpServletRequest request, Long applicationId) { log.info("Initiating deletion of signed document for applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); //cloned entity for old data ApplicationSignedDocumentEntity oldApplicationSignedDocument = Utils.getClonedEntityForData(applicationSignedDocument); if(applicationSignedDocument == null) { log.warn("No active signed document found to delete for applicationId: {}", applicationId); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_SIGNED_DOCUMENT_NOT_FOUND)); } applicationSignedDocument.setStatus(ApplicationSignedDocumentStatusEnum.INACTIVE.getValue()); applicationSignedDocument = applicationSignedDocumentRepository.save(applicationSignedDocument); loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationSignedDocument).newData(applicationSignedDocument) .build()); } public ApplicationResponse validateApplication(HttpServletRequest request, Long applicationId) { log.info("Starting application validation process | applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(applicationEntity); checkCallEndDate(applicationEntity.getCall()); UserEntity userEntity = userService.validateUser(applicationEntity.getUserId()); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); if (Boolean.FALSE.equals(ApplicationStatusTypeEnum.DRAFT.getValue().equals(applicationEntity.getStatus()))) { log.warn("Application not in draft status | applicationId: {}, status: {}", applicationId, applicationEntity.getStatus()); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_NOT_IN_DRAFT_STATUS)); } if (applicationEntity.getAmountRequested() == null || applicationEntity.getAmountRequested().compareTo(BigDecimal.ZERO) <= 0 ) { log.warn("Invalid amount requested | amount: {}", applicationEntity.getAmountRequested()); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.AMOUNT_REQUEST_SHOULD_GREATED_THEN_ZERO)); } List flowEdgesList = flowEdgesRepository.findByCallId(applicationEntity.getCall().getId()); Long totalSteps = flowFormDao.calculateTotalSteps(flowEdgesList); Integer completedSteps = flowFormDao.getCompletedSteps(applicationEntity, true); if (totalSteps.intValue() != completedSteps) { log.warn("Application incomplete | applicationId: {}", applicationId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_IS_INCOMPLETE_MSG)); } applicationEntity.setStatus(ApplicationStatusTypeEnum.AWAITING.getValue()); applicationEntity = applicationRepository.save(applicationEntity); /** This code is responsible for adding a version history log for "Update application status or other details" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEntity).newData(applicationEntity).build()); return getApplicationResponse(applicationEntity); } public byte[] downloadApplicationDocumentsAsZip(HttpServletRequest request, Long applicationId) { log.info("Starting ZIP download process for applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); validateAssignedUser(request, applicationId); Set documentIds = extractDocumentIdsFromApplicationForms(applicationId); List documents = documentRepository.findAllByIdInAndIsDeletedFalse(documentIds); ApplicationSignedDocumentEntity signedDocument = applicationSignedDocumentRepository.findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); List amendmentDocuments = fetchAmendmentDocuments(applicationId); List evaluationDocuments = fetchEvaluationDocuments(applicationId); if (documents.isEmpty() && signedDocument == null && amendmentDocuments.isEmpty() && evaluationDocuments.isEmpty()) { log.warn("No documents found for applicationId: {}", applicationId); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); } return createZipWithDocuments(applicationEntity, documents, signedDocument, amendmentDocuments, evaluationDocuments, applicationId); } private void validateAssignedUser(HttpServletRequest request, Long applicationId) { log.info("Validating assigned user for applicationId: {}", applicationId); AssignedApplicationsEntity assignedApplications = assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationId).orElse(null); if (assignedApplications != null) { validator.validatePreInstructor(request, assignedApplications.getUserId()); } } private Set extractDocumentIdsFromApplicationForms(Long applicationId) { log.info("Extracting document IDs from application forms | applicationId: {}", applicationId); Set documentIds = new HashSet<>(); List applicationForms = applicationFormRepository.findByApplicationId(applicationId); applicationForms.forEach(applicationForm -> { FormEntity formEntity = applicationForm.getForm(); if (formEntity != null) { List contentResponseBeans = formDao.convertFormEntityToFormResponseBean(formEntity).getContent(); contentResponseBeans.stream().filter(content -> "fileupload".equals(content.getName()) || "fileselect".equals(content.getName())).forEach(content -> { Optional formField = applicationFormFieldRepository.findByFieldIdAndApplicationFormIdAndApplicationFormApplicationId( content.getId(), applicationForm.getId(), applicationId); formField.ifPresent(field -> { if (field.getFieldValue() != null) { Arrays.stream(field.getFieldValue().split(",")).map(String::trim).map(Long::valueOf).forEach(documentIds::add); } }); }); } }); return documentIds; } private List fetchAmendmentDocuments(Long applicationId) { log.info("Fetching amendment documents for applicationId: {}", applicationId); List amendmentRequests = applicationAmendmentRequestRepository.findByApplicationIdAndIsDeletedFalse(applicationId); Set amendmentIds = amendmentRequests.stream().map(ApplicationAmendmentRequestEntity::getId).collect(Collectors.toSet()); return documentRepository.findBySourceIdInAndSourceAndIsDeletedFalse(amendmentIds, DocumentSourceTypeEnum.AMENDMENT.getValue()); } private List fetchEvaluationDocuments(Long applicationId) { log.info("Fetching evaluation documents for applicationId: {}", applicationId); Optional evaluationEntity = applicationEvaluationRepository.findByApplicationIdAndIsDeletedFalse(applicationId); if (evaluationEntity.isPresent()) { Long evaluationId = evaluationEntity.get().getId(); log.debug("Found evaluation entity with id: {}", evaluationId); return documentRepository.findBySourceIdInAndSourceAndIsDeletedFalse(Collections.singleton(evaluationId), DocumentSourceTypeEnum.EVALUATION.getValue()); } return Collections.emptyList(); } private String fetchProtocolNumberForAmendment(Long amendmentRequestId) { ApplicationAmendmentRequestEntity amendmentRequest = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentRequestId).orElse(null); if (amendmentRequest != null && amendmentRequest.getProtocol() != null) { return amendmentRequest.getProtocol().getProtocolNumber().toString(); } return "unknown"; } private void addDocumentToZip(ZipOutputStream zos, String s3Folder, String filePath, String fullPath) { log.info("Attempting to add file to ZIP. S3 folder: {}, file path: {}", s3Folder, filePath); try (InputStream fileInputStream = amazonS3Service.getFile(s3Folder, filePath)) { zos.putNextEntry(new ZipEntry(fullPath)); IOUtils.copy(fileInputStream, zos); zos.closeEntry(); } catch (IOException e) { log.error("Failed to add file to ZIP. S3 folder: {}, file path: {}, error: {}", s3Folder, filePath, e.getMessage(), e); throw new RuntimeException("Error downloading or adding document to ZIP: " + fullPath, e); } } private byte[] createZipWithDocuments(ApplicationEntity applicationEntity, List documents, ApplicationSignedDocumentEntity signedDocument, List amendmentDocuments, List evaluationDocuments, Long applicationId) { try (ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(zipOutputStream)) { Long callId = applicationEntity.getCall().getId(); // Add Application Documents String appS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.APPLICATION, callId, applicationId, 0L); for (DocumentEntity document : documents) { String fileName = Utils.extractFileName(document.getFilePath()); addDocumentToZip(zos, appS3Folder, document.getFilePath(), fileName); } // Add Signed Document if (signedDocument != null) { String signedFolder = "SIGNED_DOCUMENT/"; String signedDocS3Folder = s3PathConfig.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_SIGNED_DOCUMENT, callId, applicationId, 0L); String fileName = signedDocument.getFileName(); addDocumentToZip(zos, signedDocS3Folder, signedDocument.getFilePath(), signedFolder + fileName); } // Add Amendment (Soccorso) Documents for (DocumentEntity amendmentDocument : amendmentDocuments) { String protocolNumber = fetchProtocolNumberForAmendment(amendmentDocument.getSourceId()); String amendmentFolder = "SOCCORSO_" + protocolNumber + "/"; String amendmentS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.AMENDMENT, callId, applicationId, amendmentDocument.getSourceId()); String fileName = Utils.extractFileName(amendmentDocument.getFilePath()); addDocumentToZip(zos, amendmentS3Folder, amendmentDocument.getFilePath(), amendmentFolder + fileName); } // Add Evaluation Documents for (DocumentEntity evaluationDocument : evaluationDocuments) { String evaluationFolder = "EVALUATION/"; String evaluationS3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.EVALUATION, callId, applicationId, evaluationDocument.getSourceId()); String fileName = Utils.extractFileName(evaluationDocument.getFilePath()); addDocumentToZip(zos, evaluationS3Folder, evaluationDocument.getFilePath(), evaluationFolder + fileName); } zos.finish(); return zipOutputStream.toByteArray(); } catch (IOException e) { throw new RuntimeException("Error while creating ZIP file", e); } } // private Path getFieldPath(Root root, String fieldName) { // try { // return switch (fieldName) { //// case GepafinConstant.CALL_ID -> root.get(GepafinConstant.CALL).get(GepafinConstant.ID); //// case GepafinConstant.CALL_TITLE -> root.get(GepafinConstant.CALL).get(GepafinConstant.NAME); //// case GepafinConstant.CALL_END_DATE -> root.get(GepafinConstant.CALL).get(GepafinConstant.END_DATE); //// case GepafinConstant.CALL_END_TIME -> root.get(GepafinConstant.CALL).get(GepafinConstant.END_TIME); //// case GepafinConstant.MODIFIED_DATE -> root.get(GepafinConstant.CALL).get(GepafinConstant.UPDATED_DATE); //// case GepafinConstant.PROTOCOL_NUMBER-> root.get(GepafinConstant.PROTOCOL).get(GepafinConstant.PROTOCOL_NUMBER); // default -> root.get(fieldName); // }; // } catch (IllegalArgumentException e) { // return null; // } // } public void checkCallEndDate(CallEntity call) { callService.validatePublishedCall(call.getId(), call.getHub().getId()); // LocalDateTime now = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); // // LocalDateTime callEndDateTime = LocalDateTime.of( // call.getEndDate().toLocalDate(), // call.getEndTime() // ); // // if (now.isAfter(callEndDateTime)) { // throw new CustomValidationException( // Status.BAD_REQUEST, // Translator.toLocale(GepafinConstant.CALL_EXPIRED) // ); // } } public void calculationProcessForFormula(ApplicationFormEntity applicationFormEntity, List contentResponseBeans, ApplicationFormFieldRequestBean applicationFormFieldRequestBean,FieldValidator fieldValidator) { List formulaValue = new ArrayList<>(); String formulaValueOpt=null; String label=null; for (ContentResponseBean contentResponseBean:contentResponseBeans){ if(contentResponseBean.getId().equals(applicationFormFieldRequestBean.getFieldId())){ for (SettingResponseBean settingResponseBean:contentResponseBean.getSettings()){ if (settingResponseBean.getName().equals("label")){ label= String.valueOf(settingResponseBean.getValue()); } if(settingResponseBean.getName().equals("formula")){ String value= (String) settingResponseBean.getValue(); formulaValueOpt=value; formulaValue=Utils.extractValues(value); } } } } Map mappedFormulaValue = new HashMap<>(); Object fieldValue = applicationFormFieldRequestBean.getFieldValue(); if (formulaValueOpt != null && fieldValue==null) { fieldValue=0; } for (ContentResponseBean contentResponseBean : contentResponseBeans) { String contentId = contentResponseBean.getId(); // Extract variable values once per contentResponseBean to avoid repeated stream operations Set variableValues = contentResponseBean.getSettings().stream() .filter(setting -> "variable".equals(setting.getName())) .flatMap(setting -> { Object value = setting.getValue(); // Get the raw value if (value instanceof String) { return Stream.of((String) value); // Handle single String case } else if (value instanceof List) { return ((List) value).stream() .filter(item -> item instanceof String) // Ensure it's a String .map(item -> (String) item); // Convert to String } else { return Stream.empty(); // Ignore unexpected types } }) .collect(Collectors.toSet()); // Collect into a Set for uniqueness for (String formula : formulaValue) { if (variableValues.contains(formula)) { // O(1) lookup instead of O(n) mappedFormulaValue.put(formula, contentId); } } } Map updatedMappedFormulaValue = new HashMap<>(); for (Map.Entry entry : mappedFormulaValue.entrySet()) { String variable = entry.getKey(); String contentId = entry.getValue(); // Repository call using contentId Optional optionalEntity = applicationFormFieldRepository.findByApplicationFormIdAndFieldId(applicationFormEntity.getId(),contentId); // If entity is found, extract fieldValue and fieldId optionalEntity.ifPresent(entity -> { String entityFieldValue = entity.getFieldValue(); // Assuming getter method exists String fieldId = entity.getFieldId(); // Assuming getter method exists String tableType = contentResponseBeans.stream() .filter(content -> content.getId().equals(fieldId)) // Match Content ID with fieldId .flatMap(content -> content.getSettings().stream()) // Extract settings .filter(setting -> "criteria_table_columns".equals(setting.getName())) // Match name .map(setting -> setting.getName()) // Return the name of the setting .findFirst() // Get the first match .orElse(null); // Default to null if no match if(tableType!=null){ JSONObject jsonObject = new JSONObject(entityFieldValue); // Extract the value of total entityFieldValue = jsonObject.getString("total"); } updatedMappedFormulaValue.put(fieldId, entityFieldValue); }); } if(formulaValueOpt==null || formulaValueOpt.isEmpty()){ return; } double finalValue = evaluateFormula(formulaValueOpt, mappedFormulaValue, updatedMappedFormulaValue); fieldValidator.formulaValidation(fieldValue, finalValue, label); } public static double evaluateFormula(String formula, Map mappedFormulaValue, Map updatedMappedFormulaValue) { // Step 1: Extract all placeholders (variables) like {rest}, {another_var}, etc. Pattern pattern = Pattern.compile("\\{(.*?)\\}"); Matcher matcher = pattern.matcher(formula); List variables = new ArrayList<>(); while (matcher.find()) { variables.add(matcher.group(1)); // Extract variable names inside the curly braces } // Step 2: Replace placeholders with corresponding fieldValue Map variableValues = new HashMap<>(); for (String variable : variables) { String fieldId = mappedFormulaValue.get(variable); if (fieldId != null && updatedMappedFormulaValue.containsKey(fieldId)) { String fieldValueStr = updatedMappedFormulaValue.get(fieldId); try { double fieldValue = Double.parseDouble(fieldValueStr); // Assuming fieldValue is numeric variableValues.put(variable, fieldValue); } catch (NumberFormatException e) { // Handle invalid number format gracefully (e.g., log an error or default to 0) variableValues.put(variable, 0.0); } } } // Step 3: Replace variables in the formula with their corresponding values String expression = formula; for (String variable : variables) { Double value = variableValues.get(variable); if (value != null) { // Replace {variable} with its corresponding value in the formula expression = expression.replace("{" + variable + "}", String.valueOf(value)); } } // Step 4: Evaluate the mathematical expression return Utils.evaluateExpression(expression); } public ApplicationEntity validateApplicationWithCompany(Long id,Long companyId) { ApplicationEntity application=applicationRepository.findByIdAndCompanyIdAndIsDeletedFalse(id,companyId); if (application==null){ throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); } return application; } public PageableResponseBean> getAllApplicationByPaginationByView(UserEntity userEntity, Long callId, Long companyId, ApplicationPageableRequestBean applicationPageableRequestBean) { Integer pageNo = null; Integer pageLimit = null; UserWithCompanyEntity userWithCompany= userWithCompanyRepository.findByUserIdAndCompanyIdAndIsDeletedFalse(userEntity.getId(), companyId).orElse(null); Long userWithCompanyId = userWithCompany!=null?userWithCompany.getId():null; if (applicationPageableRequestBean.getGlobalFilters() != null) { pageNo = applicationPageableRequestBean.getGlobalFilters().getPage(); pageLimit = applicationPageableRequestBean.getGlobalFilters().getLimit(); } if (pageLimit == null || pageLimit <= 0) { pageLimit = GepafinConstant.DEFAULT_PAGE_LIMIT; } if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } Specification spec = searchByView(callId,companyId, userWithCompanyId, applicationPageableRequestBean, userEntity); Page entityPage = applicationViewRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response List applicationResponses = entityPage.getContent().stream() .map(application -> { ApplicationResponse response = getApplicationResponseByView(application); return response; }) .collect(Collectors.toList()); PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); pageableResponseBean.setBody(applicationResponses); pageableResponseBean.setCurrentPage(entityPage.getNumber() + 1); // Page numbers typically start from 0, so add 1 for user-friendly indexing pageableResponseBean.setTotalPages(entityPage.getTotalPages()); pageableResponseBean.setTotalRecords(entityPage.getTotalElements()); pageableResponseBean.setPageSize(entityPage.getSize()); return pageableResponseBean; } public Specification searchByView(Long callId, Long companyId, Long userWithCompanyId, ApplicationPageableRequestBean applicationPageableRequestBean, UserEntity userEntity) { return (root, query, criteriaBuilder) -> { List predicates = getPredicatesByView(applicationPageableRequestBean, criteriaBuilder, root, callId,companyId, userWithCompanyId, userEntity); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (applicationPageableRequestBean.getGlobalFilters() != null && applicationPageableRequestBean.getGlobalFilters().getSortBy() != null && applicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName() != null && Boolean.FALSE.equals( isEmpty(applicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName()))) { sortBy.setColumnName(applicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName()); sortBy.setSortDesc(true); if (applicationPageableRequestBean.getGlobalFilters().getSortBy().getSortDesc() != null) { sortBy.setSortDesc(applicationPageableRequestBean.getGlobalFilters().getSortBy().getSortDesc()); } } query.orderBy(criteriaBuilder.desc(root.get(sortBy.getColumnName()))); if (Boolean.FALSE.equals(sortBy.getSortDesc())) { query.orderBy(criteriaBuilder.asc(root.get(sortBy.getColumnName()))); } return query.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))).getRestriction(); }; } private List getPredicatesByView(ApplicationPageableRequestBean applicationPageableRequestBean, CriteriaBuilder criteriaBuilder, Root root, Long callId,Long companyId, Long userWithCompanyId, UserEntity userEntity) { Integer year = null; String search = null; Integer daysRange = null; Map filters = new HashMap<>(); if (applicationPageableRequestBean.getGlobalFilters() != null) { year = applicationPageableRequestBean.getGlobalFilters().getYear(); search = applicationPageableRequestBean.getGlobalFilters().getSearch(); daysRange = applicationPageableRequestBean.getDaysRange(); } if (applicationPageableRequestBean.getFilters() != null) { filters = applicationPageableRequestBean.getFilters(); } List predicates = new ArrayList<>(); // Boolean isBeneficiary = validator.checkIsBeneficiary(); if (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.USER_ID), userEntity.getId())); } if (year != null && year > 0) { int filterYear = applicationPageableRequestBean.getGlobalFilters().getYear(); // Create LocalDateTime boundaries for the start and end of the year LocalDateTime startOfYear = LocalDateTime.of(filterYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(filterYear, 12, 31, 23, 59, 59); // Add the range comparison to filter records within the year predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), startOfYear, endOfYear)); } // Search in `title` and `message` (if search term is provided) if (search != null && !search.isEmpty()) { String searchPattern = "%" + search.toUpperCase() + "%"; Predicate titlePredicate = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.COMMENTS)), searchPattern ); Predicate callTitlePredicate = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.CALL_TITLE)), searchPattern ); Predicate callNamePredicate = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.CALL_NAME)), searchPattern ); Predicate companyName = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.COMPANY_NAME)), searchPattern ); // Combine them using a single `or()` Predicate finalPredicate = criteriaBuilder.or(titlePredicate, callTitlePredicate,callNamePredicate,companyName); predicates.add(finalPredicate); } // Filter by `status` (if status list is provided) if (applicationPageableRequestBean.getStatus() != null && !applicationPageableRequestBean.getStatus().isEmpty()) { List statusValues = applicationPageableRequestBean.getStatus().stream() .map(ApplicationStatusTypeEnum::name) // Convert enum to string .toList(); predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); } if (callId != null) { CallEntity call = callService.validateCall(callId); predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.CALL_ID), callId)); } // Optional companyId filter if (userWithCompanyId != null) { predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.USER_WITH_COMPANY_ID), userWithCompanyId)); } if (companyId != null) { predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.COMPANY_ID), companyId)); } if (daysRange != null && daysRange >= 0) { LocalDateTime today = LocalDateTime.now(); LocalDateTime pastDate = today.minusDays(daysRange); predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), pastDate, today)); } Utils.applyFiltersByPagination(root, criteriaBuilder, predicates, filters); predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.HUB_ID), userEntity.getHub().getId())); return predicates; } private ApplicationResponse getApplicationResponseByView(ApplicationView applicationView) { ApplicationResponse responseBean = new ApplicationResponse(); List flowEdgesList = flowEdgesRepository.findByCallId(applicationView.getCallId()); Long totalFormSteps = flowFormDao.calculateTotalSteps(flowEdgesList); Long completedSteps = Long.valueOf(flowFormDao.getCompletedStepsByView(applicationView.getId(), false)); Integer progress = calculateProgress(totalFormSteps, completedSteps); responseBean.setId(applicationView.getId()); responseBean.setProgress(progress); responseBean.setCallTitle(applicationView.getCallTitle()); responseBean.setCallEndDate(applicationView.getCallEndDate()); responseBean.setCallEndTime(applicationView.getCallEndTime()); responseBean.setModifiedDate(applicationView.getModifiedDate()); responseBean.setCallId(applicationView.getCallId()); responseBean.setSubmissionDate(applicationView.getSubmissionDate()); responseBean.setStatus(applicationView.getStatus()); responseBean.setEvaluationVersion(EvaluationVersionEnum.valueOf(applicationView.getEvaluationVersion())); responseBean.setComments(applicationView.getComments()); responseBean.setCompanyId(applicationView.getCompanyId()); responseBean.setAssignedUserId(applicationView.getAssignedUserId()); responseBean.setAssignedUserName(applicationView.getAssignedUserName()); responseBean.setCompanyName(applicationView.getCompanyName()); responseBean.setProtocolNumber(applicationView.getProtocolNumber()); responseBean.setAmountAccepted(applicationView.getAmountAccepted()); responseBean.setAmountRequested(applicationView.getAmountRequested()); responseBean.setDateAccepted(applicationView.getDateAccepted()); responseBean.setDateRejected(applicationView.getDateRejected()); return responseBean; } public List getApplicationFormData(Long callId) { List applicationFormViews=new ArrayList<>(); applicationFormViews= applicationFormViewRepository.findByCallId(callId); return applicationFormViews; } private List getStaticGetterMethods() { List excluded = Arrays.asList( GepafinConstant.GET_FIELD_TYPE,GepafinConstant.GET_APPLICATION_FORM_ID,GepafinConstant.GET_ID,GepafinConstant.GET_CLASS,GepafinConstant.GET_FORM_ID,GepafinConstant.GET_FIELD_ID,GepafinConstant.GET_FIELD_LABEL,GepafinConstant.GET_FIELD_VALUE,GepafinConstant.GET_REPORT_HEADER,GepafinConstant.GET_REPORT_ENABLE ); Method applicationIdMethod = null; List methods = new ArrayList<>(); for (Method m : ApplicationFormView.class.getMethods()) { if (m.getName().equals(GepafinConstant.GET_APPLICATION_ID)) { applicationIdMethod = m; } else if (m.getName().startsWith(GepafinConstant.GET) && m.getParameterCount() == 0 && !excluded.contains(m.getName())) { methods.add(m); } } methods.sort(Comparator.comparing(Method::getName)); // Sort remaining if (applicationIdMethod != null) { methods.add(0, applicationIdMethod); // Add it to the beginning } return methods; } private String methodToHeader(Method method) { String name = method.getName().substring(3); // strip "get" return Arrays.stream(name.split("(?=[A-Z])")) .map(String::toLowerCase) .map(word -> Character.toUpperCase(word.charAt(0)) + word.substring(1)) .collect(Collectors.joining(" ")); } private String invokeGetter(ApplicationFormView view, Method method) { try { Object value = method.invoke(view); if (value == null) return ""; String stringValue; if (value instanceof LocalDate) { stringValue = ((LocalDate) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); } else if (value instanceof LocalDateTime) { stringValue = ((LocalDateTime) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } else if (value instanceof Date) { stringValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) value); } else { stringValue = value.toString(); } // Wrap it in ="..." to make Excel treat it as a literal string return stringValue; } catch (Exception e) { return ""; } } public byte[] exportCsv(Long callId) { List results = getApplicationFormData(callId); Map appInfo = new HashMap<>(); Map> appFieldValues = new LinkedHashMap<>(); Set tableFieldIds = new HashSet<>(); Map fieldIdToLabel = new LinkedHashMap<>(); for (ApplicationFormView row : results) { appInfo.putIfAbsent(row.getApplicationId(), row); String label=row.getReportHeader(); if(Boolean.TRUE.equals(StringUtils.isEmpty(label))){ label=row.getFieldLabel(); } fieldIdToLabel.putIfAbsent(row.getFieldId(), label); if (GepafinConstant.TABLE.equalsIgnoreCase(row.getFieldType())) { tableFieldIds.add(row.getFieldId()); continue; } String value = Optional.ofNullable(row.getFieldValue()) .map(v -> v.startsWith("\"") && v.endsWith("\"") ? v.substring(1, v.length() - 1) : v) .orElse(""); appFieldValues .computeIfAbsent(row.getApplicationId(), k -> new LinkedHashMap<>()) .merge(row.getFieldId(), value, (v1, v2) -> v1.equals(v2) ? v1 : String.join(", ", v1, v2)); } Map> tableHeadersByFieldId = new LinkedHashMap<>(); Map> tableDataByApp = new HashMap<>(); prepareTableFieldData(results, tableFieldIds, tableHeadersByFieldId, tableDataByApp); // Final header construction List staticMethods = getStaticGetterMethods(); List staticHeaders = staticMethods.stream().map(this::methodToHeader).toList(); List dynamicHeaders = new ArrayList<>(); for (String fieldId : fieldIdToLabel.keySet()) { if (tableHeadersByFieldId.containsKey(fieldId)) { dynamicHeaders.addAll(tableHeadersByFieldId.get(fieldId)); } else { dynamicHeaders.add(fieldIdToLabel.get(fieldId)); } } List allHeaders = new ArrayList<>(staticHeaders); allHeaders.addAll(dynamicHeaders); ByteArrayOutputStream out = new ByteArrayOutputStream(); try (CSVPrinter printer = new CSVPrinter(new OutputStreamWriter(out), CSVFormat.DEFAULT.withHeader(allHeaders.toArray(new String[0])))) { for (Long appId : appFieldValues.keySet()) { ApplicationFormView appRow = appInfo.get(appId); Map flatFieldVals = appFieldValues.get(appId); Map tableVals = tableDataByApp.getOrDefault(appId, Collections.emptyMap()); List row = new ArrayList<>(); for (Method method : staticMethods) { row.add(invokeGetter(appRow, method)); } for (String fieldId : fieldIdToLabel.keySet()) { if (tableHeadersByFieldId.containsKey(fieldId)) { for (String header : tableHeadersByFieldId.get(fieldId)) { row.add(tableVals.getOrDefault(header, "")); } } else { row.add(flatFieldVals.getOrDefault(fieldId, "")); } } printer.printRecord(row); } } catch (IOException e) { throw new RuntimeException("CSV generation failed", e); } return out.toByteArray(); } private Map extractTableData(String fieldType, ContentResponseBean content, String fieldValue) { if (content == null) return Map.of(); Map result = new LinkedHashMap<>(); List> rows = null; try { rows = GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(fieldType) ? Utils.convertJsonToListMap(String.valueOf(PdfUtils.extractRows(fieldValue))) : Utils.convertJsonToListMap(fieldValue); } catch (Exception e) { throw new RuntimeException(e); } Map fieldLabelMap = new LinkedHashMap<>(); Set predefinedIds = new LinkedHashSet<>(); Set dynamicIds = new LinkedHashSet<>(); Set numericFormulaIds = new LinkedHashSet<>(); for (SettingResponseBean setting : content.getSettings()) { String settingName = setting.getName(); if(settingName.equals(GepafinConstant.REPORT_ENABLE)){ Boolean enable= (Boolean) setting.getValue(); if(Boolean.FALSE.equals(enable)){ return null; } } if (Boolean.TRUE.equals(GepafinConstant.TABLE_COLUMNS.equals(settingName)) || Boolean.TRUE.equals(GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(settingName))) { Map valueMap = (Map) setting.getValue(); if (valueMap == null) continue; List> columns = (List>) valueMap.get(GepafinConstant.STATE_FIELD_DATA); if (columns != null) { for (Map col : columns) { String id = String.valueOf(col.get(GepafinConstant.NAME)); if (Boolean.FALSE.equals(col.get(GepafinConstant.PREDEFINED))) { if (GepafinConstant.NUMERIC.equals(col.get(GepafinConstant.FIELD_TYPE)) && Boolean.TRUE.equals(col.get(GepafinConstant.ENABLE_FORMULA))) { numericFormulaIds.add(id); } } } } } if (Boolean.TRUE.equals(GepafinConstant.REPORT_COLUMNS.equals(settingName))) { List> reportColumns = (List>) setting.getValue(); if (reportColumns != null) { for (Map col : reportColumns) { Boolean enableCsv = (Boolean) col.get(GepafinConstant.EBABLE_CSV); if (Boolean.TRUE.equals(enableCsv)) { String id = String.valueOf(col.get(GepafinConstant.NAME)); String fieldCsvLabel = col.get(GepafinConstant.LABEL_CSV) != null ? String.valueOf(col.get(GepafinConstant.LABEL_CSV)) : String.valueOf(col.get(GepafinConstant.LABEL)); fieldLabelMap.put(id, fieldCsvLabel); if (Boolean.TRUE.equals(col.get(GepafinConstant.PREDEFINED))) { predefinedIds.add(id); } else { dynamicIds.add(id); } } } } } } if (predefinedIds.isEmpty()) { return null; } for (Map row : rows) { String prefix = predefinedIds.stream() .map(id -> String.valueOf(row.getOrDefault(id, ""))) .filter(s -> !s.isBlank()) .findFirst().orElse(""); for (String dynId : dynamicIds) { String dynLabel = fieldLabelMap.get(dynId); for (String preId : predefinedIds.isEmpty() ? List.of("") : predefinedIds) { String preLabel = fieldLabelMap.get(preId); String key = dynLabel + " " + (preLabel != null ? preLabel + " " : "") + prefix; result.put(key, String.valueOf(row.getOrDefault(dynId, ""))); } } } // Add totals for numeric formula-enabled columns for (String dynId : numericFormulaIds) { double sum = rows.stream() .mapToDouble(r -> { try { return Double.parseDouble(String.valueOf(r.getOrDefault(dynId, "0"))); } catch (NumberFormatException e) { return 0.0; } }).sum(); String dynLabel = fieldLabelMap.get(dynId); result.put("TOTAL " + dynLabel, String.valueOf(sum)); } return result; } private void prepareTableFieldData( List results, Set tableFieldIds, Map> tableHeadersByFieldId, Map> tableDataByApp) { if (tableFieldIds.isEmpty()) return; Map> groupedByApp = results.stream() .filter(r -> tableFieldIds.contains(r.getFieldId())) .collect(Collectors.groupingBy(ApplicationFormView::getApplicationId)); for (Map.Entry> entry : groupedByApp.entrySet()) { Long appId = entry.getKey(); Map flattenedAll = new LinkedHashMap<>(); for (ApplicationFormView row : entry.getValue()) { formRepository.findById(row.getFormId()).ifPresent(form -> { List contentList = Utils.convertJsonStringToList(form.getContent(), ContentResponseBean.class); ContentResponseBean content = contentList.stream() .filter(c -> c.getId().equals(row.getFieldId())) .findFirst() .orElse(null); if (content == null) return; content.getSettings().stream() .filter(setting -> GepafinConstant.TABLE_COLUMNS.equals(setting.getName()) || GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(setting.getName())) .findFirst() .ifPresent(setting -> { Map flattened = extractTableData( row.getFieldType(), content, row.getFieldValue() ); if (flattened != null) { tableHeadersByFieldId.putIfAbsent(row.getFieldId(), new ArrayList<>(flattened.keySet())); flattenedAll.putAll(flattened); } }); }); } tableDataByApp.put(appId, flattenedAll); } } public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId) { log.info("Re-admiting the Application with id : {}", applicationId); ApplicationEntity applicationEntity = fetchRejectedApplication(applicationId); if(applicationEntity == null){ throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG)); } validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationEntity.getId()) .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); return getApplicationResponse(applicationEntity); } private ApplicationEntity fetchRejectedApplication(Long applicationId) { return applicationRepository.findByIdAndStatusAndIsDeletedFalse(applicationId, ApplicationStatusTypeEnum.REJECTED.getValue()); } private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse(assignedApp.getId()) .ifPresent(eval -> reopenApplication(request, applicationEntity, assignedApp, eval)); } private void reopenApplication(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp, ApplicationEvaluationEntity evaluationEntity) { ApplicationEntity oldApplication = Utils.getClonedEntityForData(applicationEntity); AssignedApplicationsEntity oldAssignedApp = Utils.getClonedEntityForData(assignedApp); ApplicationEvaluationEntity oldEvaluation = Utils.getClonedEntityForData(evaluationEntity); updateApplicationStatus(applicationEntity); updateAssignedApplicationStatus(assignedApp); updateEvaluationEntity(applicationEntity.getHubId(), evaluationEntity); saveEntities(applicationEntity, assignedApp, evaluationEntity); /** This code is responsible for adding a version history log for the "Update Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplication).newData(applicationEntity).build()); /** This code is responsible for adding a version history log for the "Update Application Evaluation" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldEvaluation).newData(evaluationEntity).build()); /** This code is responsible for adding a version history log for the "Update Assigned Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldAssignedApp).newData(assignedApp).build()); } private void updateApplicationStatus(ApplicationEntity applicationEntity) { applicationEntity.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); applicationEntity.setDateRejected(null); } private void updateAssignedApplicationStatus(AssignedApplicationsEntity assignedApp) { assignedApp.setStatus(AssignedApplicationEnum.OPEN.getValue()); } private void updateEvaluationEntity(Long hubId, ApplicationEvaluationEntity evaluationEntity) { HubEntity hub = hubService.valdateHub(hubId); Long evaluationDays = (hub != null) ? hub.getEvaluationExpirationDays() : 30L; LocalDateTime now = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); evaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.OPEN.getValue()); evaluationEntity.setClosingDate(null); evaluationEntity.setActiveDays(null); evaluationEntity.setEndDate(now.plusDays(evaluationDays)); evaluationEntity.setStartDate(now); evaluationEntity.setRemainingDays(evaluationDays); evaluationEntity.setSuspendedDays(0L); evaluationEntity.setStopDateTime(null); } private void saveEntities(ApplicationEntity app, AssignedApplicationsEntity assignedApp, ApplicationEvaluationEntity eval) { applicationRepository.save(app); assignedApplicationsRepository.save(assignedApp); applicationEvaluationRepository.save(eval); } public void sendApplicationSubmissionFailureEmail(EmailLogRequest emailLogRequest){ Long callId = emailLogRequest.getCallId(); CallEntity call = callService.validateCall(callId); HubEntity hub = call.getHub(); Long userId = emailLogRequest.getUserId(); UserEntity user = userService.validateUser(userId); Long applicationId = emailLogRequest.getApplicatioId(); ApplicationEntity applicationEntity = validateApplication(applicationId); CompanyEntity company = companyService.validateCompany(applicationEntity.getCompanyId()); SystemEmailTemplateResponse systemEmailTemplateResponse = systemEmailTemplatesService .retrieveTemplateByTypeAndCall(SystemEmailTemplatesEntityTypeEnum.APPLICATION_SUBMISSION_FAILURE_NOTIFICATION, hub, null); Map subjectPlaceholders = new HashMap<>(); subjectPlaceholders.put("{{call_name}}", call.getName()); Map bodyPlaceholders = new HashMap<>(); bodyPlaceholders.put("{{scenario}}",emailLogRequest.getEmailType().getValue()); bodyPlaceholders.put("{{call_name}}", call.getName()); bodyPlaceholders.put("{{application_id}}", applicationEntity.getId().toString()); bodyPlaceholders.put("{{company_name}}", company.getCompanyName()); String protocolNumber=applicationEntity.getProtocol().getExternalProtocolNumber(); if(protocolNumber==null){ protocolNumber= String.valueOf(applicationEntity.getProtocol().getProtocolNumber()); } bodyPlaceholders.put("{{protocol_number}}", protocolNumber); bodyPlaceholders.put("{{user_action_id}}",emailLogRequest.getUserActionId().toString()); String subject = Utils.replacePlaceholders(systemEmailTemplateResponse.getSubject(), subjectPlaceholders); String body = Utils.replacePlaceholders(systemEmailTemplateResponse.getHtmlContent(), bodyPlaceholders); emailLogRequest=emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(),RecipientTypeEnum.PROPERTIES,null,user.getEmail(),user.getId(),applicationEntity.getId(),null,callId); emailLogRequest.setRecipientEmails(GepafinConstant.RINALDO_EMAIL); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(GepafinConstant.RINALDO_EMAIL),emailLogRequest); } public byte[] downloadRankingCsv(Long callId) { CallEntity callEntity = callService.validateCall(callId); List applications = applicationRepository.findByCallIdAndIsDeletedFalseAndStatusIn( callId, List.of( ApplicationStatusForEvaluation.APPROVED.getValue(), ApplicationStatusForEvaluation.ADMISSIBLE.getValue(), ApplicationStatusForEvaluation.TECHNICAL_EVALUATION.getValue() )); List dynamicLabels = new ArrayList<>(); // Maintain insertion order, allow duplicates only once Map> appLabelScoresMap = new HashMap<>(); Map applicationMap = new HashMap<>(); Map appTotalScoreMap = new HashMap<>(); for (ApplicationEntity app : applications) { Long appId = app.getId(); applicationMap.put(appId, app); ApplicationEvaluationEntity evaluation = applicationEvaluationRepository.findByApplicationId(appId); BigDecimal totalScore = applicationEvaluationDao.calculateTotalScore(evaluation.getCriteria()); appTotalScoreMap.put(appId, totalScore); List criteriaList = evaluation.getCriteria() != null ? Utils.convertJsonToList(evaluation.getCriteria(), new TypeReference>() {}) : List.of(); List dbCriteriaList = applicationEvaluationDao.getCriteriaResponse(appId); Map scoreByLabel = new HashMap<>(); for (CriteriaResponse criteria : criteriaList) { Optional matchedDb = dbCriteriaList.stream() .filter(db -> Objects.equals(db.getId(), criteria.getId())) .findFirst(); String label = matchedDb.map(CriteriaResponse::getLabel).orElse(""); if (!dynamicLabels.contains(label)) { dynamicLabels.add(label); } scoreByLabel.put(label, criteria.getScore() != null ? criteria.getScore() : BigDecimal.ZERO); } appLabelScoresMap.put(appId, scoreByLabel); } // Build headers dynamically List headers = new ArrayList<>(List.of( "ApplicationID", "VatNumber", "Company Name", "Protocol", "Requested Amount", "Status", "Total Score" )); headers.addAll(dynamicLabels); // Prepare data rows List> rows = new ArrayList<>(); for (ApplicationEntity app : applications) { Long appId = app.getId(); CompanyEntity company = companyService.validateCompany(app.getCompanyId()); ProtocolEntity protocolEntity = app.getProtocol(); List row = new ArrayList<>(); row.add(appId); row.add(company.getVatNumber()); row.add(company.getCompanyName()); row.add(protocolEntity != null ? protocolEntity.getProtocolNumber() : 0L); row.add(app.getAmountRequested()); row.add(app.getStatus()); row.add(appTotalScoreMap.get(appId)); Map scores = appLabelScoresMap.getOrDefault(appId, Collections.emptyMap()); for (String label : dynamicLabels) { row.add(scores.getOrDefault(label, BigDecimal.ZERO)); } rows.add(row); } // Generate CSV ByteArrayOutputStream out = new ByteArrayOutputStream(); try (OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.withHeader(headers.toArray(new String[0])))) { for (List row : rows) { csvPrinter.printRecord(row); } csvPrinter.flush(); } catch (IOException e) { throw new RuntimeException("Error while generating CSV", e); } return out.toByteArray(); } }