From 3410f6b45fe8d82ca34d766928baf313960a949f Mon Sep 17 00:00:00 2001 From: rajesh Date: Fri, 13 Mar 2026 20:26:04 +0530 Subject: [PATCH 1/3] Handled rejected email rollback cases --- .../dao/ApplicationAmendmentRequestDao.java | 31 ++++- .../tendermanagement/dao/PecMailDao.java | 120 ++++++++++++++++++ .../ApplicationAmendmentRequestEnum.java | 4 +- .../VersionHistoryRepository.java | 2 + 4 files changed, 152 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 45b867b2..0c12eb8e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -786,6 +786,10 @@ 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)); @@ -1278,16 +1282,35 @@ public class ApplicationAmendmentRequestDao { log.info("Updating application amendment with status: {}", id); ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); - if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { + + 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))) { log.info("Updating amendment ID {} status from {} to {}", id, existingApplicationAmendment.getStatus(), statusTypeEnum); existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue()); existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); applicationAmendmentRequestRepository.save(existingApplicationAmendment); - - /** 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(oldApplicationAmendmentEntity).newData(existingApplicationAmendment).build()); } - ApplicationAmendmentRequestResponse response = convertEntityToResponse(existingApplicationAmendment,false); + + ApplicationAmendmentRequestResponse response = convertEntityToResponse(existingApplicationAmendment, false); log.info("Amendment status updated successfully: {}", response); return response; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java index fcaecbcc..d25e1507 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/PecMailDao.java @@ -6,13 +6,22 @@ import lombok.extern.log4j.Log4j2; 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.AssignedApplicationEnum; +import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.StatusTypeEnum; import net.gepafin.tendermanagement.model.response.EmailLogResponse; import net.gepafin.tendermanagement.model.response.PecEmailLogResponse; import net.gepafin.tendermanagement.model.response.PecMailResponse; +import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum; +import net.gepafin.tendermanagement.repositories.ApplicationAmendmentRequestRepository; +import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository; +import net.gepafin.tendermanagement.repositories.ApplicationRepository; +import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository; import net.gepafin.tendermanagement.repositories.EmailLogRepository; import net.gepafin.tendermanagement.repositories.UserActionsRepository; +import net.gepafin.tendermanagement.repositories.VersionHistoryRepository; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.util.DateTimeUtil; @@ -28,6 +37,8 @@ import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Optional; @Component @Log4j2 @@ -51,6 +62,22 @@ public class PecMailDao { @Autowired private ApplicationService applicationService; + @Autowired + private ApplicationRepository applicationRepository; + + @Autowired + private ApplicationEvaluationRepository applicationEvaluationRepository; + + @Autowired + private AssignedApplicationsRepository assignedApplicationsRepository; + + @Autowired + private VersionHistoryRepository versionHistoryRepository; + + @Autowired + private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; + + private static final String TABLE_APPLICATION = "APPLICATION"; public List sendPecMail(HttpServletRequest request, List userActionIds) { @@ -86,11 +113,104 @@ public class PecMailDao { } emailLogRepository.saveAll(emailLogs); EmailLogEntity firstLog = emailLogs.get(0); + + rollbackDomainChangesForRejectedEmail(firstLog, userActionId); + ApplicationEntity applicationEntity = applicationService.validateApplication(firstLog.getApplicationId()); String callName = applicationEntity.getCall().getName(); return createPecMailResponse(firstLog.getUserAction().getId(), firstLog, callName); } + /** + * Rolls back domain changes using version history (audit) for the user action that triggered the email. + * Restores application, application_evaluation, and assigned_applications from oldData in version history. + */ + private void rollbackDomainChangesForRejectedEmail(EmailLogEntity firstLog, Long userActionId) { + if (firstLog == null || firstLog.getApplicationId() == null || firstLog.getEmailType() == null || userActionId == null) { + return; + } + + 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); + }); + } + return; + } + + // Only rollback for the three evaluation-outcome email scenarios + if (!EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue().equals(scenario) + && !EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue().equals(scenario) + && !EmailScenarioTypeEnum.APPLICATION_ADMISSIBLE.getValue().equals(scenario)) { + return; + } + + List appHistory = versionHistoryRepository.findVersionHistoryByUserActionIdAndTableName(userActionId, TABLE_APPLICATION); + Optional applicationVersion = appHistory.stream() + .filter(v -> applicationId.equals(v.getRecordId()) && v.getOldData() != null && !v.getOldData().isEmpty()) + .findFirst(); + + ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); + 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); + } + Object dateRejectedObj = oldDataMap.get("dateRejected"); + applicationEntity.setDateRejected(parseLocalDateTimeFromAudit(dateRejectedObj)); + applicationRepository.save(applicationEntity); + log.info("Rolled back application id={} from version history (userActionId={})", applicationId, userActionId); + } + } else { + log.warn("No APPLICATION version history with oldData found for userActionId={}, applicationId={}; skipping application rollback", userActionId, applicationId); + } + + // Only set application_evaluation and assigned_applications to OPEN for REJECTED and TECHNICAL_EVALUATION_REJECTED (not for ADMISSIBLE) + boolean reopenEvaluationAndAssigned = EmailScenarioTypeEnum.APPLICATION_TECHNICAL_EVALUATION_REJECTED.getValue().equals(scenario) + || EmailScenarioTypeEnum.APPLICATION_REJECTED.getValue().equals(scenario); + if (!reopenEvaluationAndAssigned) { + return; + } + + applicationEvaluationRepository.findByApplicationIdAndIsDeletedFalse(applicationId).ifPresent(evaluation -> { + evaluation.setStatus(ApplicationEvaluationStatusTypeEnum.OPEN.getValue()); + evaluation.setClosingDate(null); + evaluation.setActiveDays(null); + applicationEvaluationRepository.save(evaluation); + log.info("Set application_evaluation id={} to OPEN (userActionId={})", evaluation.getId(), userActionId); + }); + + assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationId).ifPresent(assigned -> { + assigned.setStatus(AssignedApplicationEnum.OPEN.getValue()); + assignedApplicationsRepository.save(assigned); + log.info("Set assigned_applications id={} to OPEN (userActionId={})", assigned.getId(), userActionId); + }); + } + + private static LocalDateTime parseLocalDateTimeFromAudit(Object value) { + if (value == null) { + return null; + } + if (value instanceof String str && !str.isEmpty()) { + try { + return DateTimeUtil.parseStringToLocalDateTime(str); + } catch (Exception e) { + return null; + } + } + return null; + } + private List getEmailLogEntities(HttpServletRequest request, Long userActionId) { UserActionEntity userActionEntity = userActionsRepository.findUserActionByIdAndIsDeletedFalse(userActionId); if (userActionEntity == null) { diff --git a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java index d25ef71d..eeee1100 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationAmendmentRequestEnum.java @@ -6,7 +6,9 @@ public enum ApplicationAmendmentRequestEnum { AWAITING("AWAITING"), RESPONSE_RECEIVED("RESPONSE_RECEIVED"), CLOSE("CLOSE"), - EXPIRED("EXPIRED"); + EXPIRED("EXPIRED"), + /** Amendment PEC email was rejected; only instructor can update until status is set back to AWAITING. */ + DRAFT("DRAFT"); private String value; diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java index 853bb945..782a2cc6 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/VersionHistoryRepository.java @@ -13,4 +13,6 @@ public interface VersionHistoryRepository extends JpaRepository findVersionHistoryByUserActionIdAndUserIdNull(Long id); List findVersionHistoryByUserActionId(Long id); + + List findVersionHistoryByUserActionIdAndTableName(Long userActionId, String tableName); } From 94c86ebacd2398b0e210d4add4fe73f639f186d0 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 16 Mar 2026 16:38:53 +0530 Subject: [PATCH 2/3] 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 From d0b05aae1129aaf124a3752e806f7751cafb88a7 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 16 Mar 2026 20:07:27 +0530 Subject: [PATCH 3/3] Updated code --- src/main/resources/db/changelog/db.changelog-1.0.0.xml | 4 ---- ..._system_email_template_special_amendment_16_03_2026.sql | 7 ------- 2 files changed, 11 deletions(-) delete mode 100644 src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql 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 8ce255b6..7f005f1f 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,8 +3205,4 @@ - - - - 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 deleted file mode 100644 index 03cd457d..00000000 --- a/src/main/resources/db/dump/update_system_email_template_special_amendment_16_03_2026.sql +++ /dev/null @@ -1,7 +0,0 @@ -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