From 5e3b0025d9c9b1c93d9d103683d268276c13d64a Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 18:02:43 +0530 Subject: [PATCH 1/8] Done ticket GEPAFINBE-216 Handled error for appointment creation failed, now returning the error description getting from third party API. --- .../constants/GepafinConstant.java | 4 ++- .../tendermanagement/dao/AppointmentDao.java | 29 +++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 7e165dc3..5ecfa9b5 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -544,7 +544,9 @@ public class GepafinConstant { 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/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index cb83406e..43c8cfdc 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -758,12 +758,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; From 5a055923300906f33410adf8dcdf14e0ecdc05d5 Mon Sep 17 00:00:00 2001 From: Piyush Date: Tue, 13 May 2025 18:18:46 +0530 Subject: [PATCH 2/8] Fixed Issue with Resend Email API --- .../tendermanagement/dao/EmailDao.java | 97 ++++++++++++++++++- .../ApplicationEvaluationRepository.java | 5 + .../repositories/EmailLogRepository.java | 7 ++ 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java index 6e46d475..9b99facb 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,90 @@ 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 (EmailSendResponse response : responses) { + if (scenario.equals(response.getEmailScenario().getValue())) { + response.setIsEmailSend(true); + 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/repositories/ApplicationEvaluationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java index 9019aad4..a231d3c6 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java @@ -76,5 +76,10 @@ public interface ApplicationEvaluationRepository extends JpaRepository { List findByUserActionIdAndEmailServiceType( Long userActionId, String emailServiceType); + EmailLogEntity findTopByUserActionIdAndEmailServiceTypeAndSendStatusOrderByIdDesc( + Long userActionId, + String emailServiceType, + String sendStatus + ); + + } From 43ff10e7b685c53d3b00b05f0849e1a2c540e3fd Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 19:39:11 +0530 Subject: [PATCH 3/8] Updated code for maximum retries on login to odessa. --- .../tendermanagement/dao/AppointmentDao.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 43c8cfdc..23f9784d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -176,6 +176,11 @@ public class AppointmentDao { } private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { + + int maxRetries = 3; + int attempt = 0; + boolean success = false; + while (attempt < maxRetries && !success) { 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(); @@ -195,15 +200,16 @@ public class AppointmentDao { 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) { - logForbiddenError(); + } catch (FeignException.Forbidden forbiddenException) { + attempt++; + log.error("Failed to login to odessa due to some error"); // Extract raw response body String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response @@ -239,15 +245,17 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - - // Regenerate the token and retry - loginToOdessa(hub, application); - } - catch (Exception e) { + if (attempt >= maxRetries) { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); + } else { + 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; + } + return null; } private void startAsyncNdgProcessing(Long applicationId) { From b137c9b3ec0946166955517dc482238ee674a375 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 19:48:48 +0530 Subject: [PATCH 4/8] Updated code for retry authentication for login to odessa. --- .../tendermanagement/dao/AppointmentDao.java | 132 ++++++++++-------- 1 file changed, 70 insertions(+), 62 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 23f9784d..079addee 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -430,77 +430,85 @@ 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" + int maxRetries = 3; + int attempt = 0; + boolean success = false; + while (attempt < maxRetries && !success) { try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(responseBody); - JsonNode errorsNode = rootNode.path("errors"); + //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); - 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)); - } + // 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); - // 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)); + // 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) { + attempt++; + 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 (IOException e) { - log.error("Error parsing JSON response: {}", e.getMessage()); + if (attempt >= maxRetries) { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); + } else { + 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); } - - // 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; } From 42fd20adc7758b285126786aa0e0963488974a8a Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 20:09:12 +0530 Subject: [PATCH 5/8] Updated code fix. --- .../tendermanagement/dao/AppointmentDao.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 079addee..5cfa0fe3 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -208,7 +208,6 @@ public class AppointmentDao { } throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); } catch (FeignException.Forbidden forbiddenException) { - attempt++; log.error("Failed to login to odessa due to some error"); // Extract raw response body @@ -245,14 +244,16 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt >= maxRetries) { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); + if (attempt + 1 < maxRetries) { + regenerateTokenAndSave(hub); } else { - loginToOdessa(hub, application); + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); + } finally { + attempt++; } } return null; @@ -430,6 +431,7 @@ public class AppointmentDao { } private HubEntity authenticateAndSaveToken(HubEntity hub) { + int maxRetries = 3; int attempt = 0; boolean success = false; @@ -467,7 +469,6 @@ public class AppointmentDao { // Handle non-OK response throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); } catch (FeignException.Forbidden forbiddenException) { - attempt++; log.error("Failed to login to odessa due to some error occurred."); // Extract raw response body @@ -500,14 +501,16 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt >= maxRetries) { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); - } else { + if (attempt + 1 < maxRetries) { regenerateTokenAndSave(hub); + } else { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); + } finally { + attempt++; } } return null; From a836864faceaa34e95e0d6338703797dbf192d9e Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 20:19:43 +0530 Subject: [PATCH 6/8] Code Fix. --- .../tendermanagement/dao/AppointmentDao.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 5cfa0fe3..609ab87d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -181,6 +181,7 @@ public class AppointmentDao { 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(); @@ -244,16 +245,9 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt + 1 < maxRetries) { - regenerateTokenAndSave(hub); - } else { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); - } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); - } finally { - attempt++; } } return null; @@ -436,6 +430,7 @@ public class AppointmentDao { 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(); @@ -501,16 +496,9 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt + 1 < maxRetries) { - regenerateTokenAndSave(hub); - } else { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); - } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); - } finally { - attempt++; } } return null; From 637aec5211a49ee73399260d6e30ad1b133b797f Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 14 May 2025 11:36:35 +0530 Subject: [PATCH 7/8] Done ticket GEPAFINBE-217 --- .../constants/GepafinConstant.java | 2 +- .../dao/ApplicationAmendmentRequestDao.java | 4 +- .../tendermanagement/dao/ApplicationDao.java | 82 +++++++++++++++++++ .../enums/UserActionContextEnum.java | 1 + .../ApplicationEvaluationRepository.java | 5 ++ .../repositories/ApplicationRepository.java | 3 + .../AssignedApplicationsRepository.java | 4 + .../service/ApplicationService.java | 2 + .../service/impl/ApplicationServiceImpl.java | 7 +- .../web/rest/api/ApplicationApi.java | 14 ++++ .../api/impl/ApplicationApiController.java | 11 +++ src/main/resources/message_en.properties | 4 +- src/main/resources/message_it.properties | 8 +- 13 files changed, 139 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index d0fb0136..d26d3927 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -541,7 +541,7 @@ 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"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index a0d0ff7f..cd482625 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -1082,12 +1082,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()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 2492e8b0..9dfba4b0 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2170,6 +2170,88 @@ 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()); + validateCallEndDate(applicationEntity); + + assignedApplicationsRepository.findByApplicationIdAndStatusAndIsDeletedFalse(applicationEntity.getId(), AssignedApplicationEnum.CLOSE.getValue()) + .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); + + return getApplicationResponse(applicationEntity); + } + private ApplicationEntity fetchRejectedApplication(Long applicationId) { + return applicationRepository.findByIdAndStatusAndIsDeletedFalse(applicationId, ApplicationStatusTypeEnum.REJECTED.getValue()); + } + private void validateCallEndDate(ApplicationEntity applicationEntity) { + checkCallEndDate(applicationEntity.getCall()); + log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); + } + + private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { + applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse(assignedApp.getId(), ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()) + .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/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/repositories/ApplicationEvaluationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java index 9019aad4..306ad3a5 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java @@ -76,5 +76,10 @@ public interface ApplicationEvaluationRepository extends JpaRepository findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse( + Long assignedApplicationId, + String status + ); + } 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/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/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/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/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/message_en.properties b/src/main/resources/message_en.properties index b09c8d62..aa8d0ad4 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -403,4 +403,6 @@ 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. \ No newline at end of file +resend.email.sent.failed.msg = Failed to resend the email. + +application.readmit.success=Application has been readmitted successfully. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index faafb940..b9a8e2db 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,9 +389,11 @@ 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. \ No newline at end of file +resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail. + +application.readmit.success=L'applicazione è stata riammessa con successo. From 1de7d672d0bfe22cdeb97256564482512353d81b Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 14 May 2025 13:06:14 +0530 Subject: [PATCH 8/8] Appointment error handling check. --- .../tendermanagement/dao/AppointmentDao.java | 428 ++++++++++++------ 1 file changed, 277 insertions(+), 151 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 609ab87d..617c9dff 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,15 +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; - boolean success = false; - while (attempt < maxRetries && !success) { + 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); @@ -195,13 +371,11 @@ 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()); 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."); @@ -209,48 +383,51 @@ 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 some error"); + log.error("Failed to login to odessa due to forbidden error."); - // Extract raw response body - String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + CheckPasswordExpiredOrErrorInResponse(application, forbiddenException); + } catch (Exception e) { + log.error("Failed to authenticate user on Odessa (Attempt {}): {}", attempt, e.getMessage(), e); + } + } + throw new RuntimeException("Max retries exceeded. Failed to login to Odessa."); + } + private void CheckPasswordExpiredOrErrorInResponse(ApplicationEntity application, FeignException.Forbidden forbiddenException) { - // Parse JSON to check for "PasswordExpired" - try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(responseBody); - JsonNode errorsNode = rootNode.path("errors"); + String responseBody = forbiddenException.contentUTF8(); - 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)); - } + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(responseBody); + JsonNode errorsNode = rootNode.path("errors"); - // 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)); - } + 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)); + } + + 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()); } - } catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); - throw new RuntimeException("Authentication failed on Odessa. try again", e); } + } catch (IOException e) { + log.error("Error parsing JSON response: {}", e.getMessage()); } - return null; } private void startAsyncNdgProcessing(Long applicationId) { @@ -299,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); @@ -345,10 +522,11 @@ public class AppointmentDao { application.setStatus(ApplicationStatusTypeEnum.NDG.getValue()); applicationRepository.save(application); companyRepository.save(company); - ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); + ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation( + application.getApplicationEvaluationId()); Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); 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; } @@ -398,7 +576,7 @@ public class AppointmentDao { ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); 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()); } @@ -416,7 +594,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); @@ -424,86 +602,6 @@ public class AppointmentDao { } } - 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 AppointmentLoginResponse retrieveNdgByVatNumber(String vatNumber, String authorizationToken, HubEntity hub, ApplicationEntity application) { try { @@ -517,7 +615,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 +623,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 +639,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 +809,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 +854,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); } } @@ -819,20 +917,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); @@ -893,13 +991,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(); @@ -919,11 +1044,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 { @@ -939,7 +1065,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); @@ -980,8 +1106,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));