diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 7e165dc3..f9fbe5d6 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -541,10 +541,14 @@ public class GepafinConstant { public static final String RESEND_EMAIL_SENT_FAILED_MSG = "resend.email.sent.failed.msg"; public static final String REMINDER_EMAIL_FAILED_MSG = "reminder.email.sent.failed.msg"; + public static final String READMIT_APPLICATION_SUCCESS = "application.readmit.success"; + public static final String NO_EMAIL_LOG_FOUND = "no.email.log.msg"; public static final String USER_ACTION_ID_NOT_FOUND = "user.action.id.not.found"; - + public static final String CAUSE_STRING = "cause" ; + public static final String ERROR_DESCRIPTION_STRING = "errorDescription" ; + public static final String ERROR_STRING = "errors"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 59004619..76ce5d3d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -27,6 +27,7 @@ import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundExceptio import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; @@ -308,8 +309,14 @@ public class ApplicationAmendmentRequestDao { if (Boolean.TRUE.equals(applicationAmendmentRequestResponse.getIsSendEmail())) { emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(applicationAmendmentRequestEntity); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - applicationAmendmentRequestResponse.setEmailSendResponse(emailSendResponse); - saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity); + List responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity); + applicationAmendmentRequestResponse.setEmailSendResponse(responses); + } + else{ + applicationAmendmentRequestResponse.setEmailSendResponse(Collections.emptyList()); + } } return applicationAmendmentRequestResponse; } @@ -516,6 +523,7 @@ public class ApplicationAmendmentRequestDao { Long hubId = applicationEntity.getHubId(); HubEntity hubEntity = hubService.valdateHub(hubId); + response.setEmailSendResponse(entity.getEmailSendResponse()); response.setId(entity.getId()); response.setApplicationId(entity.getApplicationId()); response.setApplicationEvaluationId(entity.getApplicationEvaluationEntity().getId()); @@ -654,19 +662,12 @@ public class ApplicationAmendmentRequestDao { log.info(" Application amendment deleted with ID: {}", id); } - public ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(Long id) { + public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(Long id) { log.info("Fetching application amendment with ID: {}", id); ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); - ApplicationAmendmentRequestResponse sourceResponse = convertEntityToResponse(applicationAmendmentRequestEntity,true); - ApplicationAmendmentRequestResponseBean targetResponse = Utils.convertSourceObjectToDestinationObject( - sourceResponse, ApplicationAmendmentRequestResponseBean.class - ); - - if (targetResponse != null) { - targetResponse.setEmailSendResponse(applicationAmendmentRequestEntity.getEmailSendResponse()); - } - log.info("Application Amendment fetched successfully by ID: {}", targetResponse); - return targetResponse; + ApplicationAmendmentRequestResponse response = convertEntityToResponse(applicationAmendmentRequestEntity,true); + response.setEmailSendResponse(applicationAmendmentRequestEntity.getEmailSendResponse()); + return response; } public List getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId) { @@ -1049,7 +1050,7 @@ public class ApplicationAmendmentRequestDao { public ApplicationAmendmentRequestResponse closeAmendmentRequest(Long id, CloseAmendmentRequest closeAmendmentRequest) { log.info("Closing application amendement with ID: {}", id); - ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); + ApplicationAmendmentRequestEntity existingApplicationAmendment = validatApplicationAmendmentRequestByStatus(id,ApplicationAmendmentRequestEnum.AWAITING.getValue()); //cloned entity for old data and versioning ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); List amendmentRequestList = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( @@ -1059,17 +1060,18 @@ public class ApplicationAmendmentRequestDao { // Check if this is the last amendment being closed boolean isLastRemaining = amendmentRequestList.stream() .filter(amendment -> !amendment.getId().equals(id)) // Exclude the current amendment - .allMatch(amendment -> amendment.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue())); + .allMatch(amendment -> amendment.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue()) || amendment.getStatus().equals(ApplicationAmendmentRequestEnum.EXPIRED.getValue())); + - if (isLastRemaining) { - log.info("The current amendment is the last remaining one to be closed."); - applicationAmendmentRequestDao.calculateEndDateAndSuspensionDays(existingApplicationAmendment.getApplicationEvaluationEntity()); - } setIfUpdated(existingApplicationAmendment::getInternalNote, existingApplicationAmendment::setInternalNote, closeAmendmentRequest.getInternalNote()); setIfUpdated(existingApplicationAmendment::getStatus, existingApplicationAmendment::setStatus, ApplicationAmendmentRequestEnum.CLOSE.getValue()); existingApplicationAmendment.setClosingDate(LocalDateTime.now()); ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment, oldApplicationAmendmentEntity, VersionActionTypeEnum.UPDATE); + if (isLastRemaining) { + log.info("The current amendment is the last remaining one to be closed."); + applicationAmendmentRequestDao.calculateEndDateAndSuspensionDaysOnExpirationOrClosing(existingApplicationAmendment.getApplicationEvaluationEntity()); + } ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false); List amendmentRequests = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( @@ -1089,12 +1091,12 @@ public class ApplicationAmendmentRequestDao { application.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); applicationRepository.save(application); - existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().setStatus(AssignedApplicationEnum.OPEN.getValue()); - AssignedApplicationsEntity assignedApplicationsEntity = assignedApplicationsDao.validateAssignedApplication( existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().getId()); AssignedApplicationsEntity oldAssignedApplicationData = Utils.getClonedEntityForData(assignedApplicationsEntity); + existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().setStatus(AssignedApplicationEnum.OPEN.getValue()); + assignedApplicationsEntity = assignedApplicationsRepository.save(existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity()); @@ -1121,15 +1123,17 @@ public class ApplicationAmendmentRequestDao { return response; } - public ApplicationAmendmentRequestResponse extendResponseDays(Long id, Long newResponseDays) { - ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); + ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validatApplicationAmendmentRequestByStatus(id,ApplicationAmendmentRequestEnum.EXPIRED.getValue()); if (newResponseDays != null && newResponseDays > 0) { - ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(applicationAmendmentRequestEntity); + ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(applicationAmendmentRequestEntity); Long currentResponseDays = applicationAmendmentRequestEntity.getResponseDays() != null ? applicationAmendmentRequestEntity.getResponseDays() : 0L; applicationAmendmentRequestEntity.setResponseDays(currentResponseDays + newResponseDays); - applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now().plusDays(applicationAmendmentRequestEntity.getResponseDays()))); + applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now().plusDays(newResponseDays))); + applicationAmendmentRequestEntity.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); + applicationAmendmentRequestEntity.getApplicationEvaluationEntity().setStatus(ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue()); + applicationAmendmentRequestEntity.getApplicationEvaluationEntity().getAssignedApplicationsEntity().getApplication().setStatus(ApplicationStatusTypeEnum.SOCCORSO.getValue()); applicationAmendmentRequestRepository.save(applicationAmendmentRequestEntity); /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ @@ -1205,8 +1209,14 @@ public class ApplicationAmendmentRequestDao { beneficiaryUser.getId(), applicationEntity.getId(), amendment.getId(), applicationEntity.getCall().getId()); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email), emailLogRequest); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - emailReminderResponse.setEmailSendResponse(emailSendResponse); - saveEmailSendResponse(emailSendResponse, amendment); + List responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + emailReminderResponse.setEmailSendResponse(responses); + saveEmailSendResponse(emailSendResponse, amendment); + } + else{ + emailReminderResponse.setEmailSendResponse(Collections.emptyList()); + } } else { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.BENEFICIARY_EMAIL_NOT_FOUND_MSG)); } @@ -1241,26 +1251,26 @@ public class ApplicationAmendmentRequestDao { return Utils.replacePlaceholders(template.getHtmlContent(), bodyPlaceholders); } - public ApplicationEvaluationEntity calculateEndDateAndSuspensionDays(ApplicationEvaluationEntity applicationEvaluationEntity){ - LocalDateTime currentDate=DateTimeUtil.DateServerToUTC(LocalDateTime.now()); - LocalDateTime endDate=currentDate.plusDays(applicationEvaluationEntity.getRemainingDays()); - Long suspendedDays = ChronoUnit.DAYS.between(applicationEvaluationEntity.getStopDateTime(), currentDate); - - ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); - applicationEvaluationEntity.setEndDate(endDate); - if(applicationEvaluationEntity.getSuspendedDays() == null) { - applicationEvaluationEntity.setSuspendedDays(0L); - } - applicationEvaluationEntity.setSuspendedDays(applicationEvaluationEntity.getSuspendedDays()+suspendedDays); - ApplicationEvaluationEntity applicationEvaluation = applicationEvaluationRepository.save(applicationEvaluationEntity); - - /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ - loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(applicationEvaluation).build()); - - return applicationEvaluation; - - - } +// public ApplicationEvaluationEntity calculateEndDateAndSuspensionDays(ApplicationEvaluationEntity applicationEvaluationEntity){ +// LocalDateTime currentDate=DateTimeUtil.DateServerToUTC(LocalDateTime.now()); +// LocalDateTime endDate=currentDate.plusDays(applicationEvaluationEntity.getRemainingDays()); +// Long suspendedDays = ChronoUnit.DAYS.between(applicationEvaluationEntity.getStopDateTime(), currentDate); +// +// ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); +// applicationEvaluationEntity.setEndDate(endDate); +// if(applicationEvaluationEntity.getSuspendedDays() == null) { +// applicationEvaluationEntity.setSuspendedDays(0L); +// } +// applicationEvaluationEntity.setSuspendedDays(applicationEvaluationEntity.getSuspendedDays()+suspendedDays); +// ApplicationEvaluationEntity applicationEvaluation = applicationEvaluationRepository.save(applicationEvaluationEntity); +// +// /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ +// loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(applicationEvaluation).build()); +// +// return applicationEvaluation; +// +// +// } private GetAllAmendmentResponseBean initializeGetAllBasicResponse(ApplicationAmendmentRequestEntity entity) { GetAllAmendmentResponseBean response = new GetAllAmendmentResponseBean(); @@ -1565,6 +1575,95 @@ public class ApplicationAmendmentRequestDao { return applicationAmendmentRequestViewResponse; } + public ApplicationEvaluationEntity calculateEndDateAndSuspensionDaysOnExpirationOrClosing + (ApplicationEvaluationEntity applicationEvaluationEntity) { + + + // Fetch all linked amendments + List amendments = + applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(applicationEvaluationEntity.getId()); + + // Recalculate suspension + long suspendedDays = calculateSuspendedDays(amendments); + + // Update end date and save + + ApplicationEvaluationEntity oldEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); + HubEntity hub = hubService.valdateHub(applicationEvaluationEntity.getAssignedApplicationsEntity().getApplication().getHubId()); + Long initialDays = (hub != null) ? hub.getEvaluationExpirationDays() : 30L; + LocalDateTime endDate = applicationEvaluationEntity.getStartDate().plusDays(suspendedDays+initialDays); + applicationEvaluationEntity.setEndDate(endDate); + applicationEvaluationEntity.setSuspendedDays(suspendedDays); + ApplicationEvaluationEntity updated = applicationEvaluationRepository.save(applicationEvaluationEntity); + + loggingUtil.addVersionHistory(VersionHistoryRequest.builder() + .request(request) + .actionType(VersionActionTypeEnum.UPDATE) + .oldData(oldEntity) + .newData(updated) + .build()); + + return updated; + } + + public long calculateSuspendedDays(List amendments) { + List> periods = amendments.stream() + .filter(amendmentRequest -> amendmentRequest.getStartDate() != null) + .map(amendmentRequest -> { + LocalDateTime start = amendmentRequest.getStartDate(); + LocalDateTime end; + + String status = amendmentRequest.getStatus(); + if (Boolean.TRUE.equals(ApplicationAmendmentRequestEnum.CLOSE.getValue().equals(status)) && amendmentRequest.getClosingDate() != null) { + end = amendmentRequest.getClosingDate(); + } else if (Boolean.TRUE.equals(ApplicationAmendmentRequestEnum.EXPIRED.getValue().equals(status)) && amendmentRequest.getEndDate() != null) { + end = amendmentRequest.getStartDate().plusDays(amendmentRequest.getResponseDays()); + }else { + end= amendmentRequest.getEndDate(); + } + + return Pair.of(start, end); + }) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(Pair::getLeft)) + .collect(Collectors.toList()); + + long totalDays = 0; + LocalDateTime currentStart = null; + LocalDateTime currentEnd = null; + + for (Pair period : periods) { + if (currentStart == null) { + currentStart = period.getLeft(); + currentEnd = period.getRight(); + } else if (!period.getLeft().isAfter(currentEnd)) { + // Merge overlapping/touching periods + currentEnd = currentEnd.isAfter(period.getRight()) ? currentEnd : period.getRight(); + } else { + // Non-overlapping: count previous period + totalDays += ChronoUnit.DAYS.between(currentStart.toLocalDate(), currentEnd.toLocalDate()); + currentStart = period.getLeft(); + currentEnd = period.getRight(); + } + } + + if (currentStart != null && currentEnd != null) { + totalDays += ChronoUnit.DAYS.between(currentStart.toLocalDate(), currentEnd.toLocalDate()); + } + + return totalDays; + } + + + + public ApplicationAmendmentRequestEntity validatApplicationAmendmentRequestByStatus(Long id,String status) { + ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalseAndStatus(id, status); + if (applicationAmendmentRequestEntity == null) { + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)); + } + return applicationAmendmentRequestEntity; + } private void saveEmailSendResponse(EmailSendResponse newResponses, ApplicationAmendmentRequestEntity amendment) { List mergedResponses = Utils.mergeEmailSendResponses(amendment.getEmailSendResponse(), newResponses); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 2492e8b0..d8877015 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2170,6 +2170,83 @@ public class ApplicationDao { emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(GepafinConstant.RINALDO_EMAIL),emailLogRequest); } + 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); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index b26a8a2a..8d4ce08e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -314,7 +314,6 @@ public class ApplicationEvaluationDao { response.setUpdatedDate(entity.getUpdatedDate()); response.setNumberOfCheck(entity.getAssignedApplicationsEntity().getApplication().getCall().getNumberOfCheck()); response.setAppointmentTemplateId(entity.getAssignedApplicationsEntity().getApplication().getCall().getAppointmentTemplateId()); - } @@ -1131,10 +1130,14 @@ public class ApplicationEvaluationDao { } else { entityOptional = applicationEvaluationRepository.findFirstByIsDeletedFalseOrderByCreatedDateDesc(); } - return entityOptional.map(this::convertToResponse) - .orElseGet(() -> { - return getEvaluationResponseByApplicationid(user, applicationId, assignedApplicationId); - }); + + if (entityOptional.isEmpty()) { + return null; + } + ApplicationEvaluationEntity entity = entityOptional.get(); + ApplicationEvaluationResponse applicationEvaluationResponse = convertToResponse(entity); + applicationEvaluationResponse.setEmailSendResponse(entity.getEmailSendResponse()); + return applicationEvaluationResponse; } private List prepareEvaluationDocumentBeanList(ApplicationEvaluationEntity entity) { List docRequest = new ArrayList<>(); @@ -1891,12 +1894,16 @@ public class ApplicationEvaluationDao { ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(application); + List responses = new ArrayList<>(); if(newStatus.equals(ApplicationStatusForEvaluation.ADMISSIBLE) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.APPOINTMENT.getValue()))){ application.setStatus(newStatus.getValue()); log.info("Status updated to ADMISSIBLE for applicationId: " + application.getId()); emailNotificationDao.sendAdmissibilityNotificationEmailForAdmissibleApplication(application); emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - saveEmailSendResponseToEvaluation(emailSendResponse,existingEntity); + responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) { + saveEmailSendResponseToEvaluation(emailSendResponse, existingEntity); + } } if(newStatus.equals(ApplicationStatusForEvaluation.TECHNICAL_EVALUATION) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))){ @@ -1943,8 +1950,8 @@ public class ApplicationEvaluationDao { if (Boolean.TRUE.equals(statusType.equals((ApplicationStatusTypeEnum.APPROVED.getValue())))) { - application.setDateAccepted(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); - application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); + application.setDateAccepted(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); + application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application = applicationRepository.save(application); // emailNotificationDao.sendAdmissibilityNotificationEmailForApprovedApplication(application); notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); @@ -1955,7 +1962,10 @@ public class ApplicationEvaluationDao { application = applicationRepository.save(application); emailNotificationDao.sendInadmissibilityEmailForRejectedApplication(application,existingEntity); emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - saveEmailSendResponseToEvaluation(emailSendResponse,existingEntity); + responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) { + saveEmailSendResponseToEvaluation(emailSendResponse, existingEntity); + } notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); } @@ -1966,7 +1976,9 @@ public class ApplicationEvaluationDao { notificationDao.sendNotificationToInstructor(placeHolders,existingEntity,NotificationTypeEnum.EVALUATION_RESULT); ApplicationEvaluationResponse response = convertToResponse(entity); - response.setEmailSendResponse(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) { + response.setEmailSendResponse(responses); + } return response; } return null; @@ -2031,6 +2043,7 @@ public class ApplicationEvaluationDao { ApplicationEvaluationEntity entity = applicationEvaluationService.validateApplicationEvaluation(evaluationResponse.getId()); + //Handling Application Evaluation form EvaluationFormEntity evaluationFormEntity = evaluationFormService.validateEvaluationForm(evaluationFormId); validateFormFields(applicationEvaluationFormRequestBean,evaluationFormEntity); @@ -2039,7 +2052,9 @@ public class ApplicationEvaluationDao { validateFormFieldCustom(applicationEvaluationFormRequestBean.getFormFields(),entity,evaluationFormEntity); ApplicationEvaluationFormEntity applicationEvaluationFormEntity = getApplicationEvaluationFormOrCreate(evaluationFormEntity,entity); createOrUpdateMultipleFormFields(applicationEvaluationFormRequestBean.getFormFields(), applicationEvaluationFormEntity, evaluationFormEntity); - return processEvaluationForm(entity); + ApplicationEvaluationFormResponse response = processEvaluationForm(entity); + response.setEmailSendResponse(evaluationResponse.getEmailSendResponse()); + return response; } private ApplicationEvaluationFormEntity getApplicationEvaluationFormOrCreate(EvaluationFormEntity evaluationFormEntity, ApplicationEvaluationEntity applicationEvaluationEntity) { @@ -2284,6 +2299,7 @@ public class ApplicationEvaluationDao { } response.setCompanyVatNumber(company.getVatNumber()); response.setCompanyCodiceAteco(company.getCodiceAteco()); + response.setEmailSendResponse(evaluationEntity.getEmailSendResponse()); return response; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index d83cb36e..ce99d828 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -1,7 +1,6 @@ package net.gepafin.tendermanagement.dao; import com.amazonaws.services.s3.AmazonS3Client; -import com.amazonaws.services.s3.model.GetObjectRequest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -13,12 +12,14 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.config.jwt.TokenProvider; import net.gepafin.tendermanagement.constants.AppointmentApiConstant; import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestEntity; import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity; import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.DocumentEntity; import net.gepafin.tendermanagement.entities.HubEntity; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.enums.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.model.request.AppointmentCreationRequest; @@ -63,7 +64,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -145,6 +145,15 @@ public class AppointmentDao { @Autowired private AmazonS3Service amazonS3Service; + @Autowired + private ApplicationDao applicationDao; + + @Autowired + private ApplicationAmendmentRequestDao applicationAmendmentRequestDao; + + @Autowired + private ApplicationEvaluationDao applicationEvaluationDao; + private final Map executorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap threadForDocumentMap = new ConcurrentHashMap<>(); @@ -175,9 +184,182 @@ public class AppointmentDao { return ndgResponse; } - private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { + // private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { + // + // int maxRetries = 3; + // int attempt = 0; + // boolean success = false; + // while (attempt < maxRetries && !success) { + // attempt++; + // try { + // //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call + // String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); + // log.info("Got the auth for login to odessa {}", authJwtToken); + // hub.setAuthToken(authJwtToken); + // hubRepository.save(hub); + // Map body = Collections.emptyMap(); + // ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); + // if (responseLogin.getStatusCode() == HttpStatus.OK) { + // log.info("Login successful to odessa. Parsing response."); + // String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); + // AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); + // + // // Validate and save token + // if (parsedResponse.getTokenId() != null) { + // hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); + // hub.setAreaCode(parsedResponse.getAreaCode()); + // hubRepository.save(hub); + // log.info("Saved new authToken and areaCode for Hub."); + // success = true; + // return hub; + // } else { + // throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); + // } + // } + // throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); + // } catch (FeignException.Forbidden forbiddenException) { + // log.error("Failed to login to odessa due to some error"); + // + // // Extract raw response body + // String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + // + // // Parse JSON to check for "PasswordExpired" + // try { + // ObjectMapper objectMapper = new ObjectMapper(); + // JsonNode rootNode = objectMapper.readTree(responseBody); + // JsonNode errorsNode = rootNode.path("errors"); + // + // if (errorsNode.isArray()) { + // for (JsonNode error : errorsNode) { + // // Check the main errorCode + // if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + // application.setNdgStatus(GepafinConstant.NDG_FAILED); + // applicationRepository.save(application); + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // + // // Check inside "subErrors" + // JsonNode subErrorsNode = error.path("subErrors"); + // if (subErrorsNode.isArray()) { + // for (JsonNode subError : subErrorsNode) { + // if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { + // application.setNdgStatus(GepafinConstant.NDG_FAILED); + // applicationRepository.save(application); + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // } + // } + // } + // } + // } catch (IOException e) { + // log.error("Error parsing JSON response: {}", e.getMessage()); + // } + // } catch (Exception e) { + // log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); + // throw new RuntimeException("Authentication failed on Odessa. try again", e); + // } + // } + // return null; + // } + // + // + // private HubEntity authenticateAndSaveToken(HubEntity hub) { + // + // int maxRetries = 3; + // int attempt = 0; + // boolean success = false; + // while (attempt < maxRetries && !success) { + // attempt++; + // try { + // //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call + // String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); + // log.info("Got the auth for login to odessa {}", authJwtToken); + // hub.setAuthToken(authJwtToken); + // hubRepository.save(hub); + // // Prepare the request body (adjust if necessary for login API) + // Map body = Collections.emptyMap(); + // // Perform login API call + // ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); + // + // // Handle successful login + // if (responseLogin.getStatusCode() == HttpStatus.OK) { + // log.info("Login successful to odessa. Parsing response."); + // String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); + // AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); + // + // // Validate and save token + // if (parsedResponse.getTokenId() != null) { + // hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); + // hub.setAreaCode(parsedResponse.getAreaCode()); + // hubRepository.save(hub); + // + // log.info("Saved new authToken and areaCode for Hub."); + // success = true; + // return hub; + // } else { + // throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); + // } + // } + // // Handle non-OK response + // throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); + // } catch (FeignException.Forbidden forbiddenException) { + // log.error("Failed to login to odessa due to some error occurred."); + // + // // Extract raw response body + // String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + // + // // Parse JSON to check for "PasswordExpired" + // try { + // ObjectMapper objectMapper = new ObjectMapper(); + // JsonNode rootNode = objectMapper.readTree(responseBody); + // JsonNode errorsNode = rootNode.path("errors"); + // + // if (errorsNode.isArray()) { + // for (JsonNode error : errorsNode) { + // // Check the main errorCode + // if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // + // // Check inside "subErrors" + // JsonNode subErrorsNode = error.path("subErrors"); + // if (subErrorsNode.isArray()) { + // for (JsonNode subError : subErrorsNode) { + // if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // } + // } + // } + // } + // } catch (IOException e) { + // log.error("Error parsing JSON response: {}", e.getMessage()); + // } + // } catch (Exception e) { + // log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); + // throw new RuntimeException("Authentication failed on Odessa. try again", e); + // } + // } + // return null; + // } + + private void loginToOdessa(HubEntity hub, ApplicationEntity application) { + + performOdessaLogin(hub, application); + } + + private HubEntity authenticateAndSaveToken(HubEntity hub, ApplicationEntity application) { + + return performOdessaLogin(hub, application); + } + + private HubEntity performOdessaLogin(HubEntity hub, ApplicationEntity application) { + + int maxRetries = 3; + int attempt = 0; + while (attempt < maxRetries) { + attempt++; try { - //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); log.info("Got the auth for login to odessa {}", authJwtToken); hub.setAuthToken(authJwtToken); @@ -189,7 +371,6 @@ public class AppointmentDao { String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); - // Validate and save token if (parsedResponse.getTokenId() != null) { hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); hub.setAreaCode(parsedResponse.getAreaCode()); @@ -201,53 +382,52 @@ public class AppointmentDao { } } throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); + } catch (FeignException.Forbidden forbiddenException) { + log.error("Failed to login to odessa due to forbidden error."); + + CheckPasswordExpiredOrErrorInResponse(application, forbiddenException); + } catch (Exception e) { + log.error("Failed to authenticate user on Odessa (Attempt {}): {}", attempt, e.getMessage(), e); } - catch (FeignException.Forbidden forbiddenException) { - logForbiddenError(); + } + throw new RuntimeException("Max retries exceeded. Failed to login to Odessa."); + } + private void CheckPasswordExpiredOrErrorInResponse(ApplicationEntity application, FeignException.Forbidden forbiddenException) { - // Extract raw response body - String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + String responseBody = forbiddenException.contentUTF8(); - // Parse JSON to check for "PasswordExpired" - try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(responseBody); - JsonNode errorsNode = rootNode.path("errors"); + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(responseBody); + JsonNode errorsNode = rootNode.path("errors"); - if (errorsNode.isArray()) { - for (JsonNode error : errorsNode) { - // Check the main errorCode - if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { - application.setNdgStatus(GepafinConstant.NDG_FAILED); - applicationRepository.save(application); - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } + if (errorsNode.isArray()) { + for (JsonNode error : errorsNode) { + if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + if (application != null) { + application.setNdgStatus(GepafinConstant.NDG_FAILED); + applicationRepository.save(application); + } + throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + } - // Check inside "subErrors" - JsonNode subErrorsNode = error.path("subErrors"); - if (subErrorsNode.isArray()) { - for (JsonNode subError : subErrorsNode) { - if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { - application.setNdgStatus(GepafinConstant.NDG_FAILED); - applicationRepository.save(application); - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } + JsonNode subErrorsNode = error.path("subErrors"); + if (subErrorsNode.isArray()) { + for (JsonNode subError : subErrorsNode) { + if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { + if (application != null) { + application.setNdgStatus(GepafinConstant.NDG_FAILED); + applicationRepository.save(application); } + throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); } } } - } catch (IOException e) { - log.error("Error parsing JSON response: {}", e.getMessage()); } - - // Regenerate the token and retry - loginToOdessa(hub, application); } - catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); - throw new RuntimeException("Authentication failed on Odessa. try again", e); - } - return null; + } catch (IOException e) { + log.error("Error parsing JSON response: {}", e.getMessage()); + } } private void startAsyncNdgProcessing(Long applicationId) { @@ -296,7 +476,7 @@ public class AppointmentDao { try { // Authenticate and fetch token if required if (hub.getAppointmentAuthTokenId() == null || hub.getAreaCode() == null) { - authenticateAndSaveToken(hub); + authenticateAndSaveToken(hub, application); } String authorizationToken = getBearerToken(hub); @@ -349,7 +529,7 @@ public class AppointmentDao { placeHolders.put("{{call_name}}", application.getCall().getName()); placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber())); notificationDao.sendNotificationToInstructor(placeHolders, applicationEvaluationEntity, NotificationTypeEnum.NDG_GENERATION); - notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.NDG_GENERATION); + notificationDao.sendNotificationToSuperUser(application, placeHolders, NotificationTypeEnum.NDG_GENERATION); log.info("NDG saved successfully for applicationId: {}", application.getId()); break; } @@ -402,7 +582,7 @@ public class AppointmentDao { placeHolders.put("{{call_name}}", application.getCall().getName()); placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber())); notificationDao.sendNotificationToInstructor(placeHolders, applicationEvaluationEntity, NotificationTypeEnum.NDG_GENERATION); - notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.NDG_GENERATION); + notificationDao.sendNotificationToSuperUser(application, placeHolders, NotificationTypeEnum.NDG_GENERATION); log.info("NDG saved for applicationId: {}, {}", application.getId(), application.getNdg()); } @@ -420,7 +600,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { log.error("403 Forbidden received while getting visuraList for Ndg code. Regenerating token..."); // Regenerate the token and retry - String newAuthorizationToken = regenerateTokenAndSave(hub); + String newAuthorizationToken = regenerateTokenAndSave(hub, application); return getVisuraList(idVisura, newAuthorizationToken, application, hub); } catch (Exception e) { log.error("Failed to fetch Ndg code: {}", e.getMessage(), e); @@ -428,82 +608,6 @@ public class AppointmentDao { } } - private HubEntity authenticateAndSaveToken(HubEntity hub) { - - try { - //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call - String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); - log.info("Got the auth for login to odessa {}", authJwtToken); - hub.setAuthToken(authJwtToken); - hubRepository.save(hub); - // Prepare the request body (adjust if necessary for login API) - Map body = Collections.emptyMap(); - // Perform login API call - ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); - - // Handle successful login - if (responseLogin.getStatusCode() == HttpStatus.OK) { - log.info("Login successful to odessa. Parsing response."); - String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); - AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); - - // Validate and save token - if (parsedResponse.getTokenId() != null) { - hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); - hub.setAreaCode(parsedResponse.getAreaCode()); - hubRepository.save(hub); - - log.info("Saved new authToken and areaCode for Hub."); - return hub; - } else { - throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); - } - } - // Handle non-OK response - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); - } catch (FeignException.Forbidden forbiddenException) { - logForbiddenError(); - - // Extract raw response body - String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response - - // Parse JSON to check for "PasswordExpired" - try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(responseBody); - JsonNode errorsNode = rootNode.path("errors"); - - if (errorsNode.isArray()) { - for (JsonNode error : errorsNode) { - // Check the main errorCode - if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } - - // Check inside "subErrors" - JsonNode subErrorsNode = error.path("subErrors"); - if (subErrorsNode.isArray()) { - for (JsonNode subError : subErrorsNode) { - if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } - } - } - } - } - } catch (IOException e) { - log.error("Error parsing JSON response: {}", e.getMessage()); - } - - // Regenerate the token and retry - regenerateTokenAndSave(hub); - } catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); - throw new RuntimeException("Authentication failed on Odessa. try again", e); - } - return null; - } - private AppointmentLoginResponse retrieveNdgByVatNumber(String vatNumber, String authorizationToken, HubEntity hub, ApplicationEntity application) { try { @@ -517,7 +621,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { logForbiddenError(); // Regenerate the token and retry - String newAuthorizationToken = regenerateTokenAndSave(hub); + String newAuthorizationToken = regenerateTokenAndSave(hub, application); return retrieveNdgByVatNumber(vatNumber, newAuthorizationToken, hub, application); } catch (Exception e) { log.error("Failed to retrieve NDG by VAT number: {}", e.getMessage(), e); @@ -525,9 +629,10 @@ public class AppointmentDao { } } - private String regenerateTokenAndSave(HubEntity hub) { - hub = authenticateAndSaveToken(hub); - return "Bearer " + hub.getAppointmentAuthTokenId(); + private String regenerateTokenAndSave(HubEntity hub, ApplicationEntity application) { + + hub = authenticateAndSaveToken(hub, application); + return "Bearer " + hub.getAppointmentAuthTokenId(); } private AppointmentLoginResponse createVisura(CompanyEntity company, String authorizationToken, HubEntity hub) { @@ -540,7 +645,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { logForbiddenError(); // Regenerate the token and retry - String newAuthorizationToken = regenerateTokenAndSave(hub); + String newAuthorizationToken = regenerateTokenAndSave(hub, null); return createVisura(company, newAuthorizationToken, hub); } catch (Exception e) { log.error("Failed to create Visura for Ndg : {}", e.getMessage()); @@ -710,9 +815,8 @@ public class AppointmentDao { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_NOT_FOUND_FOR_APPLICATION)); } - hub = authenticateAndSaveToken(hub); // Generate authorization token and fetch template data - String authorizationToken = getBearerToken(hub); + String authorizationToken = regenerateTokenAndSave(hub, application); Long appointmentTemplateId = application.getCall().getAppointmentTemplateId(); if (appointmentTemplateId == null) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPOINTMENT_CANNOT_BE_CREATED)); @@ -756,7 +860,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { log.error("403 Forbidden received while retrieving template. Regenerating token..."); - regenerateTokenAndSave(hub); + regenerateTokenAndSave(hub, application); return createAppointment(applicationId, createAppointmentRequest); } } @@ -765,12 +869,31 @@ public class AppointmentDao { if (appointmentResponse.getBody() != null) { log.info("Appointment API Response : {}", appointmentResponse.getBody()); - Map responseBody = (Map) appointmentResponse.getBody(); - if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { - Map data = (Map) responseBody.get(GepafinConstant.DATA_STRING); - if (data != null && data.containsKey(GepafinConstant.ID_STRING)) { - return data.get(GepafinConstant.ID_STRING).toString(); + try { + Map responseBody = (Map) appointmentResponse.getBody(); + // 1. Try to get appointment ID from data.id + if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { + Map data = (Map) responseBody.get(GepafinConstant.DATA_STRING); + if (data != null && data.containsKey(GepafinConstant.ID_STRING)) { + return data.get(GepafinConstant.ID_STRING).toString(); + } } + // 2. If ID not present, check errors[0].cause.errorDescription + if (responseBody.containsKey(GepafinConstant.ERROR_STRING)) { + List> errors = (List>) responseBody.get(GepafinConstant.ERROR_STRING); + if (errors != null && !errors.isEmpty()) { + Map firstError = errors.get(0); + if (firstError.containsKey(GepafinConstant.CAUSE_STRING)) { + Map cause = (Map) firstError.get(GepafinConstant.CAUSE_STRING); + if (cause != null && cause.containsKey(GepafinConstant.ERROR_DESCRIPTION_STRING)) { + String errorDescription = cause.get(GepafinConstant.ERROR_DESCRIPTION_STRING).toString(); + log.warn("Appointment creation failed: {}", errorDescription); + } + } + } + } + } catch (Exception e) { + log.error("Error while extracting appointment ID or parsing error message", e); } } return null; @@ -800,20 +923,20 @@ public class AppointmentDao { JsonNode prodottoNode = richiestaNode.path(AppointmentApiConstant.PRODOTTO); String prodottoCode = prodottoNode.path(AppointmentApiConstant.PRODOTTO_CODE).asText(); - richiestaCliente.setCodProdotto(prodottoCode); - richiestaCliente.setIdMotivazione(getIntValue(richiestaNode)); - richiestaCliente.setCodAbi(getTextValue(richiestaNode, AppointmentApiConstant.COD_ABI)); - richiestaCliente.setCodCab(getTextValue(richiestaNode, AppointmentApiConstant.COD_CAB)); - richiestaCliente.setIdNota(getTextValue(richiestaNode, AppointmentApiConstant.ID_NOTA)); - richiestaCliente.setImportoAgevolato(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_AGEVOLATO)); - richiestaCliente.setImportoMedioLungoTermine(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_MEDIOLUNGO_TERMINE)); - richiestaCliente.setCodTipoProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_TIPO_PRODOTTO)); - richiestaCliente.setCodCategoriaProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_CATEGORIA_PRODOTTO)); - richiestaCliente.setCodFormaTecnica(getTextValue(richiestaNode, AppointmentApiConstant.COD_FORMATECNICA)); - richiestaCliente.setCodOperazione(getTextValue(richiestaNode, AppointmentApiConstant.COD_OPERAZIONE)); + richiestaCliente.setCodProdotto(prodottoCode); + richiestaCliente.setIdMotivazione(getIntValue(richiestaNode)); + richiestaCliente.setCodAbi(getTextValue(richiestaNode, AppointmentApiConstant.COD_ABI)); + richiestaCliente.setCodCab(getTextValue(richiestaNode, AppointmentApiConstant.COD_CAB)); + richiestaCliente.setIdNota(getTextValue(richiestaNode, AppointmentApiConstant.ID_NOTA)); + richiestaCliente.setImportoAgevolato(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_AGEVOLATO)); + richiestaCliente.setImportoMedioLungoTermine(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_MEDIOLUNGO_TERMINE)); + richiestaCliente.setCodTipoProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_TIPO_PRODOTTO)); + richiestaCliente.setCodCategoriaProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_CATEGORIA_PRODOTTO)); + richiestaCliente.setCodFormaTecnica(getTextValue(richiestaNode, AppointmentApiConstant.COD_FORMATECNICA)); + richiestaCliente.setCodOperazione(getTextValue(richiestaNode, AppointmentApiConstant.COD_OPERAZIONE)); - richiestaClienteList.add(richiestaCliente); - } + richiestaClienteList.add(richiestaCliente); + } input.setRichiestaCliente(richiestaClienteList); appointmentCreationRequest.setInput(input); @@ -874,13 +997,40 @@ public class AppointmentDao { // Check if the document is already being processed DocumentEntity systemDoc = documentDao.validateDocument(documentId); + ApplicationEntity application = null; + + if (systemDoc != null) { + DocumentSourceTypeEnum sourceType = DocumentSourceTypeEnum.valueOf(systemDoc.getSource()); + + switch (sourceType) { + case APPLICATION: + application = applicationDao.validateApplication(systemDoc.getSourceId()); + break; + case AMENDMENT: + ApplicationAmendmentRequestEntity applicationAmendmentEntity = applicationAmendmentRequestDao.validateApplicationAmendmentRequest(systemDoc.getSourceId()); + application = applicationDao.validateApplication(applicationAmendmentEntity.getApplicationId()); + break; + case EVALUATION: + ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationDao.validateApplicationEvaluation(systemDoc.getSourceId()); + application = applicationDao.validateApplication(applicationEvaluationEntity.getApplicationId()); + break; + + case CALL: + break; + + default: + log.warn("Unhandled document source type: {}", sourceType); + break; + } + } + Claims claims = tokenProvider.getClaimsFromToken(tokenProvider.extractTokenFromRequest(request)); Long hubId = Utils.extractHubIdFromPayload(claims.getSubject()); // Authenticate the hub before proceeding HubEntity hub = hubRepository.findByHubId(hubId); - authenticateAndSaveToken(hub); - if (systemDoc.getDocumentAttachmentId() != null) { + authenticateAndSaveToken(hub, application); + if (systemDoc != null && systemDoc.getDocumentAttachmentId() != null) { // If the documentAttachmentId is already set, return the response log.info("Document already uploaded with documentAttachmentId: {}", systemDoc.getDocumentAttachmentId()); DocumentUploadResponse response = new DocumentUploadResponse(); @@ -900,11 +1050,12 @@ public class AppointmentDao { }); threadForDocumentMap.put(documentId, executor); + ApplicationEntity finalApplication = application; executor.submit(() -> { threadLocalHubId.set(hubId); try { log.info("Starting async document upload for documentId: {}", documentId); - uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest); + uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest, finalApplication); } catch (Exception e) { log.error("Error in async document upload for documentId: {}", documentId, e); } finally { @@ -920,7 +1071,7 @@ public class AppointmentDao { return null; } - private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest) { + private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest, ApplicationEntity application) { // Synchronous upload logic DocumentEntity systemDoc = documentDao.validateDocument(documentId); @@ -961,8 +1112,8 @@ public class AppointmentDao { log.info("Document uploaded successfully to external system: {}", parsedResponse); } catch (FeignException.Forbidden forbiddenException) { log.error("403 Forbidden received while uploading document. Regenerating token..."); - regenerateTokenAndSave(hub); - uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest); + regenerateTokenAndSave(hub, application); + uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest, application); } catch (Exception e) { log.error("Exception during document upload: {}", e.getMessage(), e); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.EXTERNAL_DOCUMENT_UPLOAD_FAILURE_MSG)); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java index c7263313..7339a7c5 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java @@ -315,7 +315,8 @@ public class AssignedApplicationsDao { if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } - Specification spec = searchByPagination( assignedApplicationPageableRequestBean, user,userId); + Long hubId=user.getHub().getId(); + Specification spec = searchByPagination( assignedApplicationPageableRequestBean,hubId,userId); Page entityPage = assignedApplicationsViewRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response @@ -333,10 +334,10 @@ public class AssignedApplicationsDao { return pageableResponseBean; } - public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, UserEntity userEntity,Long userId) { + public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, Long hubId,Long userId) { return (root, query, criteriaBuilder) -> { - List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, userEntity,userId); + List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, hubId,userId); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (assignedApplicationPageableRequestBean.getGlobalFilters() != null @@ -377,7 +378,7 @@ public class AssignedApplicationsDao { private List getPredicates(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, - CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity,Long userId) { + CriteriaBuilder criteriaBuilder, Root root,Long hubId,Long userId) { Integer year = null; String search = null; @@ -448,6 +449,8 @@ public class AssignedApplicationsDao { } predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); + predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.HUB_ID), hubId)); + Utils.applyFiltersByPagination(root, criteriaBuilder, predicates, filters); return predicates; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java index 6e46d475..244df6a4 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java @@ -5,9 +5,7 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.extern.log4j.Log4j2; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; -import net.gepafin.tendermanagement.entities.CallEntity; -import net.gepafin.tendermanagement.entities.EmailLogEntity; -import net.gepafin.tendermanagement.entities.UserActionEntity; +import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.RecipientTypeEnum; @@ -15,8 +13,7 @@ import net.gepafin.tendermanagement.enums.StatusTypeEnum; import net.gepafin.tendermanagement.model.request.EmailLogRequest; import net.gepafin.tendermanagement.model.response.EmailResendResponseBean; import net.gepafin.tendermanagement.model.response.EmailSendResponse; -import net.gepafin.tendermanagement.repositories.EmailLogRepository; -import net.gepafin.tendermanagement.repositories.UserActionsRepository; +import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; @@ -47,6 +44,15 @@ public class EmailDao { @Autowired private UserActionsRepository userActionsRepository; + @Autowired + private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private ApplicationEvaluationRepository applicationEvaluationRepository; + public EmailResendResponseBean resendEmail(HttpServletRequest request , Long userActionId){ UserActionEntity userActionEntity = userActionsRepository.findUserActionByIdAndIsDeletedFalse(userActionId); if(userActionEntity == null){ @@ -82,9 +88,92 @@ public class EmailDao { } EmailSendResponse emailSendResponse = buildEmailSendResponseFromRequest(request); emailResendResponseBean.setEmailSendResponse(emailSendResponse); + + if (Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + updateEmailSendStatusIfSuccessful(emailSendResponse); + } return emailResendResponseBean; } + private void updateEmailSendStatusIfSuccessful(EmailSendResponse emailSendResponse){ + Long actionId = emailSendResponse.getUserActionId(); + + EmailLogEntity emailLog = emailLogRepository.findTopByUserActionIdAndEmailServiceTypeAndSendStatusOrderByIdDesc( + actionId, + EmailServiceTypeEnum.PEC_SERVICE.getValue(), + StatusTypeEnum.SUCCESS.getValue() + ); + if (emailLog != null) { + switch (emailSendResponse.getEmailScenario()) { + case APPLICATION_AMENDMENT_REQUESTED: + case APPLICATION_AMENDMENT_REMINDER: + updateApplicationAmendmentStatus(emailLog, emailSendResponse.getEmailScenario().getValue()); + break; + + case USER_CREATION: + case PASSWORD_RESET_REQUEST: + updateUserEmailStatus(emailLog, emailSendResponse.getEmailScenario().getValue()); + break; + + case APPLICATION_ADMISSIBLE: + case APPLICATION_REJECTED: + updateApplicationEvaluationStatus(emailLog, emailSendResponse.getEmailScenario().getValue()); + break; + + default: + log.warn("Unhandled email scenario: {}", emailSendResponse.getEmailScenario()); + } + } + } + + private void updateApplicationAmendmentStatus(EmailLogEntity log, String scenario) { + if (log.getAmendmentId() != null) { + applicationAmendmentRequestRepository.findById(log.getAmendmentId()).ifPresent(amendment -> { + if (updateEmailSendResponse(amendment.getEmailSendResponse(), scenario)) { + applicationAmendmentRequestRepository.save(amendment); + } + }); + } + } + + private void updateApplicationEvaluationStatus(EmailLogEntity log, String scenario) { + if (log.getApplicationId() != null) { + ApplicationEvaluationEntity evaluation = applicationEvaluationRepository.findByApplicationId(log.getApplicationId()); + if (evaluation != null && updateEmailSendResponse(evaluation.getEmailSendResponse(), scenario)) { + applicationEvaluationRepository.save(evaluation); + } + } + } + + private void updateUserEmailStatus(EmailLogEntity log, String scenario) { + if (log.getUserId() != null) { + userRepository.findById(log.getUserId()).ifPresent(user -> { + if (updateEmailSendResponse(user.getEmailSendResponse(), scenario)) { + userRepository.save(user); + } + }); + } + } + + + + + private boolean updateEmailSendResponse(List responses, String scenario) { + if (responses == null || responses.isEmpty()) return false; + + for (Iterator iterator = responses.iterator(); iterator.hasNext(); ) { + EmailSendResponse response = iterator.next(); + if (scenario.equals(response.getEmailScenario().getValue())) { + iterator.remove(); // remove only the first match + return true; + } + } + return false; + } + + + + public EmailSendResponse buildEmailSendResponseFromRequest(HttpServletRequest request) { Long userActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID); List emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceType(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java index 234ffa1d..0403fde3 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java @@ -149,17 +149,25 @@ public class UserDao { /** This code is responsible for adding a version history log for the "Create user" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(userEntity).build()); - EmailSendResponse emailSendResponse = new EmailSendResponse(); + List responses = new ArrayList<>(); if(Boolean.FALSE.equals(roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue()))){ sendEmailToOnboardingUser(userEntity, userReq ); boolean isEmailSendSuccess = isEmailSentSuccessfully(userEntity.getId()); - emailSendResponse.setIsEmailSend(isEmailSendSuccess); - Long userActionId =(Long)request.getAttribute(GepafinConstant.USER_ACTION_ID); - emailSendResponse.setUserActionId(userActionId); - emailSendResponse.setEmailScenario(EmailScenarioTypeEnum.USER_CREATION); - saveEmailSendResponseToUser(emailSendResponse,userEntity); + EmailSendResponse emailSendResponse = new EmailSendResponse(); + if (Boolean.FALSE.equals(isEmailSendSuccess)){ + emailSendResponse.setIsEmailSend(false); + Long userActionId =(Long)request.getAttribute(GepafinConstant.USER_ACTION_ID); + emailSendResponse.setUserActionId(userActionId); + emailSendResponse.setEmailScenario(EmailScenarioTypeEnum.USER_CREATION); + + saveEmailSendResponseToUser(emailSendResponse,userEntity); + responses = List.of(emailSendResponse); + } + else{ + responses = Collections.emptyList(); + } } - JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId(),emailSendResponse); + JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId(),responses); return token; } @@ -509,8 +517,14 @@ public class UserDao { sendResetPasswordTokenEmail(user, token); InitiatePasswordResetResponse initiatePasswordResetResponse = new InitiatePasswordResetResponse(); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - initiatePasswordResetResponse.setEmailSendResponse(emailSendResponse); - saveEmailSendResponseToUser(emailSendResponse,user); + List responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + initiatePasswordResetResponse.setEmailSendResponse(responses); + saveEmailSendResponseToUser(emailSendResponse,user); + } + else{ + initiatePasswordResetResponse.setEmailSendResponse(Collections.emptyList()); + } return initiatePasswordResetResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java index 71cd1075..46bf004b 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java @@ -64,4 +64,7 @@ public class AssignedApplicationsView{ @Convert(converter = EmailSendResponseConverter.class) @Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT") private List emailSendResponse; + + @Column(name = "HUB_ID") + private Long hubId; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java b/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java index d02a842d..43409886 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java @@ -18,6 +18,9 @@ public class EmailSendResponseConverter implements AttributeConverter attribute) { try { + if (attribute == null) { + attribute = List.of(); + } return objectMapper.writeValueAsString(attribute); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Error converting list to JSON", e); diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index 9fae6ce7..fe2e4cd1 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -46,6 +46,7 @@ public enum UserActionContextEnum { GET_SIGNED_DOCUMENT("GET_SIGNED_DOCUMENT"), GET_NEXT_PREVIOUS_FORM("GET_NEXT_PREVIOUS_FORM"), DOWNLOAD_APPLICATION_DOC_ZIP("DOWNLOAD_APPLICATION_DOC_ZIP"), + READMIT_APPLICATION("READMIT_APPLICATION"), /** FAQ action context **/ CREATE_FAQ("CREATE_FAQ"), diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java index ace60672..c7f1a2eb 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java @@ -32,5 +32,5 @@ public class ApplicationAmendmentRequestResponse { private String internalNote; private ApplicationAmendmentRequestEnum status; private String emailTemplate; - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java index 38530c8a..92f7933a 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java @@ -48,5 +48,6 @@ public class ApplicationEvaluationFormResponse { private Long appointmentTemplateId; private String companyVatNumber; private String companyCodiceAteco; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java index 187aa1dd..49f07c6f 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java @@ -49,6 +49,6 @@ public class ApplicationEvaluationResponse { private EvaluationVersionEnum evaluationVersion; private String companyVatNumber; private String companyCodiceAteco; - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponseBean.java new file mode 100644 index 00000000..4cda0fca --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponseBean.java @@ -0,0 +1,52 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; +import net.gepafin.tendermanagement.enums.ApplicationEvaluationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.EvaluationVersionEnum; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class ApplicationEvaluationResponseBean { + + private Long id; + private Long applicationId; + private ApplicationStatusTypeEnum applicationStatus; + private Long assignedApplicationId; + private String note; + private ApplicationEvaluationStatusTypeEnum status; + private Long minScore; + private List criteria; + private List checklist; + private List files; + private List evaluationDocument; + private List amendmentDetails; + private LocalDateTime createdDate; + private LocalDateTime updatedDate; + private String beneficiary; + private Long assignedUserId; + private String assignedUserName; + private Long protocolNumber; + private String callName; + private String motivation; + private LocalDateTime submissionDate; + private LocalDateTime evaluationEndDate; + private LocalDateTime callEndDate; + private String companyName; + private LocalDateTime assignedAt; + private String ndg; + private String appointmentId; + private BigDecimal amountRequested; + private BigDecimal amountAccepted; + private LocalDateTime dateAccepted; + private LocalDateTime dateRejected; + private Long numberOfCheck; + private Long appointmentTemplateId; + private EvaluationVersionEnum evaluationVersion; + private String companyVatNumber; + private String companyCodiceAteco; + private List emailSendResponse; +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java index d76b4fcd..25b8a3b3 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java @@ -5,12 +5,14 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor public class EmailReminderResponse { @JsonProperty("emailSendResponse") - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java index c14ef643..129a1744 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java @@ -5,9 +5,11 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor public class InitiatePasswordResetResponse { - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java index a65f7d6e..fdfb3e3a 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java +++ b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java @@ -6,6 +6,8 @@ import lombok.Data; import net.gepafin.tendermanagement.model.response.EmailSendResponse; import net.gepafin.tendermanagement.model.response.LoginResponse; +import java.util.List; + /** * JWTToken */ @@ -18,14 +20,14 @@ public class JWTToken { private LoginResponse loginResponse; @JsonProperty("emailSendResponse") - private EmailSendResponse emailSendResponse; + private List emailSendResponse; public JWTToken(String token, LoginResponse loginResponse) { this.token = token; this.loginResponse = loginResponse; } - public JWTToken(String token, LoginResponse loginResponse, EmailSendResponse emailSendResponse) { + public JWTToken(String token, LoginResponse loginResponse, List emailSendResponse) { this.token = token; this.loginResponse = loginResponse; this.emailSendResponse = emailSendResponse; diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java index fc492019..4cd6d413 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java @@ -150,4 +150,6 @@ public interface ApplicationAmendmentRequestRepository extends JpaRepository applicationIds, @Param("statuses") List statuses); + + ApplicationAmendmentRequestEntity findByIdAndIsDeletedFalseAndStatus(Long id,String status); } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java index 9019aad4..87fe8045 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java @@ -76,5 +76,14 @@ public interface ApplicationEvaluationRepository extends JpaRepository findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse( + Long assignedApplicationId, + String status + ); + @Query("SELECT ae FROM ApplicationEvaluationEntity ae WHERE ae.applicationId = :applicationId AND ae.isDeleted = false") + ApplicationEvaluationEntity findByApplicationId(@Param("applicationId") Long applicationId); + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java index b5cf7fb9..c760689a 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java @@ -178,4 +178,7 @@ public interface ApplicationRepository extends JpaRepository findByApplicationIdAndStatusAndIsDeletedFalse( Long applicationId, String status); + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java index 669c4b69..9d9e26e5 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java @@ -17,5 +17,12 @@ public interface EmailLogRepository extends JpaRepository { List findByUserActionIdAndEmailServiceType( Long userActionId, String emailServiceType); + EmailLogEntity findTopByUserActionIdAndEmailServiceTypeAndSendStatusOrderByIdDesc( + Long userActionId, + String emailServiceType, + String sendStatus + ); + + } diff --git a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java index 6a4c7b81..050b4972 100644 --- a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java +++ b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java @@ -122,7 +122,7 @@ public class ApplicationAmendmentScheduler { .findEvaluationsWithoutActiveAmendmentsByIds(applicationEvaluationIds); evaluationsWithoutActiveAmendmentList.forEach(evaluation -> { try { - applicationAmendmentRequestDao.calculateEndDateAndSuspensionDays(evaluation); + applicationAmendmentRequestDao.calculateEndDateAndSuspensionDaysOnExpirationOrClosing(evaluation); updateEvaluationStatus(evaluation); diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java index 9b4b63ed..b19f77c4 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java @@ -16,7 +16,7 @@ public interface ApplicationAmendmentRequestService { public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(HttpServletRequest request,Long applicationEvaluationId); public ApplicationAmendmentRequestResponse createApplicationAmendmentRequest(HttpServletRequest request, Long applicationEvaluationId , ApplicationAmendmentRequest applicationAmendmentRequest); void deleteApplicationAmendmentRequest(HttpServletRequest request, Long id); - ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(HttpServletRequest request,Long id); + ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(HttpServletRequest request,Long id); List getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId); ApplicationAmendmentRequestResponse updateApplicationAmendment(HttpServletRequest request, Long id, ApplicationAmendmentRequestBean applicationAmendmentRequestBean); ApplicationAmendmentRequestEntity validateApplicationAmendmentRequest(Long applicationAmendmentId); diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index 24fde801..c7af4f88 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -50,4 +50,6 @@ public interface ApplicationService { public byte[] exportCsv(HttpServletRequest request, Long callId); + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java index 20a1e455..a680ec1b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java @@ -75,7 +75,7 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm } @Override - public ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { + public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(id) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java index 044c0902..650acdc1 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java @@ -11,6 +11,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationEvaluationFormReque import net.gepafin.tendermanagement.model.request.ApplicationEvaluationRequest; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationFormResponse; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationResponse; +import net.gepafin.tendermanagement.model.response.ApplicationEvaluationResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationVersionResponse; import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository; import net.gepafin.tendermanagement.service.ApplicationEvaluationService; diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index 879c72cf..357661d1 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -170,5 +170,10 @@ public class ApplicationServiceImpl implements ApplicationService { return csvBytes; } - + @Override + @Transactional(rollbackFor = Exception.class) + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId) { + UserEntity userEntity = validator.validateUser(request); + return applicationDao.readmitApplication(request, applicationId); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java index e112d40e..01ad155b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java @@ -142,7 +142,7 @@ public class AuthenticationService { loginAttemptEntity.setErrorMsg(errorMsg); loginAttemptDao.createLoginAttempt(loginAttemptEntity); } - public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId, EmailSendResponse emailSendResponse) { + public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId, List emailSendResponse) { UserEntity oldUserEntity = Utils.getClonedEntityForData(user); user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); user = userRepository.save(user); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java index 25b53b3c..5d81ce7e 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java @@ -72,7 +72,7 @@ public interface ApplicationAmendmentRequestApi { @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) @GetMapping(value = "", produces = "application/json") - ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,@Parameter(description = "The application amendment id", required = true) @RequestParam(value = "id", required = true) Long id); + ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,@Parameter(description = "The application amendment id", required = true) @RequestParam(value = "id", required = true) Long id); @Operation(summary = "Api to get all applications amendment request by preInstructor user Id (deprecated)", responses = { diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index 00609f68..a18e6852 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -238,6 +238,20 @@ public interface ApplicationApi { public ResponseEntity exportCsv( HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable(value = "callId", required = true) Long callId); + @Operation(summary = "Api to re-admit an application", + responses = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) + @PutMapping(value = "/{applicationId}/readmit", produces = { "application/json" }) + @PreAuthorize("hasRole('ROLE_SUPER_ADMIN')|| hasRole('ROLE_INSTRUCTOR_MANAGER')|| hasRole('ROLE_PRE_INSTRUCTOR')") + ResponseEntity> readmitApplication(HttpServletRequest request, + @Parameter(description = "The application id", required = true) @PathVariable("applicationId") Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java index 739c2802..0c8ef489 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java @@ -69,14 +69,14 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme } @Override - public ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { + public ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { log.info("Get Application Amendment Request By Id"); /** This code is responsible for creating user action logs for the "get application amendment by id" operation. **/ loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW) .actionContext(UserActionContextEnum.GET_AMENDMENT).build()); - ApplicationAmendmentRequestResponseBean applicationAmendmentRequestResponse = applicationAmendmentRequestService.getApplicationAmendmentRequestById(request,id); + ApplicationAmendmentRequestResponse applicationAmendmentRequestResponse = applicationAmendmentRequestService.getApplicationAmendmentRequestById(request,id); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(applicationAmendmentRequestResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_APPLICATION_AMENDMENT_SUCCESS_MSG))); } @@ -185,11 +185,6 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme EmailReminderResponse emailSendResponse = applicationAmendmentRequestService.sendReminderEmail(request,amendmentId); - if (!emailSendResponse.getEmailSendResponse().getIsEmailSend()) { - return ResponseEntity.status(HttpStatus.OK) - .body(new Response<>(emailSendResponse, Status.EXCEPTION_ERROR, Translator.toLocale(GepafinConstant.REMINDER_EMAIL_FAILED_MSG))); - } - return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(emailSendResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.REMINDER_EMAIL_SENT_SUCCESS_MSG))); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index a06f5dc4..840711ae 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -242,5 +242,16 @@ public class ApplicationApiController implements ApplicationApi { .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(csvBytes); } + @Override + public ResponseEntity> readmitApplication(HttpServletRequest request, Long applicationId) { + /** This code is responsible for creating user action logs for the "re-admit application" operation. **/ + loggingUtil.logUserAction( + UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.READMIT_APPLICATION).build()); + + ApplicationResponse applicationResponse = applicationService.readmitApplication(request, applicationId); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(applicationResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.READMIT_APPLICATION_SUCCESS))); + } } diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index bff80f3f..0b4e6cc7 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2801,4 +2801,8 @@ path="db/dump/update_system_email_template_for_application_submission_failure_08_05_2025.sql"/> + + + diff --git a/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql b/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql new file mode 100644 index 00000000..ec2ba975 --- /dev/null +++ b/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql @@ -0,0 +1,57 @@ + +DROP VIEW IF EXISTS gepafin_schema.assigned_applications_view ; + +CREATE OR REPLACE VIEW gepafin_schema.assigned_applications_view AS +SELECT + -- From assigned_applications + aa.id AS id, + aa.user_id AS user_id, + aa.status AS status, + aa.created_date AS created_date, + aa.updated_date AS updated_date, + aa.is_deleted AS is_deleted, + + -- From application + a.id AS application_id, + a.hub_id as hub_id, + a.status AS application_status, + a.submission_date AS submission_date, + ae.end_date AS evaluation_end_date, + a.ndg AS ndg, + a.appointment_id AS appointment_id, + + -- From protocol (OneToOne) + p.protocol_number AS protocol_number, + + -- From call (ManyToOne) + cl.name AS call_name, + + -- From company (ManyToOne) + c.company_name AS company_name, + ae.email_send_response AS email_send_response + +FROM gepafin_schema.assigned_applications aa + +-- Join application (ManyToOne from assigned_applications) +LEFT JOIN gepafin_schema.application a + ON aa.application_id = a.id + AND (a.is_deleted IS FALSE OR a.is_deleted IS NULL) + +-- Join application_evaluation (application_id matches + not deleted) +LEFT JOIN gepafin_schema.application_evaluation ae + ON ae.application_id = a.id + AND (ae.is_deleted IS FALSE OR ae.is_deleted IS NULL) + +-- Join protocol (OneToOne from application) +LEFT JOIN gepafin_schema.protocol p + ON a.protocol_number = p.id + +-- Join call (ManyToOne from application) +LEFT JOIN gepafin_schema.call cl + ON a.call_id = cl.id + +-- Join company (ManyToOne from application) +LEFT JOIN gepafin_schema.company c + ON a.company_id = c.id + +WHERE aa.is_deleted IS FALSE OR aa.is_deleted IS NULL; diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index ddd71c3e..e69af662 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -404,5 +404,7 @@ invalid.user=Invalid user. reminder.email.sent.failed.msg = Failed to send reminder email resend.email.sent.success.msg = Email resend successfully resend.email.sent.failed.msg = Failed to resend the email. + +application.readmit.success=Application has been readmitted successfully. no.email.log.msg = No failed emails found for given userActionId. -user.action.id.not.found = User Action id not found. \ No newline at end of file +user.action.id.not.found = User Action id not found. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 09ec0e49..ef23cfac 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -53,7 +53,7 @@ call.update.successfully=Chiamata aggiornata con successo. call.fetch.success=Dettagli della chiamata recuperati con successo. call.not.found=Chiamata non trovata. score.not.null=Il punteggio non pu? essere nullo o zero. -field.not.null={0} non può essere vuoto. +field.not.null={0} non pu� essere vuoto. field.not.empty=la {0} non pu? essere vuota. update_call_status_success_msg=Lo stato della chiamata ? stato aggiornato con successo. status.same.error=Lo stato ? gi? impostato. @@ -389,11 +389,13 @@ error.invalid.limit=Il limite dovrebbe essere compreso tra 1 e 3000. insufficient.score.msg = Punteggio non sufficiente per passaggio alla valutazione tecnica ed economico finanziaria validation.table.message=I dati per il campo {0} non sono presenti. -password.expired.for.login.to.odessa = La password di accesso a Odessa è scaduta +password.expired.for.login.to.odessa = La password di accesso a Odessa � scaduta invalid.user=Utente non valido. reminder.email.sent.failed.msg = Impossibile inviare l'e-mail di promemoria resend.email.sent.success.msg = Email reinviata con successo resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail. + +application.readmit.success=L'applicazione è stata riammessa con successo. no.email.log.msg = Nessuna email trovata per userActionId specificato. -user.action.id.not.found = ID azione utente non trovato. \ No newline at end of file +user.action.id.not.found = ID azione utente non trovato.