From 9b21791f9fbc746dc1e96f0590a9d30ba6d3dcd9 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 16 Mar 2026 16:38:53 +0530 Subject: [PATCH] Updated amendment rejection email flow and handled for special amendment --- .../dao/ApplicationAmendmentRequestDao.java | 25 +-------- .../dao/EmailNotificationDao.java | 4 +- .../tendermanagement/dao/PecMailDao.java | 54 +++++++++++++++---- .../ApplicationAmendmentRequestEnum.java | 4 +- .../db/changelog/db.changelog-1.0.0.xml | 4 ++ ..._template_special_amendment_16_03_2026.sql | 7 +++ 6 files changed, 62 insertions(+), 36 deletions(-) create mode 100644 src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 0c12eb8e..33e70a17 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -786,10 +786,6 @@ public class ApplicationAmendmentRequestDao { log.warn("Permission denied: Beneficiary tried to update amendment ID {} with status RESPONSE_RECEIVED", id); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); } - if(Boolean.TRUE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.DRAFT.getValue())){ - log.warn("Permission denied: Beneficiary tried to update amendment ID {} with status DRAFT (only instructor can update)", id); - throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); - } if(Boolean.FALSE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())){ log.warn("Permission denied: Non-beneficiary tried to update amendment ID {} with status AWAITING", id); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); @@ -1283,26 +1279,7 @@ public class ApplicationAmendmentRequestDao { ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); - if (ApplicationAmendmentRequestEnum.AWAITING.equals(statusTypeEnum)) { - // Only instructor can set status to AWAITING (e.g. after finishing edits post email rejection); beneficiary must not be allowed - if (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { - log.warn("Permission denied: Beneficiary/Confidi tried to set amendment ID {} status to AWAITING", id); - throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); - } - validator.validatePreInstructor(request, existingApplicationAmendment.getApplicationEvaluationEntity().getUserId()); - // Allow transition to AWAITING only from DRAFT (e.g. after instructor finished edits post email rejection) - if (!ApplicationAmendmentRequestEnum.DRAFT.getValue().equals(existingApplicationAmendment.getStatus())) { - log.warn("Invalid status transition: amendment ID {} is not in DRAFT (current: {})", id, existingApplicationAmendment.getStatus()); - throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_APPROPIATE_STATUS)); - } - log.info("Updating amendment ID {} status from DRAFT to AWAITING", id); - existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); - existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); - applicationAmendmentRequestRepository.save(existingApplicationAmendment); - loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationAmendmentEntity).newData(existingApplicationAmendment).build()); - // Send the same mail as when (normal) amendment was created; only normal amendments can be in DRAFT (special amendment emails are sent at creation, not held) - emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(existingApplicationAmendment); - } else if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { + if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { log.info("Updating amendment ID {} status from {} to {}", id, existingApplicationAmendment.getStatus(), statusTypeEnum); existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue()); existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index 7cfb73cc..60d867bc 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -427,7 +427,9 @@ public class EmailNotificationDao { if(Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue())) || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue())) || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue())) - || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue()))) { + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue())) + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED.getValue())) + || Boolean.TRUE.equals(emailLogEntity.getEmailType().equals(EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE.getValue()))) { isSendEmail = Boolean.FALSE; } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java index d25e1507..73a352c6 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java @@ -7,6 +7,7 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.ApplicationEvaluationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; @@ -133,16 +134,39 @@ public class PecMailDao { String scenario = firstLog.getEmailType(); Long applicationId = firstLog.getApplicationId(); - // Only normal amendment emails are rejectable in PEC flow; set amendment to DRAFT so only instructor can update - if (EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue().equals(scenario)) { - Long amendmentId = firstLog.getAmendmentId(); - if (amendmentId != null) { - applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId).ifPresent(amendment -> { - amendment.setStatus(ApplicationAmendmentRequestEnum.DRAFT.getValue()); - applicationAmendmentRequestRepository.save(amendment); - log.info("Set amendment id={} to DRAFT after email rejected (userActionId={})", amendmentId, userActionId); - }); + // Amendment email rejected (normal or special): revert application, then mark amendment REJECTED and soft-deleted + boolean isNormalAmendment = EmailScenarioTypeEnum.APPLICATION_AMENDMENT_REQUESTED.getValue().equals(scenario); + boolean isSpecialAmendment = EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED.getValue().equals(scenario) + || EmailScenarioTypeEnum.SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE.getValue().equals(scenario); + + if (isNormalAmendment || isSpecialAmendment) { + ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); + if (isNormalAmendment) { + List appHistory = versionHistoryRepository.findVersionHistoryByUserActionIdAndTableName(userActionId, TABLE_APPLICATION); + Optional applicationVersion = appHistory.stream() + .filter(v -> applicationId.equals(v.getRecordId()) && v.getOldData() != null && !v.getOldData().isEmpty()) + .findFirst(); + if (applicationVersion.isPresent()) { + Map oldDataMap = Utils.convertJsonStringToMap(applicationVersion.get().getOldData()); + if (oldDataMap != null) { + String previousStatus = Utils.extractString(oldDataMap, "status"); + if (previousStatus != null) { + applicationEntity.setStatus(previousStatus); + } + applicationRepository.save(applicationEntity); + log.info("Rolled back application id={} from version history after amendment email rejected (userActionId={})", applicationId, userActionId); + } + } else { + log.warn("No APPLICATION version history with oldData found for userActionId={}, applicationId={}; skipping application rollback", userActionId, applicationId); + } + } else { + applicationEntity.setStatus(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()); + applicationEntity.setDateRejected(null); + applicationRepository.save(applicationEntity); + log.info("Set application id={} to ADMISSIBLE after special amendment email rejected (userActionId={})", applicationId, userActionId); } + + markAmendmentRejectedAndDeleted(firstLog.getAmendmentId(), userActionId); return; } @@ -197,6 +221,18 @@ public class PecMailDao { }); } + private void markAmendmentRejectedAndDeleted(Long amendmentId, Long userActionId) { + if (amendmentId == null) { + return; + } + applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId).ifPresent(amendment -> { + amendment.setStatus(ApplicationAmendmentRequestEnum.REJECTED.getValue()); + amendment.setIsDeleted(true); + applicationAmendmentRequestRepository.save(amendment); + log.info("Set amendment id={} to REJECTED and is_deleted=true after amendment email rejected (userActionId={})", amendmentId, userActionId); + }); + } + private static LocalDateTime parseLocalDateTimeFromAudit(Object value) { if (value == null) { return null; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java index eeee1100..13a6d8c4 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java @@ -7,8 +7,8 @@ public enum ApplicationAmendmentRequestEnum { RESPONSE_RECEIVED("RESPONSE_RECEIVED"), CLOSE("CLOSE"), EXPIRED("EXPIRED"), - /** Amendment PEC email was rejected; only instructor can update until status is set back to AWAITING. */ - DRAFT("DRAFT"); + /** Special amendment PEC email was rejected; amendment status set to REJECTED. */ + REJECTED("REJECTED"); private String value; 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 7f005f1f..8ce255b6 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 @@ -3205,4 +3205,8 @@ + + + + diff --git a/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql b/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql new file mode 100644 index 00000000..03cd457d --- /dev/null +++ b/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql @@ -0,0 +1,7 @@ +UPDATE gepafin_schema.system_email_template +SET subject='Comunicazione esito valutazione tecnica ed economico-finanziaria– Avviso {{call_name}} ' +WHERE email_scenario='SPECIAL_APPLICATION_AMENDMENT_REQUESTED'; + +UPDATE gepafin_schema.system_email_template +SET subject='Comunicazione esito valutazione tecnica ed economico-finanziaria– Avviso {{call_name}} ' +WHERE email_scenario='SPECIAL_APPLICATION_AMENDMENT_REQUESTED_BLUE_TONGUE'; \ No newline at end of file