Merge pull request #291 from Kitzanos/develop

Sync Master with Develop (21/05/2025)
This commit is contained in:
Antonio Manca
2025-05-21 14:16:29 +02:00
committed by GitHub
71 changed files with 1687 additions and 303 deletions

View File

@@ -537,7 +537,20 @@ public class GepafinConstant {
public static final String APPLICATION_STATUS="applicationStatus"; public static final String APPLICATION_STATUS="applicationStatus";
public static final String RINALDO_EMAIL = "rinaldo.bonazzo@bflows.net"; public static final String RINALDO_EMAIL = "rinaldo.bonazzo@bflows.net";
public static final String RESEND_EMAIL_SENT_SUCCESS_MSG = "resend.email.sent.success.msg";
public static final String RESEND_EMAIL_SENT_FAILED_MSG = "resend.email.sent.failed.msg";
public static final String REMINDER_EMAIL_FAILED_MSG = "reminder.email.sent.failed.msg";
public static final String READMIT_APPLICATION_SUCCESS = "application.readmit.success"; public static final String READMIT_APPLICATION_SUCCESS = "application.readmit.success";
public static final String NO_EMAIL_LOG_FOUND = "no.email.log.msg";
public static final String USER_ACTION_ID_NOT_FOUND = "user.action.id.not.found";
public static final String CAUSE_STRING = "cause" ;
public static final String ERROR_DESCRIPTION_STRING = "errorDescription" ;
public static final String ERROR_STRING = "errors";
} }

View File

@@ -1,5 +1,6 @@
package net.gepafin.tendermanagement.dao; package net.gepafin.tendermanagement.dao;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
@@ -26,6 +27,7 @@ import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundExceptio
import net.gepafin.tendermanagement.web.rest.api.errors.Status; import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -140,6 +142,12 @@ public class ApplicationAmendmentRequestDao {
@Autowired @Autowired
private ApplicationDao applicationDao; private ApplicationDao applicationDao;
@Autowired
private EmailLogRepository emailLogRepository;
@Autowired
private EmailDao emailDao;
public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(Long applicationEvaluationId) { public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(Long applicationEvaluationId) {
log.info("Fetching the application data for the Amendment process {}", applicationEvaluationId); log.info("Fetching the application data for the Amendment process {}", applicationEvaluationId);
ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(applicationEvaluationId); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(applicationEvaluationId);
@@ -300,6 +308,15 @@ public class ApplicationAmendmentRequestDao {
log.info("Application submitted successfully for amendment", applicationAmendmentRequestResponse); log.info("Application submitted successfully for amendment", applicationAmendmentRequestResponse);
if (Boolean.TRUE.equals(applicationAmendmentRequestResponse.getIsSendEmail())) { if (Boolean.TRUE.equals(applicationAmendmentRequestResponse.getIsSendEmail())) {
emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(applicationAmendmentRequestEntity); emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(applicationAmendmentRequestEntity);
EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request);
List<EmailSendResponse> responses = List.of(emailSendResponse);
if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){
saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity);
applicationAmendmentRequestResponse.setEmailSendResponse(responses);
}
else{
applicationAmendmentRequestResponse.setEmailSendResponse(Collections.emptyList());
}
} }
return applicationAmendmentRequestResponse; return applicationAmendmentRequestResponse;
} }
@@ -506,6 +523,7 @@ public class ApplicationAmendmentRequestDao {
Long hubId = applicationEntity.getHubId(); Long hubId = applicationEntity.getHubId();
HubEntity hubEntity = hubService.valdateHub(hubId); HubEntity hubEntity = hubService.valdateHub(hubId);
response.setEmailSendResponse(entity.getEmailSendResponse());
response.setId(entity.getId()); response.setId(entity.getId());
response.setApplicationId(entity.getApplicationId()); response.setApplicationId(entity.getApplicationId());
response.setApplicationEvaluationId(entity.getApplicationEvaluationEntity().getId()); response.setApplicationEvaluationId(entity.getApplicationEvaluationEntity().getId());
@@ -647,9 +665,9 @@ public class ApplicationAmendmentRequestDao {
public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(Long id) { public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(Long id) {
log.info("Fetching application amendment with ID: {}", id); log.info("Fetching application amendment with ID: {}", id);
ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id);
ApplicationAmendmentRequestResponse response = convertEntityToResponse(applicationAmendmentRequestEntity,true); ApplicationAmendmentRequestResponse response = convertEntityToResponse(applicationAmendmentRequestEntity,true);
log.info("Application Amendment fetched successfully by ID: {}", response); response.setEmailSendResponse(applicationAmendmentRequestEntity.getEmailSendResponse());
return response; return response;
} }
public List<GetAllAmendmentResponseBean> getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId) { public List<GetAllAmendmentResponseBean> getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId) {
@@ -1032,7 +1050,7 @@ public class ApplicationAmendmentRequestDao {
public ApplicationAmendmentRequestResponse closeAmendmentRequest(Long id, CloseAmendmentRequest closeAmendmentRequest) { public ApplicationAmendmentRequestResponse closeAmendmentRequest(Long id, CloseAmendmentRequest closeAmendmentRequest) {
log.info("Closing application amendement with ID: {}", id); log.info("Closing application amendement with ID: {}", id);
ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity existingApplicationAmendment = validatApplicationAmendmentRequestByStatus(id,ApplicationAmendmentRequestEnum.AWAITING.getValue());
//cloned entity for old data and versioning //cloned entity for old data and versioning
ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment);
List<ApplicationAmendmentRequestEntity> amendmentRequestList = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( List<ApplicationAmendmentRequestEntity> amendmentRequestList = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(
@@ -1042,17 +1060,18 @@ public class ApplicationAmendmentRequestDao {
// Check if this is the last amendment being closed // Check if this is the last amendment being closed
boolean isLastRemaining = amendmentRequestList.stream() boolean isLastRemaining = amendmentRequestList.stream()
.filter(amendment -> !amendment.getId().equals(id)) // Exclude the current amendment .filter(amendment -> !amendment.getId().equals(id)) // Exclude the current amendment
.allMatch(amendment -> amendment.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue())); .allMatch(amendment -> amendment.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue()) || amendment.getStatus().equals(ApplicationAmendmentRequestEnum.EXPIRED.getValue()));
if (isLastRemaining) {
log.info("The current amendment is the last remaining one to be closed.");
applicationAmendmentRequestDao.calculateEndDateAndSuspensionDays(existingApplicationAmendment.getApplicationEvaluationEntity());
}
setIfUpdated(existingApplicationAmendment::getInternalNote, existingApplicationAmendment::setInternalNote, closeAmendmentRequest.getInternalNote()); setIfUpdated(existingApplicationAmendment::getInternalNote, existingApplicationAmendment::setInternalNote, closeAmendmentRequest.getInternalNote());
setIfUpdated(existingApplicationAmendment::getStatus, existingApplicationAmendment::setStatus, ApplicationAmendmentRequestEnum.CLOSE.getValue()); setIfUpdated(existingApplicationAmendment::getStatus, existingApplicationAmendment::setStatus, ApplicationAmendmentRequestEnum.CLOSE.getValue());
existingApplicationAmendment.setClosingDate(LocalDateTime.now()); existingApplicationAmendment.setClosingDate(LocalDateTime.now());
ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment, oldApplicationAmendmentEntity, ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment, oldApplicationAmendmentEntity,
VersionActionTypeEnum.UPDATE); VersionActionTypeEnum.UPDATE);
if (isLastRemaining) {
log.info("The current amendment is the last remaining one to be closed.");
applicationAmendmentRequestDao.calculateEndDateAndSuspensionDaysOnExpirationOrClosing(existingApplicationAmendment.getApplicationEvaluationEntity());
}
ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false); ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false);
List<ApplicationAmendmentRequestEntity> amendmentRequests = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( List<ApplicationAmendmentRequestEntity> amendmentRequests = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(
@@ -1104,15 +1123,17 @@ public class ApplicationAmendmentRequestDao {
return response; return response;
} }
public ApplicationAmendmentRequestResponse extendResponseDays(Long id, Long newResponseDays) { public ApplicationAmendmentRequestResponse extendResponseDays(Long id, Long newResponseDays) {
ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validatApplicationAmendmentRequestByStatus(id,ApplicationAmendmentRequestEnum.EXPIRED.getValue());
if (newResponseDays != null && newResponseDays > 0) { if (newResponseDays != null && newResponseDays > 0) {
ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(applicationAmendmentRequestEntity); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(applicationAmendmentRequestEntity);
Long currentResponseDays = applicationAmendmentRequestEntity.getResponseDays() != null ? applicationAmendmentRequestEntity.getResponseDays() : 0L; Long currentResponseDays = applicationAmendmentRequestEntity.getResponseDays() != null ? applicationAmendmentRequestEntity.getResponseDays() : 0L;
applicationAmendmentRequestEntity.setResponseDays(currentResponseDays + newResponseDays); applicationAmendmentRequestEntity.setResponseDays(currentResponseDays + newResponseDays);
applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now().plusDays(applicationAmendmentRequestEntity.getResponseDays()))); applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now().plusDays(newResponseDays)));
applicationAmendmentRequestEntity.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue());
applicationAmendmentRequestEntity.getApplicationEvaluationEntity().setStatus(ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue());
applicationAmendmentRequestEntity.getApplicationEvaluationEntity().getAssignedApplicationsEntity().getApplication().setStatus(ApplicationStatusTypeEnum.SOCCORSO.getValue());
applicationAmendmentRequestRepository.save(applicationAmendmentRequestEntity); applicationAmendmentRequestRepository.save(applicationAmendmentRequestEntity);
/** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/
@@ -1168,12 +1189,13 @@ public class ApplicationAmendmentRequestDao {
return response; return response;
} }
public void sendReminderEmail(Long amendmentId) { public EmailReminderResponse sendReminderEmail(Long amendmentId) {
ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId) ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId)
.orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)));
Optional<ApplicationEvaluationEntity> entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId()); Optional<ApplicationEvaluationEntity> entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId());
EmailReminderResponse emailReminderResponse = new EmailReminderResponse();
if (entityOptional.isPresent()) { if (entityOptional.isPresent()) {
ApplicationEntity applicationEntity = applicationService.validateApplication(entityOptional.get().getApplicationId()); ApplicationEntity applicationEntity = applicationService.validateApplication(entityOptional.get().getApplicationId());
UserEntity beneficiaryUser = userService.validateUser(applicationEntity.getUserId()); UserEntity beneficiaryUser = userService.validateUser(applicationEntity.getUserId());
@@ -1186,10 +1208,20 @@ public class ApplicationAmendmentRequestDao {
EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(emailTemplate.getEmailScenario(), RecipientTypeEnum.USER, beneficiaryUser.getId(), email, EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(emailTemplate.getEmailScenario(), RecipientTypeEnum.USER, beneficiaryUser.getId(), email,
beneficiaryUser.getId(), applicationEntity.getId(), amendment.getId(), applicationEntity.getCall().getId()); beneficiaryUser.getId(), applicationEntity.getId(), amendment.getId(), applicationEntity.getCall().getId());
emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email), emailLogRequest); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email), emailLogRequest);
EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request);
List<EmailSendResponse> responses = List.of(emailSendResponse);
if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){
emailReminderResponse.setEmailSendResponse(responses);
saveEmailSendResponse(emailSendResponse, amendment);
}
else{
emailReminderResponse.setEmailSendResponse(Collections.emptyList());
}
} else { } else {
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.BENEFICIARY_EMAIL_NOT_FOUND_MSG)); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.BENEFICIARY_EMAIL_NOT_FOUND_MSG));
} }
} }
return emailReminderResponse;
} }
private String prepareSubject(SystemEmailTemplateResponse template, ApplicationAmendmentRequestEntity amendment, UserEntity beneficiary) { private String prepareSubject(SystemEmailTemplateResponse template, ApplicationAmendmentRequestEntity amendment, UserEntity beneficiary) {
@@ -1219,26 +1251,26 @@ public class ApplicationAmendmentRequestDao {
return Utils.replacePlaceholders(template.getHtmlContent(), bodyPlaceholders); return Utils.replacePlaceholders(template.getHtmlContent(), bodyPlaceholders);
} }
public ApplicationEvaluationEntity calculateEndDateAndSuspensionDays(ApplicationEvaluationEntity applicationEvaluationEntity){ // public ApplicationEvaluationEntity calculateEndDateAndSuspensionDays(ApplicationEvaluationEntity applicationEvaluationEntity){
LocalDateTime currentDate=DateTimeUtil.DateServerToUTC(LocalDateTime.now()); // LocalDateTime currentDate=DateTimeUtil.DateServerToUTC(LocalDateTime.now());
LocalDateTime endDate=currentDate.plusDays(applicationEvaluationEntity.getRemainingDays()); // LocalDateTime endDate=currentDate.plusDays(applicationEvaluationEntity.getRemainingDays());
Long suspendedDays = ChronoUnit.DAYS.between(applicationEvaluationEntity.getStopDateTime(), currentDate); // Long suspendedDays = ChronoUnit.DAYS.between(applicationEvaluationEntity.getStopDateTime(), currentDate);
//
ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); // ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(applicationEvaluationEntity);
applicationEvaluationEntity.setEndDate(endDate); // applicationEvaluationEntity.setEndDate(endDate);
if(applicationEvaluationEntity.getSuspendedDays() == null) { // if(applicationEvaluationEntity.getSuspendedDays() == null) {
applicationEvaluationEntity.setSuspendedDays(0L); // applicationEvaluationEntity.setSuspendedDays(0L);
} // }
applicationEvaluationEntity.setSuspendedDays(applicationEvaluationEntity.getSuspendedDays()+suspendedDays); // applicationEvaluationEntity.setSuspendedDays(applicationEvaluationEntity.getSuspendedDays()+suspendedDays);
ApplicationEvaluationEntity applicationEvaluation = applicationEvaluationRepository.save(applicationEvaluationEntity); // ApplicationEvaluationEntity applicationEvaluation = applicationEvaluationRepository.save(applicationEvaluationEntity);
//
/** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ // /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(applicationEvaluation).build()); // loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(applicationEvaluation).build());
//
return applicationEvaluation; // return applicationEvaluation;
//
//
} // }
private GetAllAmendmentResponseBean initializeGetAllBasicResponse(ApplicationAmendmentRequestEntity entity) { private GetAllAmendmentResponseBean initializeGetAllBasicResponse(ApplicationAmendmentRequestEntity entity) {
GetAllAmendmentResponseBean response = new GetAllAmendmentResponseBean(); GetAllAmendmentResponseBean response = new GetAllAmendmentResponseBean();
@@ -1539,8 +1571,103 @@ public class ApplicationAmendmentRequestDao {
applicationAmendmentRequestViewResponse.setExpirationDate(applicationAmendmentRequestView.getExpirationDate()); applicationAmendmentRequestViewResponse.setExpirationDate(applicationAmendmentRequestView.getExpirationDate());
applicationAmendmentRequestViewResponse.setAssigendUserName(applicationAmendmentRequestView.getAssigendUserName()); applicationAmendmentRequestViewResponse.setAssigendUserName(applicationAmendmentRequestView.getAssigendUserName());
applicationAmendmentRequestViewResponse.setStatus(applicationAmendmentRequestView.getStatus()); applicationAmendmentRequestViewResponse.setStatus(applicationAmendmentRequestView.getStatus());
applicationAmendmentRequestViewResponse.setEmailSendResponse(applicationAmendmentRequestView.getEmailSendResponse());
return applicationAmendmentRequestViewResponse; return applicationAmendmentRequestViewResponse;
} }
public ApplicationEvaluationEntity calculateEndDateAndSuspensionDaysOnExpirationOrClosing
(ApplicationEvaluationEntity applicationEvaluationEntity) {
// Fetch all linked amendments
List<ApplicationAmendmentRequestEntity> amendments =
applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(applicationEvaluationEntity.getId());
// Recalculate suspension
long suspendedDays = calculateSuspendedDays(amendments);
// Update end date and save
ApplicationEvaluationEntity oldEntity = Utils.getClonedEntityForData(applicationEvaluationEntity);
HubEntity hub = hubService.valdateHub(applicationEvaluationEntity.getAssignedApplicationsEntity().getApplication().getHubId());
Long initialDays = (hub != null) ? hub.getEvaluationExpirationDays() : 30L;
LocalDateTime endDate = applicationEvaluationEntity.getStartDate().plusDays(suspendedDays+initialDays);
applicationEvaluationEntity.setEndDate(endDate);
applicationEvaluationEntity.setSuspendedDays(suspendedDays);
ApplicationEvaluationEntity updated = applicationEvaluationRepository.save(applicationEvaluationEntity);
loggingUtil.addVersionHistory(VersionHistoryRequest.builder()
.request(request)
.actionType(VersionActionTypeEnum.UPDATE)
.oldData(oldEntity)
.newData(updated)
.build());
return updated;
}
public long calculateSuspendedDays(List<ApplicationAmendmentRequestEntity> amendments) {
List<Pair<LocalDateTime, LocalDateTime>> periods = amendments.stream()
.filter(amendmentRequest -> amendmentRequest.getStartDate() != null)
.map(amendmentRequest -> {
LocalDateTime start = amendmentRequest.getStartDate();
LocalDateTime end;
String status = amendmentRequest.getStatus();
if (Boolean.TRUE.equals(ApplicationAmendmentRequestEnum.CLOSE.getValue().equals(status)) && amendmentRequest.getClosingDate() != null) {
end = amendmentRequest.getClosingDate();
} else if (Boolean.TRUE.equals(ApplicationAmendmentRequestEnum.EXPIRED.getValue().equals(status)) && amendmentRequest.getEndDate() != null) {
end = amendmentRequest.getStartDate().plusDays(amendmentRequest.getResponseDays());
}else {
end= amendmentRequest.getEndDate();
}
return Pair.of(start, end);
})
.filter(Objects::nonNull)
.sorted(Comparator.comparing(Pair::getLeft))
.collect(Collectors.toList());
long totalDays = 0;
LocalDateTime currentStart = null;
LocalDateTime currentEnd = null;
for (Pair<LocalDateTime, LocalDateTime> period : periods) {
if (currentStart == null) {
currentStart = period.getLeft();
currentEnd = period.getRight();
} else if (!period.getLeft().isAfter(currentEnd)) {
// Merge overlapping/touching periods
currentEnd = currentEnd.isAfter(period.getRight()) ? currentEnd : period.getRight();
} else {
// Non-overlapping: count previous period
totalDays += ChronoUnit.DAYS.between(currentStart.toLocalDate(), currentEnd.toLocalDate());
currentStart = period.getLeft();
currentEnd = period.getRight();
}
}
if (currentStart != null && currentEnd != null) {
totalDays += ChronoUnit.DAYS.between(currentStart.toLocalDate(), currentEnd.toLocalDate());
}
return totalDays;
}
public ApplicationAmendmentRequestEntity validatApplicationAmendmentRequestByStatus(Long id,String status) {
ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalseAndStatus(id, status);
if (applicationAmendmentRequestEntity == null) {
throw new ResourceNotFoundException(Status.NOT_FOUND,
Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG));
}
return applicationAmendmentRequestEntity;
}
private void saveEmailSendResponse(EmailSendResponse newResponses, ApplicationAmendmentRequestEntity amendment) {
List<EmailSendResponse> mergedResponses = Utils.mergeEmailSendResponses(amendment.getEmailSendResponse(), newResponses);
amendment.setEmailSendResponse(mergedResponses);
applicationAmendmentRequestRepository.save(amendment);
}
} }

View File

@@ -1109,7 +1109,7 @@ public class ApplicationDao {
if (userEntity.getBeneficiary() != null) { if (userEntity.getBeneficiary() != null) {
emailLogRequest.setRecipientType(RecipientTypeEnum.BENEFICIARY); emailLogRequest.setRecipientType(RecipientTypeEnum.BENEFICIARY);
email = userEntity.getBeneficiary().getEmail(); email = userEntity.getBeneficiary().getEmail();
emailLogRequest.setUserId(userEntity.getBeneficiary().getId()); emailLogRequest.setRecipientId(userEntity.getBeneficiary().getId());
} }
emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email),emailLogRequest); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email),emailLogRequest);
List<String> recipientEmails = new ArrayList<>(); List<String> recipientEmails = new ArrayList<>();
@@ -2211,4 +2211,40 @@ public class ApplicationDao {
} }
public void sendApplicationSubmissionFailureEmail(EmailLogRequest emailLogRequest){
Long callId = emailLogRequest.getCallId();
CallEntity call = callService.validateCall(callId);
HubEntity hub = call.getHub();
Long userId = emailLogRequest.getUserId();
UserEntity user = userService.validateUser(userId);
Long applicationId = emailLogRequest.getApplicatioId();
ApplicationEntity applicationEntity = validateApplication(applicationId);
CompanyEntity company = companyService.validateCompany(applicationEntity.getCompanyId());
SystemEmailTemplateResponse systemEmailTemplateResponse = systemEmailTemplatesService
.retrieveTemplateByTypeAndCall(SystemEmailTemplatesEntityTypeEnum.APPLICATION_SUBMISSION_FAILURE_NOTIFICATION,
hub, null);
Map<String, String> subjectPlaceholders = new HashMap<>();
subjectPlaceholders.put("{{call_name}}", call.getName());
Map<String, String> bodyPlaceholders = new HashMap<>();
bodyPlaceholders.put("{{scenario}}",emailLogRequest.getEmailType().getValue());
bodyPlaceholders.put("{{call_name}}", call.getName());
bodyPlaceholders.put("{{application_id}}", applicationEntity.getId().toString());
bodyPlaceholders.put("{{company_name}}", company.getCompanyName());
bodyPlaceholders.put("{{protocol_number}}", applicationEntity.getProtocol().getProtocolNumber().toString());
bodyPlaceholders.put("{{user_action_id}}",emailLogRequest.getUserActionId().toString());
String subject = Utils.replacePlaceholders(systemEmailTemplateResponse.getSubject(), subjectPlaceholders);
String body = Utils.replacePlaceholders(systemEmailTemplateResponse.getHtmlContent(), bodyPlaceholders);
emailLogRequest=emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(),RecipientTypeEnum.PROPERTIES,null,user.getEmail(),user.getId(),applicationEntity.getId(),null,callId);
emailLogRequest.setRecipientEmails(GepafinConstant.RINALDO_EMAIL);
emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(GepafinConstant.RINALDO_EMAIL),emailLogRequest);
}
} }

View File

@@ -143,6 +143,9 @@ public class ApplicationEvaluationDao {
@Autowired @Autowired
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
@Autowired
private EmailDao emailDao;
private ApplicationEvaluationEntity convertToEntity(UserEntity user, ApplicationEvaluationRequest req, Long assignedApplciationId) { private ApplicationEvaluationEntity convertToEntity(UserEntity user, ApplicationEvaluationRequest req, Long assignedApplciationId) {
@@ -311,7 +314,6 @@ public class ApplicationEvaluationDao {
response.setUpdatedDate(entity.getUpdatedDate()); response.setUpdatedDate(entity.getUpdatedDate());
response.setNumberOfCheck(entity.getAssignedApplicationsEntity().getApplication().getCall().getNumberOfCheck()); response.setNumberOfCheck(entity.getAssignedApplicationsEntity().getApplication().getCall().getNumberOfCheck());
response.setAppointmentTemplateId(entity.getAssignedApplicationsEntity().getApplication().getCall().getAppointmentTemplateId()); response.setAppointmentTemplateId(entity.getAssignedApplicationsEntity().getApplication().getCall().getAppointmentTemplateId());
} }
@@ -701,7 +703,11 @@ public class ApplicationEvaluationDao {
/** This code is responsible for adding a version history log for the "Update Application" operation. **/ /** This code is responsible for adding a version history log for the "Update Application" operation. **/
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(actionType).oldData(oldApplication).newData(application).build()); loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(actionType).oldData(oldApplication).newData(application).build());
Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_CREATION); // Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_CREATION);
Map<String, String> placeHolders = new HashMap<>();
placeHolders.put("{{call_name}}", application.getCall().getName());
placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber()));
notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.EVALUATION_CREATION); notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.EVALUATION_CREATION);
notificationDao.sendNotificationToInstructor(placeHolders,entity,NotificationTypeEnum.EVALUATION_CREATION); notificationDao.sendNotificationToInstructor(placeHolders,entity,NotificationTypeEnum.EVALUATION_CREATION);
@@ -1124,10 +1130,14 @@ public class ApplicationEvaluationDao {
} else { } else {
entityOptional = applicationEvaluationRepository.findFirstByIsDeletedFalseOrderByCreatedDateDesc(); entityOptional = applicationEvaluationRepository.findFirstByIsDeletedFalseOrderByCreatedDateDesc();
} }
return entityOptional.map(this::convertToResponse)
.orElseGet(() -> { if (entityOptional.isEmpty()) {
return getEvaluationResponseByApplicationid(user, applicationId, assignedApplicationId); return null;
}); }
ApplicationEvaluationEntity entity = entityOptional.get();
ApplicationEvaluationResponse applicationEvaluationResponse = convertToResponse(entity);
applicationEvaluationResponse.setEmailSendResponse(entity.getEmailSendResponse());
return applicationEvaluationResponse;
} }
private List<EvaluationDocumentRequest> prepareEvaluationDocumentBeanList(ApplicationEvaluationEntity entity) { private List<EvaluationDocumentRequest> prepareEvaluationDocumentBeanList(ApplicationEvaluationEntity entity) {
List<EvaluationDocumentRequest> docRequest = new ArrayList<>(); List<EvaluationDocumentRequest> docRequest = new ArrayList<>();
@@ -1876,7 +1886,7 @@ public class ApplicationEvaluationDao {
assignedApplicationsEntity.getId()); assignedApplicationsEntity.getId());
ApplicationEvaluationEntity entity; ApplicationEvaluationEntity entity;
EmailSendResponse emailSendResponse = new EmailSendResponse();
if (existingEntityOptional.isPresent()) { if (existingEntityOptional.isPresent()) {
ApplicationEvaluationEntity existingEntity = existingEntityOptional.get(); ApplicationEvaluationEntity existingEntity = existingEntityOptional.get();
// UserEntity userEntity = userService.validateUser(application.getUserId()); // UserEntity userEntity = userService.validateUser(application.getUserId());
@@ -1884,10 +1894,16 @@ public class ApplicationEvaluationDao {
ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(application); ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(application);
List<EmailSendResponse> responses = new ArrayList<>();
if(newStatus.equals(ApplicationStatusForEvaluation.ADMISSIBLE) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.APPOINTMENT.getValue()))){ if(newStatus.equals(ApplicationStatusForEvaluation.ADMISSIBLE) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.APPOINTMENT.getValue()))){
application.setStatus(newStatus.getValue()); application.setStatus(newStatus.getValue());
log.info("Status updated to ADMISSIBLE for applicationId: " + application.getId()); log.info("Status updated to ADMISSIBLE for applicationId: " + application.getId());
emailNotificationDao.sendAdmissibilityNotificationEmailForAdmissibleApplication(application); emailNotificationDao.sendAdmissibilityNotificationEmailForAdmissibleApplication(application);
emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request);
responses = List.of(emailSendResponse);
if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) {
saveEmailSendResponseToEvaluation(emailSendResponse, existingEntity);
}
} }
if(newStatus.equals(ApplicationStatusForEvaluation.TECHNICAL_EVALUATION) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))){ if(newStatus.equals(ApplicationStatusForEvaluation.TECHNICAL_EVALUATION) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))){
@@ -1934,27 +1950,48 @@ public class ApplicationEvaluationDao {
if (Boolean.TRUE.equals(statusType.equals((ApplicationStatusTypeEnum.APPROVED.getValue())))) { if (Boolean.TRUE.equals(statusType.equals((ApplicationStatusTypeEnum.APPROVED.getValue())))) {
application.setDateAccepted(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application.setDateAccepted(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
application = applicationRepository.save(application); application = applicationRepository.save(application);
// emailNotificationDao.sendAdmissibilityNotificationEmailForApprovedApplication(application); // emailNotificationDao.sendAdmissibilityNotificationEmailForApprovedApplication(application);
notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT);
} }
if (Boolean.TRUE.equals(statusType.equals((ApplicationStatusTypeEnum.REJECTED.getValue())))) { if (Boolean.TRUE.equals(statusType.equals((ApplicationStatusTypeEnum.REJECTED.getValue())))) {
application.setDateRejected(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application.setDateRejected(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
application = applicationRepository.save(application); application = applicationRepository.save(application);
emailNotificationDao.sendInadmissibilityEmailForRejectedApplication(application,existingEntity); emailNotificationDao.sendInadmissibilityEmailForRejectedApplication(application,existingEntity);
emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request);
responses = List.of(emailSendResponse);
if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) {
saveEmailSendResponseToEvaluation(emailSendResponse, existingEntity);
}
notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT);
} }
Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); Map<String, String> placeHolders = new HashMap<>();
placeHolders.put("{{call_name}}", application.getCall().getName());
placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber()));
notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.EVALUATION_RESULT); notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.EVALUATION_RESULT);
notificationDao.sendNotificationToInstructor(placeHolders,existingEntity,NotificationTypeEnum.EVALUATION_RESULT); notificationDao.sendNotificationToInstructor(placeHolders,existingEntity,NotificationTypeEnum.EVALUATION_RESULT);
return convertToResponse(entity); ApplicationEvaluationResponse response = convertToResponse(entity);
if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) {
response.setEmailSendResponse(responses);
}
return response;
} }
return null; return null;
} }
private void saveEmailSendResponseToEvaluation(EmailSendResponse newResponse, ApplicationEvaluationEntity evaluationEntity) {
List<EmailSendResponse> mergedResponses = Utils.mergeEmailSendResponses(
evaluationEntity.getEmailSendResponse(), newResponse
);
evaluationEntity.setEmailSendResponse(mergedResponses);
applicationEvaluationRepository.save(evaluationEntity);
}
public ApplicationEvaluationEntity validateApplicationEvaluationByApplicationId(Long applicationId) { public ApplicationEvaluationEntity validateApplicationEvaluationByApplicationId(Long applicationId) {
return applicationEvaluationRepository return applicationEvaluationRepository
.findByApplicationIdAndIsDeletedFalse(applicationId) .findByApplicationIdAndIsDeletedFalse(applicationId)
@@ -2006,6 +2043,7 @@ public class ApplicationEvaluationDao {
ApplicationEvaluationEntity entity = applicationEvaluationService.validateApplicationEvaluation(evaluationResponse.getId()); ApplicationEvaluationEntity entity = applicationEvaluationService.validateApplicationEvaluation(evaluationResponse.getId());
//Handling Application Evaluation form //Handling Application Evaluation form
EvaluationFormEntity evaluationFormEntity = evaluationFormService.validateEvaluationForm(evaluationFormId); EvaluationFormEntity evaluationFormEntity = evaluationFormService.validateEvaluationForm(evaluationFormId);
validateFormFields(applicationEvaluationFormRequestBean,evaluationFormEntity); validateFormFields(applicationEvaluationFormRequestBean,evaluationFormEntity);
@@ -2014,7 +2052,9 @@ public class ApplicationEvaluationDao {
validateFormFieldCustom(applicationEvaluationFormRequestBean.getFormFields(),entity,evaluationFormEntity); validateFormFieldCustom(applicationEvaluationFormRequestBean.getFormFields(),entity,evaluationFormEntity);
ApplicationEvaluationFormEntity applicationEvaluationFormEntity = getApplicationEvaluationFormOrCreate(evaluationFormEntity,entity); ApplicationEvaluationFormEntity applicationEvaluationFormEntity = getApplicationEvaluationFormOrCreate(evaluationFormEntity,entity);
createOrUpdateMultipleFormFields(applicationEvaluationFormRequestBean.getFormFields(), applicationEvaluationFormEntity, evaluationFormEntity); createOrUpdateMultipleFormFields(applicationEvaluationFormRequestBean.getFormFields(), applicationEvaluationFormEntity, evaluationFormEntity);
return processEvaluationForm(entity); ApplicationEvaluationFormResponse response = processEvaluationForm(entity);
response.setEmailSendResponse(evaluationResponse.getEmailSendResponse());
return response;
} }
private ApplicationEvaluationFormEntity getApplicationEvaluationFormOrCreate(EvaluationFormEntity evaluationFormEntity, ApplicationEvaluationEntity applicationEvaluationEntity) { private ApplicationEvaluationFormEntity getApplicationEvaluationFormOrCreate(EvaluationFormEntity evaluationFormEntity, ApplicationEvaluationEntity applicationEvaluationEntity) {
@@ -2259,6 +2299,7 @@ public class ApplicationEvaluationDao {
} }
response.setCompanyVatNumber(company.getVatNumber()); response.setCompanyVatNumber(company.getVatNumber());
response.setCompanyCodiceAteco(company.getCodiceAteco()); response.setCompanyCodiceAteco(company.getCodiceAteco());
response.setEmailSendResponse(evaluationEntity.getEmailSendResponse());
return response; return response;
} }

View File

@@ -1,7 +1,6 @@
package net.gepafin.tendermanagement.dao; package net.gepafin.tendermanagement.dao;
import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; 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.config.jwt.TokenProvider;
import net.gepafin.tendermanagement.constants.AppointmentApiConstant; import net.gepafin.tendermanagement.constants.AppointmentApiConstant;
import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestEntity;
import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.entities.ApplicationEntity;
import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity; import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity;
import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.CompanyEntity;
import net.gepafin.tendermanagement.entities.DocumentEntity; import net.gepafin.tendermanagement.entities.DocumentEntity;
import net.gepafin.tendermanagement.entities.HubEntity; import net.gepafin.tendermanagement.entities.HubEntity;
import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum;
import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum;
import net.gepafin.tendermanagement.enums.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.NotificationTypeEnum;
import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum;
import net.gepafin.tendermanagement.model.request.AppointmentCreationRequest; import net.gepafin.tendermanagement.model.request.AppointmentCreationRequest;
@@ -61,12 +62,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@@ -145,6 +141,15 @@ public class AppointmentDao {
@Autowired @Autowired
private AmazonS3Service amazonS3Service; private AmazonS3Service amazonS3Service;
@Autowired
private ApplicationDao applicationDao;
@Autowired
private ApplicationAmendmentRequestDao applicationAmendmentRequestDao;
@Autowired
private ApplicationEvaluationDao applicationEvaluationDao;
private final Map<Long, ExecutorService> executorMap = new ConcurrentHashMap<>(); private final Map<Long, ExecutorService> executorMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Long, ExecutorService> threadForDocumentMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Long, ExecutorService> threadForDocumentMap = new ConcurrentHashMap<>();
@@ -175,9 +180,182 @@ public class AppointmentDao {
return ndgResponse; 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<String, Object> body = Collections.emptyMap();
// ResponseEntity<Object> 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<String, Object> body = Collections.emptyMap();
// // Perform login API call
// ResponseEntity<Object> responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body);
//
// // Handle successful login
// if (responseLogin.getStatusCode() == HttpStatus.OK) {
// log.info("Login successful to odessa. Parsing response.");
// String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody());
// AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson);
//
// // Validate and save token
// if (parsedResponse.getTokenId() != null) {
// hub.setAppointmentAuthTokenId(parsedResponse.getTokenId());
// hub.setAreaCode(parsedResponse.getAreaCode());
// hubRepository.save(hub);
//
// log.info("Saved new authToken and areaCode for Hub.");
// success = true;
// return hub;
// } else {
// throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again.");
// }
// }
// // Handle non-OK response
// throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN));
// } catch (FeignException.Forbidden forbiddenException) {
// log.error("Failed to login to odessa due to some error occurred.");
//
// // Extract raw response body
// String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response
//
// // Parse JSON to check for "PasswordExpired"
// try {
// ObjectMapper objectMapper = new ObjectMapper();
// JsonNode rootNode = objectMapper.readTree(responseBody);
// JsonNode errorsNode = rootNode.path("errors");
//
// if (errorsNode.isArray()) {
// for (JsonNode error : errorsNode) {
// // Check the main errorCode
// if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) {
// throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA));
// }
//
// // Check inside "subErrors"
// JsonNode subErrorsNode = error.path("subErrors");
// if (subErrorsNode.isArray()) {
// for (JsonNode subError : subErrorsNode) {
// if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) {
// throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA));
// }
// }
// }
// }
// }
// } catch (IOException e) {
// log.error("Error parsing JSON response: {}", e.getMessage());
// }
// } catch (Exception e) {
// log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e);
// throw new RuntimeException("Authentication failed on Odessa. try again", e);
// }
// }
// return null;
// }
private void loginToOdessa(HubEntity hub, ApplicationEntity application) {
performOdessaLogin(hub, application);
}
private HubEntity authenticateAndSaveToken(HubEntity hub, ApplicationEntity application) {
return performOdessaLogin(hub, application);
}
private HubEntity performOdessaLogin(HubEntity hub, ApplicationEntity application) {
int maxRetries = 3;
int attempt = 0;
while (attempt < maxRetries) {
attempt++;
try { 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(); String authJwtToken = Utils.generateAuthTokenForLoginToOdessa();
log.info("Got the auth for login to odessa {}", authJwtToken); log.info("Got the auth for login to odessa {}", authJwtToken);
hub.setAuthToken(authJwtToken); hub.setAuthToken(authJwtToken);
@@ -189,7 +367,6 @@ public class AppointmentDao {
String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody());
AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson);
// Validate and save token
if (parsedResponse.getTokenId() != null) { if (parsedResponse.getTokenId() != null) {
hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); hub.setAppointmentAuthTokenId(parsedResponse.getTokenId());
hub.setAreaCode(parsedResponse.getAreaCode()); hub.setAreaCode(parsedResponse.getAreaCode());
@@ -201,53 +378,52 @@ public class AppointmentDao {
} }
} }
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_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 forbidden error.");
CheckPasswordExpiredOrErrorInResponse(application, forbiddenException);
} catch (Exception e) {
log.error("Failed to authenticate user on Odessa (Attempt {}): {}", attempt, e.getMessage(), e);
} }
catch (FeignException.Forbidden forbiddenException) { }
logForbiddenError(); throw new RuntimeException("Max retries exceeded. Failed to login to Odessa.");
}
private void CheckPasswordExpiredOrErrorInResponse(ApplicationEntity application, FeignException.Forbidden forbiddenException) {
// Extract raw response body String responseBody = forbiddenException.contentUTF8();
String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response
// Parse JSON to check for "PasswordExpired" try {
try { ObjectMapper objectMapper = new ObjectMapper();
ObjectMapper objectMapper = new ObjectMapper(); JsonNode rootNode = objectMapper.readTree(responseBody);
JsonNode rootNode = objectMapper.readTree(responseBody); JsonNode errorsNode = rootNode.path("errors");
JsonNode errorsNode = rootNode.path("errors");
if (errorsNode.isArray()) { if (errorsNode.isArray()) {
for (JsonNode error : errorsNode) { for (JsonNode error : errorsNode) {
// Check the main errorCode if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) {
if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { if (application != null) {
application.setNdgStatus(GepafinConstant.NDG_FAILED); application.setNdgStatus(GepafinConstant.NDG_FAILED);
applicationRepository.save(application); applicationRepository.save(application);
throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); }
} throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA));
}
// Check inside "subErrors" JsonNode subErrorsNode = error.path("subErrors");
JsonNode subErrorsNode = error.path("subErrors"); if (subErrorsNode.isArray()) {
if (subErrorsNode.isArray()) { for (JsonNode subError : subErrorsNode) {
for (JsonNode subError : subErrorsNode) { if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) {
if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { if (application != null) {
application.setNdgStatus(GepafinConstant.NDG_FAILED); application.setNdgStatus(GepafinConstant.NDG_FAILED);
applicationRepository.save(application); applicationRepository.save(application);
throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA));
}
} }
throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA));
} }
} }
} }
} catch (IOException e) {
log.error("Error parsing JSON response: {}", e.getMessage());
} }
// Regenerate the token and retry
loginToOdessa(hub, application);
} }
catch (Exception e) { } catch (IOException e) {
log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); log.error("Error parsing JSON response: {}", e.getMessage());
throw new RuntimeException("Authentication failed on Odessa. try again", e); }
}
return null;
} }
private void startAsyncNdgProcessing(Long applicationId) { private void startAsyncNdgProcessing(Long applicationId) {
@@ -296,7 +472,7 @@ public class AppointmentDao {
try { try {
// Authenticate and fetch token if required // Authenticate and fetch token if required
if (hub.getAppointmentAuthTokenId() == null || hub.getAreaCode() == null) { if (hub.getAppointmentAuthTokenId() == null || hub.getAreaCode() == null) {
authenticateAndSaveToken(hub); authenticateAndSaveToken(hub, application);
} }
String authorizationToken = getBearerToken(hub); String authorizationToken = getBearerToken(hub);
@@ -343,9 +519,13 @@ public class AppointmentDao {
applicationRepository.save(application); applicationRepository.save(application);
companyRepository.save(company); companyRepository.save(company);
ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId());
Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); // Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION);
Map<String, String> placeHolders = new HashMap<>();
placeHolders.put("{{call_name}}", application.getCall().getName());
placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber()));
notificationDao.sendNotificationToInstructor(placeHolders, applicationEvaluationEntity, 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()); log.info("NDG saved successfully for applicationId: {}", application.getId());
break; break;
} }
@@ -393,9 +573,12 @@ public class AppointmentDao {
companyRepository.save(company); companyRepository.save(company);
applicationRepository.save(application); applicationRepository.save(application);
ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId());
Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); // Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION);
Map<String, String> placeHolders = new HashMap<>();
placeHolders.put("{{call_name}}", application.getCall().getName());
placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber()));
notificationDao.sendNotificationToInstructor(placeHolders, applicationEvaluationEntity, 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()); log.info("NDG saved for applicationId: {}, {}", application.getId(), application.getNdg());
} }
@@ -413,7 +596,7 @@ public class AppointmentDao {
} catch (FeignException.Forbidden forbiddenException) { } catch (FeignException.Forbidden forbiddenException) {
log.error("403 Forbidden received while getting visuraList for Ndg code. Regenerating token..."); log.error("403 Forbidden received while getting visuraList for Ndg code. Regenerating token...");
// Regenerate the token and retry // Regenerate the token and retry
String newAuthorizationToken = regenerateTokenAndSave(hub); String newAuthorizationToken = regenerateTokenAndSave(hub, application);
return getVisuraList(idVisura, newAuthorizationToken, application, hub); return getVisuraList(idVisura, newAuthorizationToken, application, hub);
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to fetch Ndg code: {}", e.getMessage(), e); log.error("Failed to fetch Ndg code: {}", e.getMessage(), e);
@@ -421,82 +604,6 @@ public class AppointmentDao {
} }
} }
private HubEntity authenticateAndSaveToken(HubEntity hub) {
try {
//code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call
String authJwtToken = Utils.generateAuthTokenForLoginToOdessa();
log.info("Got the auth for login to odessa {}", authJwtToken);
hub.setAuthToken(authJwtToken);
hubRepository.save(hub);
// Prepare the request body (adjust if necessary for login API)
Map<String, Object> body = Collections.emptyMap();
// Perform login API call
ResponseEntity<Object> responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body);
// Handle successful login
if (responseLogin.getStatusCode() == HttpStatus.OK) {
log.info("Login successful to odessa. Parsing response.");
String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody());
AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson);
// Validate and save token
if (parsedResponse.getTokenId() != null) {
hub.setAppointmentAuthTokenId(parsedResponse.getTokenId());
hub.setAreaCode(parsedResponse.getAreaCode());
hubRepository.save(hub);
log.info("Saved new authToken and areaCode for Hub.");
return hub;
} else {
throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again.");
}
}
// Handle non-OK response
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN));
} catch (FeignException.Forbidden forbiddenException) {
logForbiddenError();
// Extract raw response body
String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response
// Parse JSON to check for "PasswordExpired"
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(responseBody);
JsonNode errorsNode = rootNode.path("errors");
if (errorsNode.isArray()) {
for (JsonNode error : errorsNode) {
// Check the main errorCode
if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) {
throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA));
}
// Check inside "subErrors"
JsonNode subErrorsNode = error.path("subErrors");
if (subErrorsNode.isArray()) {
for (JsonNode subError : subErrorsNode) {
if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) {
throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA));
}
}
}
}
}
} catch (IOException e) {
log.error("Error parsing JSON response: {}", e.getMessage());
}
// Regenerate the token and retry
regenerateTokenAndSave(hub);
} catch (Exception e) {
log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e);
throw new RuntimeException("Authentication failed on Odessa. try again", e);
}
return null;
}
private AppointmentLoginResponse retrieveNdgByVatNumber(String vatNumber, String authorizationToken, HubEntity hub, ApplicationEntity application) { private AppointmentLoginResponse retrieveNdgByVatNumber(String vatNumber, String authorizationToken, HubEntity hub, ApplicationEntity application) {
try { try {
@@ -510,7 +617,7 @@ public class AppointmentDao {
} catch (FeignException.Forbidden forbiddenException) { } catch (FeignException.Forbidden forbiddenException) {
logForbiddenError(); logForbiddenError();
// Regenerate the token and retry // Regenerate the token and retry
String newAuthorizationToken = regenerateTokenAndSave(hub); String newAuthorizationToken = regenerateTokenAndSave(hub, application);
return retrieveNdgByVatNumber(vatNumber, newAuthorizationToken, hub, application); return retrieveNdgByVatNumber(vatNumber, newAuthorizationToken, hub, application);
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to retrieve NDG by VAT number: {}", e.getMessage(), e); log.error("Failed to retrieve NDG by VAT number: {}", e.getMessage(), e);
@@ -518,9 +625,10 @@ public class AppointmentDao {
} }
} }
private String regenerateTokenAndSave(HubEntity hub) { private String regenerateTokenAndSave(HubEntity hub, ApplicationEntity application) {
hub = authenticateAndSaveToken(hub);
return "Bearer " + hub.getAppointmentAuthTokenId(); hub = authenticateAndSaveToken(hub, application);
return "Bearer " + hub.getAppointmentAuthTokenId();
} }
private AppointmentLoginResponse createVisura(CompanyEntity company, String authorizationToken, HubEntity hub) { private AppointmentLoginResponse createVisura(CompanyEntity company, String authorizationToken, HubEntity hub) {
@@ -533,7 +641,7 @@ public class AppointmentDao {
} catch (FeignException.Forbidden forbiddenException) { } catch (FeignException.Forbidden forbiddenException) {
logForbiddenError(); logForbiddenError();
// Regenerate the token and retry // Regenerate the token and retry
String newAuthorizationToken = regenerateTokenAndSave(hub); String newAuthorizationToken = regenerateTokenAndSave(hub, null);
return createVisura(company, newAuthorizationToken, hub); return createVisura(company, newAuthorizationToken, hub);
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to create Visura for Ndg : {}", e.getMessage()); log.error("Failed to create Visura for Ndg : {}", e.getMessage());
@@ -703,9 +811,8 @@ public class AppointmentDao {
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_NOT_FOUND_FOR_APPLICATION)); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_NOT_FOUND_FOR_APPLICATION));
} }
hub = authenticateAndSaveToken(hub);
// Generate authorization token and fetch template data // Generate authorization token and fetch template data
String authorizationToken = getBearerToken(hub); String authorizationToken = regenerateTokenAndSave(hub, application);
Long appointmentTemplateId = application.getCall().getAppointmentTemplateId(); Long appointmentTemplateId = application.getCall().getAppointmentTemplateId();
if (appointmentTemplateId == null) { if (appointmentTemplateId == null) {
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPOINTMENT_CANNOT_BE_CREATED)); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPOINTMENT_CANNOT_BE_CREATED));
@@ -749,7 +856,7 @@ public class AppointmentDao {
} catch (FeignException.Forbidden forbiddenException) { } catch (FeignException.Forbidden forbiddenException) {
log.error("403 Forbidden received while retrieving template. Regenerating token..."); log.error("403 Forbidden received while retrieving template. Regenerating token...");
regenerateTokenAndSave(hub); regenerateTokenAndSave(hub, application);
return createAppointment(applicationId, createAppointmentRequest); return createAppointment(applicationId, createAppointmentRequest);
} }
} }
@@ -758,12 +865,31 @@ public class AppointmentDao {
if (appointmentResponse.getBody() != null) { if (appointmentResponse.getBody() != null) {
log.info("Appointment API Response : {}", appointmentResponse.getBody()); log.info("Appointment API Response : {}", appointmentResponse.getBody());
Map<String, Object> responseBody = (Map<String, Object>) appointmentResponse.getBody(); try {
if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { Map<String, Object> responseBody = (Map<String, Object>) appointmentResponse.getBody();
Map<String, Object> data = (Map<String, Object>) responseBody.get(GepafinConstant.DATA_STRING); // 1. Try to get appointment ID from data.id
if (data != null && data.containsKey(GepafinConstant.ID_STRING)) { if (responseBody.containsKey(GepafinConstant.DATA_STRING)) {
return data.get(GepafinConstant.ID_STRING).toString(); Map<String, Object> data = (Map<String, Object>) 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<Map<String, Object>> errors = (List<Map<String, Object>>) responseBody.get(GepafinConstant.ERROR_STRING);
if (errors != null && !errors.isEmpty()) {
Map<String, Object> firstError = errors.get(0);
if (firstError.containsKey(GepafinConstant.CAUSE_STRING)) {
Map<String, Object> cause = (Map<String, Object>) 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; return null;
@@ -793,20 +919,20 @@ public class AppointmentDao {
JsonNode prodottoNode = richiestaNode.path(AppointmentApiConstant.PRODOTTO); JsonNode prodottoNode = richiestaNode.path(AppointmentApiConstant.PRODOTTO);
String prodottoCode = prodottoNode.path(AppointmentApiConstant.PRODOTTO_CODE).asText(); String prodottoCode = prodottoNode.path(AppointmentApiConstant.PRODOTTO_CODE).asText();
richiestaCliente.setCodProdotto(prodottoCode); richiestaCliente.setCodProdotto(prodottoCode);
richiestaCliente.setIdMotivazione(getIntValue(richiestaNode)); richiestaCliente.setIdMotivazione(getIntValue(richiestaNode));
richiestaCliente.setCodAbi(getTextValue(richiestaNode, AppointmentApiConstant.COD_ABI)); richiestaCliente.setCodAbi(getTextValue(richiestaNode, AppointmentApiConstant.COD_ABI));
richiestaCliente.setCodCab(getTextValue(richiestaNode, AppointmentApiConstant.COD_CAB)); richiestaCliente.setCodCab(getTextValue(richiestaNode, AppointmentApiConstant.COD_CAB));
richiestaCliente.setIdNota(getTextValue(richiestaNode, AppointmentApiConstant.ID_NOTA)); richiestaCliente.setIdNota(getTextValue(richiestaNode, AppointmentApiConstant.ID_NOTA));
richiestaCliente.setImportoAgevolato(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_AGEVOLATO)); richiestaCliente.setImportoAgevolato(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_AGEVOLATO));
richiestaCliente.setImportoMedioLungoTermine(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_MEDIOLUNGO_TERMINE)); richiestaCliente.setImportoMedioLungoTermine(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_MEDIOLUNGO_TERMINE));
richiestaCliente.setCodTipoProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_TIPO_PRODOTTO)); richiestaCliente.setCodTipoProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_TIPO_PRODOTTO));
richiestaCliente.setCodCategoriaProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_CATEGORIA_PRODOTTO)); richiestaCliente.setCodCategoriaProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_CATEGORIA_PRODOTTO));
richiestaCliente.setCodFormaTecnica(getTextValue(richiestaNode, AppointmentApiConstant.COD_FORMATECNICA)); richiestaCliente.setCodFormaTecnica(getTextValue(richiestaNode, AppointmentApiConstant.COD_FORMATECNICA));
richiestaCliente.setCodOperazione(getTextValue(richiestaNode, AppointmentApiConstant.COD_OPERAZIONE)); richiestaCliente.setCodOperazione(getTextValue(richiestaNode, AppointmentApiConstant.COD_OPERAZIONE));
richiestaClienteList.add(richiestaCliente); richiestaClienteList.add(richiestaCliente);
} }
input.setRichiestaCliente(richiestaClienteList); input.setRichiestaCliente(richiestaClienteList);
appointmentCreationRequest.setInput(input); appointmentCreationRequest.setInput(input);
@@ -867,13 +993,40 @@ public class AppointmentDao {
// Check if the document is already being processed // Check if the document is already being processed
DocumentEntity systemDoc = documentDao.validateDocument(documentId); 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)); Claims claims = tokenProvider.getClaimsFromToken(tokenProvider.extractTokenFromRequest(request));
Long hubId = Utils.extractHubIdFromPayload(claims.getSubject()); Long hubId = Utils.extractHubIdFromPayload(claims.getSubject());
// Authenticate the hub before proceeding // Authenticate the hub before proceeding
HubEntity hub = hubRepository.findByHubId(hubId); HubEntity hub = hubRepository.findByHubId(hubId);
authenticateAndSaveToken(hub); authenticateAndSaveToken(hub, application);
if (systemDoc.getDocumentAttachmentId() != null) { if (systemDoc != null && systemDoc.getDocumentAttachmentId() != null) {
// If the documentAttachmentId is already set, return the response // If the documentAttachmentId is already set, return the response
log.info("Document already uploaded with documentAttachmentId: {}", systemDoc.getDocumentAttachmentId()); log.info("Document already uploaded with documentAttachmentId: {}", systemDoc.getDocumentAttachmentId());
DocumentUploadResponse response = new DocumentUploadResponse(); DocumentUploadResponse response = new DocumentUploadResponse();
@@ -893,11 +1046,12 @@ public class AppointmentDao {
}); });
threadForDocumentMap.put(documentId, executor); threadForDocumentMap.put(documentId, executor);
ApplicationEntity finalApplication = application;
executor.submit(() -> { executor.submit(() -> {
threadLocalHubId.set(hubId); threadLocalHubId.set(hubId);
try { try {
log.info("Starting async document upload for documentId: {}", documentId); log.info("Starting async document upload for documentId: {}", documentId);
uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest); uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest, finalApplication);
} catch (Exception e) { } catch (Exception e) {
log.error("Error in async document upload for documentId: {}", documentId, e); log.error("Error in async document upload for documentId: {}", documentId, e);
} finally { } finally {
@@ -913,7 +1067,7 @@ public class AppointmentDao {
return null; return null;
} }
private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest) { private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest, ApplicationEntity application) {
// Synchronous upload logic // Synchronous upload logic
DocumentEntity systemDoc = documentDao.validateDocument(documentId); DocumentEntity systemDoc = documentDao.validateDocument(documentId);
@@ -954,8 +1108,8 @@ public class AppointmentDao {
log.info("Document uploaded successfully to external system: {}", parsedResponse); log.info("Document uploaded successfully to external system: {}", parsedResponse);
} catch (FeignException.Forbidden forbiddenException) { } catch (FeignException.Forbidden forbiddenException) {
log.error("403 Forbidden received while uploading document. Regenerating token..."); log.error("403 Forbidden received while uploading document. Regenerating token...");
regenerateTokenAndSave(hub); regenerateTokenAndSave(hub, application);
uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest); uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest, application);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during document upload: {}", e.getMessage(), e); log.error("Exception during document upload: {}", e.getMessage(), e);
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.EXTERNAL_DOCUMENT_UPLOAD_FAILURE_MSG)); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.EXTERNAL_DOCUMENT_UPLOAD_FAILURE_MSG));

View File

@@ -473,6 +473,7 @@ public class AssignedApplicationsDao {
response.setCompanyName(view.getCompanyName()); response.setCompanyName(view.getCompanyName());
response.setCreatedDate(view.getCreatedDate()); response.setCreatedDate(view.getCreatedDate());
response.setUpdatedDate(view.getUpdatedDate()); response.setUpdatedDate(view.getUpdatedDate());
response.setEmailSendResponse(view.getEmailSendResponse());
return response; return response;
} }

View File

@@ -986,7 +986,7 @@ public class CallDao {
return callEntity; return callEntity;
} }
public PageableResponseBean<List<CallDetailsResponseBean>> getAllCallsByPagination(HttpServletRequest request,UserEntity user,Long companyId , Boolean onlyPreferredCall, CallPageableRequestBean callPageableRequestBean) { public PageableResponseBean<List<CallDetailsResponseBean>> getAllCallsByPagination(HttpServletRequest request,UserEntity user,Long companyId , Boolean onlyPreferredCall, Boolean onlyConfidiCall, CallPageableRequestBean callPageableRequestBean) {
Integer pageNo = null; Integer pageNo = null;
Integer pageLimit = null; Integer pageLimit = null;
if (callPageableRequestBean.getGlobalFilters() != null) { if (callPageableRequestBean.getGlobalFilters() != null) {
@@ -1006,7 +1006,7 @@ public class CallDao {
); );
} }
expirePublishedCalls(request); expirePublishedCalls(request);
Specification<CallEntity> spec = search(request,user, callPageableRequestBean); Specification<CallEntity> spec = search(request,user, callPageableRequestBean,onlyConfidiCall);
Page<CallEntity> entityPage; Page<CallEntity> entityPage;
if (Boolean.TRUE.equals(onlyPreferredCall)) { if (Boolean.TRUE.equals(onlyPreferredCall)) {
validator.validateUserWithCompany(request, companyId); validator.validateUserWithCompany(request, companyId);
@@ -1056,10 +1056,10 @@ public class CallDao {
return pageableResponseBean; return pageableResponseBean;
} }
public Specification<CallEntity> search(HttpServletRequest request,UserEntity userEntity, CallPageableRequestBean callPageableRequestBean) { public Specification<CallEntity> search(HttpServletRequest request,UserEntity userEntity, CallPageableRequestBean callPageableRequestBean,Boolean onlyConfidiCall) {
return (root, query, criteriaBuilder) -> { return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = getPredicates(request,callPageableRequestBean, criteriaBuilder, root, userEntity); List<Predicate> predicates = getPredicates(request,callPageableRequestBean, criteriaBuilder, root, userEntity,onlyConfidiCall);
SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true);
if (callPageableRequestBean.getGlobalFilters() != null if (callPageableRequestBean.getGlobalFilters() != null
@@ -1083,7 +1083,7 @@ public class CallDao {
private List<Predicate> getPredicates(HttpServletRequest request,CallPageableRequestBean callPageableRequestBean, private List<Predicate> getPredicates(HttpServletRequest request,CallPageableRequestBean callPageableRequestBean,
CriteriaBuilder criteriaBuilder, Root<CallEntity> root, UserEntity userEntity) { CriteriaBuilder criteriaBuilder, Root<CallEntity> root, UserEntity userEntity,Boolean onlyConfidiCall) {
Integer year = null; Integer year = null;
String search = null; String search = null;
Map<String, FilterCriteria> filters = new HashMap<>(); Map<String, FilterCriteria> filters = new HashMap<>();
@@ -1137,7 +1137,7 @@ public class CallDao {
predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); predicates.add(root.get(GepafinConstant.STATUS).in(statusValues));
} }
applyFilters(root, criteriaBuilder, predicates, filters); applyFilters(root, criteriaBuilder, predicates, filters);
Boolean isConfidi = callPageableRequestBean.getConfidi(); Boolean isConfidi =onlyConfidiCall;
if (validator.checkIsConfidi()) { if (validator.checkIsConfidi()) {

View File

@@ -0,0 +1,212 @@
package net.gepafin.tendermanagement.dao;
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.*;
import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum;
import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum;
import net.gepafin.tendermanagement.enums.RecipientTypeEnum;
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.*;
import net.gepafin.tendermanagement.service.CallService;
import net.gepafin.tendermanagement.util.Utils;
import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
@Log4j2
public class EmailDao {
@Autowired
EmailLogRepository emailLogRepository;
@Autowired
EmailNotificationDao emailNotificationDao;
@Autowired
private CallService callService;
@Autowired
private EmailLogDao emailLogDao;
@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){
throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_ACTION_ID_NOT_FOUND));
}
List<EmailLogEntity> emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceTypeAndSendStatus(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue(),StatusTypeEnum.FAILED.getValue());
if (emailLogs.isEmpty()) {
log.info("No emails found for given userActionId: {}",userActionId);
throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.NO_EMAIL_LOG_FOUND));
}
EmailResendResponseBean emailResendResponseBean = new EmailResendResponseBean();
for (EmailLogEntity log : emailLogs){
EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(EmailScenarioTypeEnum.valueOf(log.getEmailType()),
RecipientTypeEnum.valueOf(log.getRecipientType()),
log.getRecipientId(),
log.getRecipientEmails(),
log.getUserId(),
log.getApplicationId(),
log.getAmendmentId(),
log.getCallId()
);
List<String> recipients = Utils.commaSeparatedStringToList(log.getRecipientEmails());
CallEntity call = callService.validateCall(log.getCallId());
emailNotificationDao.sendMail(
call.getHub().getId(),
log.getEmailSubject(),
log.getEmailBody(),
recipients,
emailLogRequest
);
}
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<EmailSendResponse> responses, String scenario) {
if (responses == null || responses.isEmpty()) return false;
for (Iterator<EmailSendResponse> iterator = responses.iterator(); iterator.hasNext(); ) {
EmailSendResponse response = iterator.next();
if (scenario.equals(response.getEmailScenario().getValue())) {
iterator.remove(); // remove only the first match
return true;
}
}
return false;
}
public EmailSendResponse buildEmailSendResponseFromRequest(HttpServletRequest request) {
Long userActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID);
List<EmailLogEntity> emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceType(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue());
boolean allSuccess = true;
String emailScenario = null;
for (EmailLogEntity log : emailLogs) {
if (emailScenario == null) {
emailScenario = log.getEmailType();
}
boolean isSuccess = StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus());
if (Boolean.FALSE.equals(isSuccess)) {
allSuccess = false;
break;
}
}
return buildResponse(userActionId, allSuccess, emailScenario);
}
private EmailSendResponse buildResponse(Long userActionId, boolean allSuccess, String emailScenario) {
EmailSendResponse response = new EmailSendResponse();
response.setUserActionId(userActionId);
response.setIsEmailSend(allSuccess);
response.setEmailScenario(emailScenario != null ? EmailScenarioTypeEnum.valueOf(emailScenario) : null);
return response;
}
}

View File

@@ -1,6 +1,7 @@
package net.gepafin.tendermanagement.dao; package net.gepafin.tendermanagement.dao;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.entities.EmailLogEntity; import net.gepafin.tendermanagement.entities.EmailLogEntity;
import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum;
import net.gepafin.tendermanagement.enums.EmailEntityTypeEnum; import net.gepafin.tendermanagement.enums.EmailEntityTypeEnum;
@@ -9,6 +10,7 @@ import net.gepafin.tendermanagement.enums.VersionActionTypeEnum;
import net.gepafin.tendermanagement.model.request.EmailLogRequest; import net.gepafin.tendermanagement.model.request.EmailLogRequest;
import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest;
import net.gepafin.tendermanagement.repositories.EmailLogRepository; import net.gepafin.tendermanagement.repositories.EmailLogRepository;
import net.gepafin.tendermanagement.repositories.UserActionsRepository;
import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.DateTimeUtil;
import net.gepafin.tendermanagement.util.LoggingUtil; import net.gepafin.tendermanagement.util.LoggingUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +24,12 @@ public class EmailLogDao {
@Autowired @Autowired
private EmailLogRepository emailLogRepository; private EmailLogRepository emailLogRepository;
@Autowired
private HttpServletRequest request;
@Autowired
private LoggingUtil loggingUtil;
public EmailLogEntity createEmailLog(EmailLogRequest emailLogRequest) { public EmailLogEntity createEmailLog(EmailLogRequest emailLogRequest) {
@@ -42,8 +50,8 @@ public class EmailLogDao {
emailLogEntity.setApplicationId(emailLogRequest.getApplicatioId()); emailLogEntity.setApplicationId(emailLogRequest.getApplicatioId());
emailLogEntity.setAmendmentId(emailLogRequest.getAmendmentId()); emailLogEntity.setAmendmentId(emailLogRequest.getAmendmentId());
emailLogEntity.setCallId(emailLogRequest.getCallId()); emailLogEntity.setCallId(emailLogRequest.getCallId());
emailLogEntity.setUserAction(loggingUtil.getUserActionLogById(emailLogRequest.getUserActionId()));
emailLogEntity = saveEmailLogEntity(emailLogEntity); emailLogEntity = saveEmailLogEntity(emailLogEntity);
return emailLogEntity; return emailLogEntity;
} }
public EmailLogEntity saveEmailLogEntity(EmailLogEntity emailLogEntity){ public EmailLogEntity saveEmailLogEntity(EmailLogEntity emailLogEntity){
@@ -52,6 +60,7 @@ public class EmailLogDao {
public EmailLogRequest createEmailLogRequest(EmailScenarioTypeEnum emailType, RecipientTypeEnum recipientType, Long recipientId, public EmailLogRequest createEmailLogRequest(EmailScenarioTypeEnum emailType, RecipientTypeEnum recipientType, Long recipientId,
String recipientEmails, Long userId,Long applicationId,Long amendmentId,Long callId) { String recipientEmails, Long userId,Long applicationId,Long amendmentId,Long callId) {
EmailLogRequest emailLogRequest = new EmailLogRequest(); EmailLogRequest emailLogRequest = new EmailLogRequest();
Long userActionId =(Long) request.getAttribute(GepafinConstant.USER_ACTION_ID);
emailLogRequest.setEmailType(emailType); emailLogRequest.setEmailType(emailType);
emailLogRequest.setRecipientType(recipientType); emailLogRequest.setRecipientType(recipientType);
emailLogRequest.setRecipientId(recipientId); emailLogRequest.setRecipientId(recipientId);
@@ -60,6 +69,7 @@ public class EmailLogDao {
emailLogRequest.setApplicatioId(applicationId); emailLogRequest.setApplicatioId(applicationId);
emailLogRequest.setAmendmentId(amendmentId); emailLogRequest.setAmendmentId(amendmentId);
emailLogRequest.setCallId(callId); emailLogRequest.setCallId(callId);
emailLogRequest.setUserActionId(userActionId);
return emailLogRequest; return emailLogRequest;
} }
} }

View File

@@ -139,7 +139,7 @@ public class EmailNotificationDao {
} }
} }
} }
if (rinaldoEmail != null) { if (GepafinConstant.RINALDO_EMAIL.equals(rinaldoEmail)) {
EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(), RecipientTypeEnum.PROPERTIES,null , EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(), RecipientTypeEnum.PROPERTIES,null ,
rinaldoEmail, userEntity.getId(), applicationEntity.getId(), amendmentId, applicationEntity.getCall().getId()); rinaldoEmail, userEntity.getId(), applicationEntity.getId(), amendmentId, applicationEntity.getCall().getId());
@@ -283,12 +283,11 @@ public class EmailNotificationDao {
if (recipientEmails.stream().anyMatch(email -> email.equals(GepafinConstant.RINALDO_EMAIL))) { if (recipientEmails.stream().anyMatch(email -> email.equals(GepafinConstant.RINALDO_EMAIL))) {
emailConfig.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE.getValue()); emailConfig.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE.getValue());
EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType()); EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType());
emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest);
} else { } else {
emailConfig = retrieveEmailConfig(hubId); emailConfig = retrieveEmailConfig(hubId);
EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType()); EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType());
emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest);
} }
} }

View File

@@ -15,6 +15,7 @@ import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.JWTToken;
import net.gepafin.tendermanagement.model.util.SortBy; import net.gepafin.tendermanagement.model.util.SortBy;
import net.gepafin.tendermanagement.repositories.BeneficiaryRepository; import net.gepafin.tendermanagement.repositories.BeneficiaryRepository;
import net.gepafin.tendermanagement.repositories.EmailLogRepository;
import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.repositories.UserRepository;
import net.gepafin.tendermanagement.service.HubService; import net.gepafin.tendermanagement.service.HubService;
import net.gepafin.tendermanagement.service.RoleService; import net.gepafin.tendermanagement.service.RoleService;
@@ -42,6 +43,7 @@ import org.springframework.stereotype.Component;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; import static net.gepafin.tendermanagement.util.Utils.setIfUpdated;
@@ -109,9 +111,15 @@ public class UserDao {
@Autowired @Autowired
private EmailNotificationDao emailNotificationDao; private EmailNotificationDao emailNotificationDao;
@Autowired
private EmailLogRepository emailLogRepository;
@Value("${fe.base.url}") @Value("${fe.base.url}")
private String feBaseUrl; private String feBaseUrl;
@Autowired
EmailDao emailDao;
public JWTToken createUser(HttpServletRequest request, String tempToken, UserReq userReq) { public JWTToken createUser(HttpServletRequest request, String tempToken, UserReq userReq) {
if (StringUtils.isEmpty(userReq.getHubUuid())) { if (StringUtils.isEmpty(userReq.getHubUuid())) {
@@ -134,7 +142,6 @@ public class UserDao {
authenticationService.createSuccessLoginAttempt(loginAttemptEntity); authenticationService.createSuccessLoginAttempt(loginAttemptEntity);
} }
JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId());
/** This code is responsible for adding a version history log for the "Create beneficiary" operation. **/ /** This code is responsible for adding a version history log for the "Create beneficiary" operation. **/
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(beneficiary).build()); loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(beneficiary).build());
@@ -142,12 +149,40 @@ public class UserDao {
/** This code is responsible for adding a version history log for the "Create user" operation. **/ /** This code is responsible for adding a version history log for the "Create user" operation. **/
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(userEntity).build()); loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(userEntity).build());
List<EmailSendResponse> responses = new ArrayList<>();
if(Boolean.FALSE.equals(roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue()))){ if(Boolean.FALSE.equals(roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue()))){
sendEmailToOnboardingUser(userEntity, userReq ); sendEmailToOnboardingUser(userEntity, userReq );
boolean isEmailSendSuccess = isEmailSentSuccessfully(userEntity.getId());
EmailSendResponse emailSendResponse = new EmailSendResponse();
if (Boolean.FALSE.equals(isEmailSendSuccess)){
emailSendResponse.setIsEmailSend(false);
Long userActionId =(Long)request.getAttribute(GepafinConstant.USER_ACTION_ID);
emailSendResponse.setUserActionId(userActionId);
emailSendResponse.setEmailScenario(EmailScenarioTypeEnum.USER_CREATION);
saveEmailSendResponseToUser(emailSendResponse,userEntity);
responses = List.of(emailSendResponse);
}
else{
responses = Collections.emptyList();
}
} }
JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId(),responses);
return token; return token;
} }
public void sendEmailToOnboardingUser(UserEntity userEntity,UserReq userReq){
public boolean isEmailSentSuccessfully(Long userId) {
Optional<EmailLogEntity> latestLogOpt = emailLogRepository
.findTopByUserIdAndEmailTypeAndIsDeletedFalseOrderByCreatedDateDesc(userId, EmailScenarioTypeEnum.USER_CREATION.getValue());
return latestLogOpt
.map(log -> StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus()))
.orElse(false);
}
public void sendEmailToOnboardingUser(UserEntity userEntity,UserReq userReq){
SystemEmailTemplateResponse emailTemplate; SystemEmailTemplateResponse emailTemplate;
RoleStatusEnum roleStatus = RoleStatusEnum.valueOf(userEntity.getRoleEntity().getRoleType()); RoleStatusEnum roleStatus = RoleStatusEnum.valueOf(userEntity.getRoleEntity().getRoleType());
@@ -382,6 +417,7 @@ public class UserDao {
RoleResponseBean roleResponseBean = roleDao.convertRoleEntityToRoleResponse(userEntity.getRoleEntity()); RoleResponseBean roleResponseBean = roleDao.convertRoleEntityToRoleResponse(userEntity.getRoleEntity());
userResponseBean.setRole(roleResponseBean); userResponseBean.setRole(roleResponseBean);
userResponseBean.setLastLogin(userEntity.getLastLogin()); userResponseBean.setLastLogin(userEntity.getLastLogin());
userResponseBean.setEmailSendResponse(userEntity.getEmailSendResponse());
List<CompanyResponse> companyResponseBeans = companyDao.getCompanyByUserId(userEntity.getId()); List<CompanyResponse> companyResponseBeans = companyDao.getCompanyByUserId(userEntity.getId());
userResponseBean.setCompanies(companyResponseBeans); userResponseBean.setCompanies(companyResponseBeans);
if (userEntity.getBeneficiary() == null) { if (userEntity.getBeneficiary() == null) {
@@ -459,7 +495,7 @@ public class UserDao {
return user; return user;
} }
public void initiatePasswordReset(InitiatePasswordResetReq resetReq) { public InitiatePasswordResetResponse initiatePasswordReset(InitiatePasswordResetReq resetReq) {
UserEntity user = userRepository.findUserExcludingRoleType( UserEntity user = userRepository.findUserExcludingRoleType(
resetReq.getEmail(), resetReq.getEmail(),
resetReq.getHubUuid(), resetReq.getHubUuid(),
@@ -478,9 +514,28 @@ public class UserDao {
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldUserEntity).newData(user).build()); loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldUserEntity).newData(user).build());
log.info("Password reset token generated for user: {}", resetReq.getEmail()); log.info("Password reset token generated for user: {}", resetReq.getEmail());
sendResetPasswordTokenEmail(user, token); sendResetPasswordTokenEmail(user, token);
InitiatePasswordResetResponse initiatePasswordResetResponse = new InitiatePasswordResetResponse();
EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request);
List<EmailSendResponse> responses = List.of(emailSendResponse);
if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){
initiatePasswordResetResponse.setEmailSendResponse(responses);
saveEmailSendResponseToUser(emailSendResponse,user);
}
else{
initiatePasswordResetResponse.setEmailSendResponse(Collections.emptyList());
}
return initiatePasswordResetResponse;
} }
private void saveEmailSendResponseToUser(EmailSendResponse newResponse, UserEntity user) {
List<EmailSendResponse> mergedResponses = Utils.mergeEmailSendResponses(
user.getEmailSendResponse(), newResponse
);
user.setEmailSendResponse(mergedResponses);
userRepository.save(user);
}
public void sendResetPasswordTokenEmail(UserEntity user, String token) { public void sendResetPasswordTokenEmail(UserEntity user, String token) {
SystemEmailTemplateResponse emailTemplate = systemEmailTemplatesService.retrieveTemplateByTypeAndCall( SystemEmailTemplateResponse emailTemplate = systemEmailTemplatesService.retrieveTemplateByTypeAndCall(

View File

@@ -2,7 +2,10 @@ package net.gepafin.tendermanagement.entities;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.Data; import lombok.Data;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Entity @Entity
@Table(name="application_amendment_request") @Table(name="application_amendment_request")
@@ -53,7 +56,10 @@ public class ApplicationAmendmentRequestEntity extends BaseEntity {
@Column(name = "amendment_document") @Column(name = "amendment_document")
private String amendmentDocument; private String amendmentDocument;
@Column(name = "CLOSING_DATE") @Column(name = "CLOSING_DATE")
private LocalDateTime closingDate; private LocalDateTime closingDate;
@Convert(converter = EmailSendResponseConverter.class)
@Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT")
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -3,9 +3,12 @@ package net.gepafin.tendermanagement.entities;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import net.gepafin.tendermanagement.model.BaseBean;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Immutable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Entity @Entity
@Immutable @Immutable
@@ -13,12 +16,12 @@ import java.time.LocalDateTime;
@Getter @Getter
@Setter @Setter
@IdClass(ApplicationAmendmentRequestViewId.class) @IdClass(ApplicationAmendmentRequestViewId.class)
public class ApplicationAmendmentRequestView { public class ApplicationAmendmentRequestView extends BaseEntity {
@Id // @Id
@Column(name = "ID") // @Column(name = "ID")
private Long id; // private Long id;
@Column(name = "APPLICATION_ID") @Column(name = "APPLICATION_ID")
private Long applicationId; private Long applicationId;
@@ -56,12 +59,17 @@ public class ApplicationAmendmentRequestView {
@Column(name = "APPLICATION_USER_ID") @Column(name = "APPLICATION_USER_ID")
private Long applicationUserId; private Long applicationUserId;
@Column(name = "CREATED_DATE") // @Column(name = "CREATED_DATE")
private String createdDate; // private String createdDate;
//
@Column(name = "UPDATED_DATE") // @Column(name = "UPDATED_DATE")
private String updatedDate; // private String updatedDate;
@Column(name = "IS_DELETED") @Column(name = "IS_DELETED")
private Boolean isDeleted; private Boolean isDeleted;
@Convert(converter = EmailSendResponseConverter.class)
@Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT")
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -2,8 +2,10 @@ package net.gepafin.tendermanagement.entities;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.Data; import lombok.Data;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Data @Data
@Entity @Entity
@@ -71,4 +73,7 @@ public class ApplicationEvaluationEntity extends BaseEntity{
@Column(name = "evaluationVersion") @Column(name = "evaluationVersion")
private String evaluationVersion; private String evaluationVersion;
@Convert(converter = EmailSendResponseConverter.class)
@Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT")
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -2,9 +2,11 @@ package net.gepafin.tendermanagement.entities;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.Data; import lombok.Data;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Immutable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Entity @Entity
@Immutable @Immutable
@@ -59,6 +61,10 @@ public class AssignedApplicationsView{
@Column(name = "IS_DELETED") @Column(name = "IS_DELETED")
private Boolean isDeleted; private Boolean isDeleted;
@Convert(converter = EmailSendResponseConverter.class)
@Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT")
private List<EmailSendResponse> emailSendResponse;
@Column(name = "HUB_ID") @Column(name = "HUB_ID")
private Long hubId; private Long hubId;
} }

View File

@@ -56,5 +56,9 @@ public class EmailLogEntity extends BaseEntity{
@Column(name = "is_deleted") @Column(name = "is_deleted")
private Boolean isDeleted; private Boolean isDeleted;
@ManyToOne
@JoinColumn(name = "user_action_id")
private UserActionEntity userAction;
} }

View File

@@ -0,0 +1,43 @@
package net.gepafin.tendermanagement.entities;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import java.io.IOException;
import java.util.List;
@Converter
public class EmailSendResponseConverter implements AttributeConverter<List<EmailSendResponse>, String> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(List<EmailSendResponse> attribute) {
try {
if (attribute == null) {
attribute = List.of();
}
return objectMapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Error converting list to JSON", e);
}
}
@Override
public List<EmailSendResponse> convertToEntityAttribute(String dbData) {
if (dbData == null || dbData.isBlank()) {
return List.of(); // or null if you prefer
}
try {
return objectMapper.readValue(dbData, new TypeReference<List<EmailSendResponse>>() {});
} catch (IOException e) {
throw new IllegalArgumentException("Error reading JSON from database", e);
}
}
}

View File

@@ -55,7 +55,8 @@ public class SystemEmailTemplatesEntity extends BaseEntity {
USER_ONBOARDING_CONFIDI("USER_ONBOARDING_CONFIDI"), USER_ONBOARDING_CONFIDI("USER_ONBOARDING_CONFIDI"),
USER_ONBOARDING_BANDI("USER_ONBOARDING_BANDI"), USER_ONBOARDING_BANDI("USER_ONBOARDING_BANDI"),
PASSWORD_RESET("PASSWORD_RESET"), PASSWORD_RESET("PASSWORD_RESET"),
INADMISSIBILITY_TEMPLATE("INADMISSIBILITY_NOTIFICATION"); INADMISSIBILITY_TEMPLATE("INADMISSIBILITY_NOTIFICATION"),
APPLICATION_SUBMISSION_FAILURE_NOTIFICATION("APPLICATION_SUBMISSION_FAILURE_NOTIFICATION");
private String value; private String value;
SystemEmailTemplatesEntityTypeEnum(String value) { SystemEmailTemplatesEntityTypeEnum(String value) {

View File

@@ -7,8 +7,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Entity @Entity
@Table(name = "GEPAFIN_USER") @Table(name = "GEPAFIN_USER")
@@ -69,4 +71,9 @@ public class UserEntity extends BaseEntity {
@ManyToOne @ManyToOne
@JoinColumn(name = "HUB_ID") @JoinColumn(name = "HUB_ID")
private HubEntity hub; private HubEntity hub;
@Convert(converter = EmailSendResponseConverter.class)
@Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT")
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -11,7 +11,8 @@ public enum EmailScenarioTypeEnum {
APPLICATION_ADMISSIBLE("APPLICATION_ADMISSIBLE"), APPLICATION_ADMISSIBLE("APPLICATION_ADMISSIBLE"),
USER_CREATION("USER_CREATION"), USER_CREATION("USER_CREATION"),
PASSWORD_RESET_REQUEST("PASSWORD_RESET_REQUEST"), PASSWORD_RESET_REQUEST("PASSWORD_RESET_REQUEST"),
APPLICATION_REJECTED("APPLICATION_REJECTED"); APPLICATION_REJECTED("APPLICATION_REJECTED"),
APPLICATION_SUBMISSION_FAILURE("APPLICATION_SUBMISSION_FAILURE");
private final String value; private final String value;

View File

@@ -14,7 +14,8 @@ public enum NotificationTypeEnum {
EVALUATION_EXPIRED("EVALUATION_EXPIRED"), EVALUATION_EXPIRED("EVALUATION_EXPIRED"),
AMENDMENT_EXPIRATION_REMINDER("AMENDMENT_EXPIRATION_REMINDER"), AMENDMENT_EXPIRATION_REMINDER("AMENDMENT_EXPIRATION_REMINDER"),
EVALUATION_EXPIRATION_REMINDER("EVALUATION_EXPIRATION_REMINDER"), EVALUATION_EXPIRATION_REMINDER("EVALUATION_EXPIRATION_REMINDER"),
COMPANY_DOCUMENT_EXPIRATION_REMINDER("COMPANY_DOCUMENT_EXPIRATION_REMINDER"); COMPANY_DOCUMENT_EXPIRATION_REMINDER("COMPANY_DOCUMENT_EXPIRATION_REMINDER"),
PEC_EMAIL_SENDING_FAILURE("PEC_EMAIL_SENDING_FAILURE");
private final String value; private final String value;

View File

@@ -216,7 +216,9 @@ public enum UserActionContextEnum {
GET_ALL_USER_ACTION_BY_PAGINATION("GET_ALL_USER_ACTION_BY_PAGINATION"), GET_ALL_USER_ACTION_BY_PAGINATION("GET_ALL_USER_ACTION_BY_PAGINATION"),
GET_ALL_USER_BY_PAGINATION("GET_ALL_USER_BY_PAGINATION"), GET_ALL_USER_BY_PAGINATION("GET_ALL_USER_BY_PAGINATION"),
UPDATE_CALL_END_DATE_AND_TIME("UPDATE_CALL_END_DATE_AND_TIME"), UPDATE_CALL_END_DATE_AND_TIME("UPDATE_CALL_END_DATE_AND_TIME"),
UPDATE_EXPIRED_CALL("UPDATE_EXPIRED_CALL") ; UPDATE_EXPIRED_CALL("UPDATE_EXPIRED_CALL"),
RESEND_EMAIL("RESEND_EMAIL"),
SEND_REMINDER_EMAIL("SEND_REMINDER_EMAIL");
private final String value; private final String value;

View File

@@ -12,7 +12,8 @@ public enum UserActionLogsEnum {
DOWNLOAD("DOWNLOAD"), DOWNLOAD("DOWNLOAD"),
UPLOAD("UPLOAD"), UPLOAD("UPLOAD"),
SCHEDULER("SCHEDULER"), SCHEDULER("SCHEDULER"),
SCRIPT("SCRIPT"); SCRIPT("SCRIPT"),
EMAIL("EMAIL");
private final String value; private final String value;

View File

@@ -14,6 +14,4 @@ public class CallPageableRequestBean {
private List<CallStatusEnum> status; private List<CallStatusEnum> status;
private Map<String, FilterCriteria> filters; private Map<String, FilterCriteria> filters;
private Boolean confidi;
} }

View File

@@ -37,4 +37,6 @@ public class EmailLogRequest {
private Long callId; private Long callId;
private Long userActionId;
} }

View File

@@ -32,4 +32,5 @@ public class ApplicationAmendmentRequestResponse {
private String internalNote; private String internalNote;
private ApplicationAmendmentRequestEnum status; private ApplicationAmendmentRequestEnum status;
private String emailTemplate; private String emailTemplate;
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -0,0 +1,36 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class ApplicationAmendmentRequestResponseBean {
private Long id;
private String callEmail;
private String note;
private Long responseDays;
private LocalDateTime startDate;
private Boolean isSendNotification;
private Boolean isSendEmail;
private Long protocolNumber;
private String callName;
private String beneficiaryName;
private String companyName;
private List<AmendmentFormFieldResponse> formFields;
private List<ApplicationFormFieldResponseBean> applicationFormFields;
private List<DocumentResponseBean> amendmentDocuments;
private String amendmentNotes;
private Boolean valid;
private Long applicationId;
private Long applicationEvaluationId;
private LocalDateTime evaluationEndDate;
private LocalDateTime expirationDate;
private List<CommunicationResponseBean> commentsList;
private String internalNote;
private ApplicationAmendmentRequestEnum status;
private String emailTemplate;
private List<EmailSendResponse> emailSendResponse;
}

View File

@@ -3,6 +3,7 @@ package net.gepafin.tendermanagement.model.response;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Data @Data
public class ApplicationAmendmentRequestViewResponse { public class ApplicationAmendmentRequestViewResponse {
@@ -24,4 +25,6 @@ public class ApplicationAmendmentRequestViewResponse {
private String assigendUserName; private String assigendUserName;
private String status; private String status;
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -48,5 +48,6 @@ public class ApplicationEvaluationFormResponse {
private Long appointmentTemplateId; private Long appointmentTemplateId;
private String companyVatNumber; private String companyVatNumber;
private String companyCodiceAteco; private String companyCodiceAteco;
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -49,5 +49,6 @@ public class ApplicationEvaluationResponse {
private EvaluationVersionEnum evaluationVersion; private EvaluationVersionEnum evaluationVersion;
private String companyVatNumber; private String companyVatNumber;
private String companyCodiceAteco; private String companyCodiceAteco;
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -0,0 +1,52 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import net.gepafin.tendermanagement.enums.ApplicationEvaluationStatusTypeEnum;
import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum;
import net.gepafin.tendermanagement.enums.EvaluationVersionEnum;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class ApplicationEvaluationResponseBean {
private Long id;
private Long applicationId;
private ApplicationStatusTypeEnum applicationStatus;
private Long assignedApplicationId;
private String note;
private ApplicationEvaluationStatusTypeEnum status;
private Long minScore;
private List<CriteriaResponse> criteria;
private List<ChecklistResponse> checklist;
private List<FieldResponse> files;
private List<EvaluationDocumentResponse> evaluationDocument;
private List<AmendmentDocumentResponseBean> amendmentDetails;
private LocalDateTime createdDate;
private LocalDateTime updatedDate;
private String beneficiary;
private Long assignedUserId;
private String assignedUserName;
private Long protocolNumber;
private String callName;
private String motivation;
private LocalDateTime submissionDate;
private LocalDateTime evaluationEndDate;
private LocalDateTime callEndDate;
private String companyName;
private LocalDateTime assignedAt;
private String ndg;
private String appointmentId;
private BigDecimal amountRequested;
private BigDecimal amountAccepted;
private LocalDateTime dateAccepted;
private LocalDateTime dateRejected;
private Long numberOfCheck;
private Long appointmentTemplateId;
private EvaluationVersionEnum evaluationVersion;
private String companyVatNumber;
private String companyCodiceAteco;
private List<EmailSendResponse> emailSendResponse;
}

View File

@@ -6,6 +6,7 @@ import net.gepafin.tendermanagement.enums.AssignedApplicationEnum;
import net.gepafin.tendermanagement.model.BaseBean; import net.gepafin.tendermanagement.model.BaseBean;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Data @Data
public class AssignedApplicationViewResponse extends BaseBean { public class AssignedApplicationViewResponse extends BaseBean {
@@ -20,5 +21,7 @@ public class AssignedApplicationViewResponse extends BaseBean {
private Long protocolNumber; private Long protocolNumber;
private String callName; private String callName;
private String companyName; private String companyName;
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -0,0 +1,18 @@
package net.gepafin.tendermanagement.model.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmailReminderResponse {
@JsonProperty("emailSendResponse")
private List<EmailSendResponse> emailSendResponse;
}

View File

@@ -0,0 +1,12 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class EmailResendResponseBean {
private EmailSendResponse emailSendResponse;
}

View File

@@ -0,0 +1,11 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum;
@Data
public class EmailSendResponse {
private Boolean isEmailSend;
private Long userActionId;
private EmailScenarioTypeEnum emailScenario;
}

View File

@@ -0,0 +1,15 @@
package net.gepafin.tendermanagement.model.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class InitiatePasswordResetResponse {
private List<EmailSendResponse> emailSendResponse;
}

View File

@@ -48,4 +48,5 @@ public class UserResponseBean extends BaseBean {
private Boolean thirdParty; private Boolean thirdParty;
private String emailPec; private String emailPec;
private List<EmailSendResponse> emailSendResponse;
} }

View File

@@ -3,8 +3,11 @@ package net.gepafin.tendermanagement.model.util;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import net.gepafin.tendermanagement.model.response.LoginResponse; import net.gepafin.tendermanagement.model.response.LoginResponse;
import java.util.List;
/** /**
* JWTToken * JWTToken
*/ */
@@ -15,10 +18,20 @@ public class JWTToken {
@JsonProperty("user") @JsonProperty("user")
private LoginResponse loginResponse; private LoginResponse loginResponse;
@JsonProperty("emailSendResponse")
private List<EmailSendResponse> emailSendResponse;
public JWTToken(String token, LoginResponse loginResponse) { public JWTToken(String token, LoginResponse loginResponse) {
this.token = token; this.token = token;
this.loginResponse = loginResponse; this.loginResponse = loginResponse;
} }
public JWTToken(String token, LoginResponse loginResponse, List<EmailSendResponse> emailSendResponse) {
this.token = token;
this.loginResponse = loginResponse;
this.emailSendResponse = emailSendResponse;
}
} }

View File

@@ -150,4 +150,6 @@ public interface ApplicationAmendmentRequestRepository extends JpaRepository<App
@Query("SELECT COUNT(a) FROM ApplicationAmendmentRequestEntity a WHERE a.applicationId IN :applicationIds AND a.status IN :statuses AND a.isDeleted = false") @Query("SELECT COUNT(a) FROM ApplicationAmendmentRequestEntity a WHERE a.applicationId IN :applicationIds AND a.status IN :statuses AND a.isDeleted = false")
Long countAmendmentsByApplicationIds(@Param("applicationIds") List<Long> applicationIds, @Param("statuses") List<String> statuses); Long countAmendmentsByApplicationIds(@Param("applicationIds") List<Long> applicationIds, @Param("statuses") List<String> statuses);
ApplicationAmendmentRequestEntity findByIdAndIsDeletedFalseAndStatus(Long id,String status);
} }

View File

@@ -80,6 +80,10 @@ public interface ApplicationEvaluationRepository extends JpaRepository<Applicati
Long assignedApplicationId, Long assignedApplicationId,
String status String status
); );
@Query("SELECT ae FROM ApplicationEvaluationEntity ae WHERE ae.applicationId = :applicationId AND ae.isDeleted = false")
ApplicationEvaluationEntity findByApplicationId(@Param("applicationId") Long applicationId);
} }

View File

@@ -1,11 +1,28 @@
package net.gepafin.tendermanagement.repositories; package net.gepafin.tendermanagement.repositories;
import net.gepafin.tendermanagement.entities.EmailLogEntity; import net.gepafin.tendermanagement.entities.EmailLogEntity;
import net.gepafin.tendermanagement.entities.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List; import java.util.List;
import java.util.Optional;
public interface EmailLogRepository extends JpaRepository<EmailLogEntity,Long> { public interface EmailLogRepository extends JpaRepository<EmailLogEntity,Long> {
List<EmailLogEntity> findByUserIdAndAmendmentIdAndIsDeletedFalse(Long userId,Long amendmentId); List<EmailLogEntity> findByUserIdAndAmendmentIdAndIsDeletedFalse(Long userId,Long amendmentId);
List<EmailLogEntity> findByUserActionId(Long userActionId);
List<EmailLogEntity> findByUserActionIdAndEmailServiceTypeAndSendStatus(
Long userActionId, String emailServiceType, String sendStatus);
Optional<EmailLogEntity> findTopByUserIdAndEmailTypeAndIsDeletedFalseOrderByCreatedDateDesc(Long userId, String emailType);
List<EmailLogEntity> findByUserActionIdAndEmailServiceType(
Long userActionId, String emailServiceType);
EmailLogEntity findTopByUserActionIdAndEmailServiceTypeAndSendStatusOrderByIdDesc(
Long userActionId,
String emailServiceType,
String sendStatus
);
} }

View File

@@ -122,7 +122,7 @@ public class ApplicationAmendmentScheduler {
.findEvaluationsWithoutActiveAmendmentsByIds(applicationEvaluationIds); .findEvaluationsWithoutActiveAmendmentsByIds(applicationEvaluationIds);
evaluationsWithoutActiveAmendmentList.forEach(evaluation -> { evaluationsWithoutActiveAmendmentList.forEach(evaluation -> {
try { try {
applicationAmendmentRequestDao.calculateEndDateAndSuspensionDays(evaluation); applicationAmendmentRequestDao.calculateEndDateAndSuspensionDaysOnExpirationOrClosing(evaluation);
updateEvaluationStatus(evaluation); updateEvaluationStatus(evaluation);

View File

@@ -24,6 +24,7 @@ import org.springframework.stereotype.Component;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -87,7 +88,10 @@ public class ApplicationEvaluationScheduler {
evaluation.setStatus(ApplicationEvaluationStatusTypeEnum.EXPIRED.getValue()); evaluation.setStatus(ApplicationEvaluationStatusTypeEnum.EXPIRED.getValue());
evaluation = applicationEvaluationRepository.save(evaluation); evaluation = applicationEvaluationRepository.save(evaluation);
Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_EXPIRED); // Map<String, String> placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_EXPIRED);
Map<String, String> placeHolders = new HashMap<>();
placeHolders.put("{{call_name}}", application.getCall().getName());
placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber()));
notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.EVALUATION_EXPIRED); notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.EVALUATION_EXPIRED);
notificationDao.sendNotificationToInstructor(placeHolders,evaluation,NotificationTypeEnum.EVALUATION_EXPIRED); notificationDao.sendNotificationToInstructor(placeHolders,evaluation,NotificationTypeEnum.EVALUATION_EXPIRED);
notificationDao.sendNotificationToInstructorManager(placeHolders,evaluation,NotificationTypeEnum.EVALUATION_EXPIRED); notificationDao.sendNotificationToInstructorManager(placeHolders,evaluation,NotificationTypeEnum.EVALUATION_EXPIRED);

View File

@@ -8,10 +8,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationAmendmentPagination
import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequest; import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequest;
import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequestBean; import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequestBean;
import net.gepafin.tendermanagement.model.request.CloseAmendmentRequest; import net.gepafin.tendermanagement.model.request.CloseAmendmentRequest;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestViewResponse;
import net.gepafin.tendermanagement.model.response.PageableResponseBean;
import net.gepafin.tendermanagement.model.response.GetAllAmendmentResponseBean;
import java.util.List; import java.util.List;
@@ -29,6 +26,6 @@ public interface ApplicationAmendmentRequestService {
public List<ApplicationAmendmentRequestResponse> getAmendmentByApplicationId(HttpServletRequest request,Long applicationId,List<ApplicationAmendmentRequestEnum> statuses); public List<ApplicationAmendmentRequestResponse> getAmendmentByApplicationId(HttpServletRequest request,Long applicationId,List<ApplicationAmendmentRequestEnum> statuses);
public ApplicationAmendmentRequestResponse updateApplicationAmendmentStatus(HttpServletRequest request, Long applicationAmendmentId, ApplicationAmendmentRequestEnum status); public ApplicationAmendmentRequestResponse updateApplicationAmendmentStatus(HttpServletRequest request, Long applicationAmendmentId, ApplicationAmendmentRequestEnum status);
void sendReminderEmail(HttpServletRequest request,Long amendmentId); EmailReminderResponse sendReminderEmail(HttpServletRequest request, Long amendmentId);
PageableResponseBean<List<ApplicationAmendmentRequestViewResponse>> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean); PageableResponseBean<List<ApplicationAmendmentRequestViewResponse>> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean);
} }

View File

@@ -33,7 +33,7 @@ public interface CallService {
byte[] downloadCallDocumentsAsZip(HttpServletRequest request, Long callId); byte[] downloadCallDocumentsAsZip(HttpServletRequest request, Long callId);
PageableResponseBean<List<CallDetailsResponseBean>> getAllCallsByPagination(HttpServletRequest request, Long companyId , Boolean onlyPreferredCall,CallPageableRequestBean callPageableRequestBean); PageableResponseBean<List<CallDetailsResponseBean>> getAllCallsByPagination(HttpServletRequest request, Long companyId , Boolean onlyPreferredCall,Boolean onlyConfidiCall,CallPageableRequestBean callPageableRequestBean);
CallResponse createCallStep2EvaluationV2(HttpServletRequest request, Long callId, CreateCallRequestStep2EvaluationV2 createCallRequest); CallResponse createCallStep2EvaluationV2(HttpServletRequest request, Long callId, CreateCallRequestStep2EvaluationV2 createCallRequest);

View File

@@ -0,0 +1,9 @@
package net.gepafin.tendermanagement.service;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.model.response.EmailResendResponseBean;
public interface ResendEmailService {
EmailResendResponseBean resendEmail(HttpServletRequest request , Long userActionId);
}

View File

@@ -8,9 +8,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.enums.UserStatusEnum;
import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.request.*;
import net.gepafin.tendermanagement.model.response.PageableResponseBean; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.UserSamlResponse;
import net.gepafin.tendermanagement.model.response.UserResponseBean;
import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.JWTToken;
import java.util.List; import java.util.List;
@@ -28,7 +26,7 @@ public interface UserService {
UserEntity validateUser(Long userId); UserEntity validateUser(Long userId);
void initiatePasswordReset(InitiatePasswordResetReq resetReq); InitiatePasswordResetResponse initiatePasswordReset(InitiatePasswordResetReq resetReq);
Boolean resetPassword(ResetPasswordReq resetPasswordReq); Boolean resetPassword(ResetPasswordReq resetPasswordReq);

View File

@@ -12,10 +12,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationAmendmentPagination
import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequest; import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequest;
import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequestBean; import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequestBean;
import net.gepafin.tendermanagement.model.request.CloseAmendmentRequest; import net.gepafin.tendermanagement.model.request.CloseAmendmentRequest;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestViewResponse;
import net.gepafin.tendermanagement.model.response.PageableResponseBean;
import net.gepafin.tendermanagement.model.response.GetAllAmendmentResponseBean;
import net.gepafin.tendermanagement.repositories.ApplicationAmendmentRequestRepository; import net.gepafin.tendermanagement.repositories.ApplicationAmendmentRequestRepository;
import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository; import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository;
import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService; import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService;
@@ -145,17 +142,18 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm
} }
@Override @Override
public void sendReminderEmail(HttpServletRequest request,Long amendmentId) { public EmailReminderResponse sendReminderEmail(HttpServletRequest request, Long amendmentId) {
ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId) ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId)
.orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND,
Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)));
EmailReminderResponse response = new EmailReminderResponse();
Optional<ApplicationEvaluationEntity> entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId()); Optional<ApplicationEvaluationEntity> entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId());
if (entityOptional.isPresent()) { if (entityOptional.isPresent()) {
UserEntity user = validator.validatePreInstructor(request, entityOptional.get().getUserId()); UserEntity user = validator.validatePreInstructor(request, entityOptional.get().getUserId());
response = applicationAmendmentRequestDao.sendReminderEmail(amendmentId);
applicationAmendmentRequestDao.sendReminderEmail(amendmentId);
} }
return response;
} }
@Override @Override

View File

@@ -11,6 +11,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationEvaluationFormReque
import net.gepafin.tendermanagement.model.request.ApplicationEvaluationRequest; import net.gepafin.tendermanagement.model.request.ApplicationEvaluationRequest;
import net.gepafin.tendermanagement.model.response.ApplicationEvaluationFormResponse; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationFormResponse;
import net.gepafin.tendermanagement.model.response.ApplicationEvaluationResponse; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationResponse;
import net.gepafin.tendermanagement.model.response.ApplicationEvaluationResponseBean;
import net.gepafin.tendermanagement.model.response.ApplicationEvaluationVersionResponse; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationVersionResponse;
import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository; import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository;
import net.gepafin.tendermanagement.service.ApplicationEvaluationService; import net.gepafin.tendermanagement.service.ApplicationEvaluationService;

View File

@@ -15,10 +15,7 @@ import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.enums.*; import net.gepafin.tendermanagement.enums.*;
import net.gepafin.tendermanagement.model.request.LoginReq; import net.gepafin.tendermanagement.model.request.LoginReq;
import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest;
import net.gepafin.tendermanagement.model.response.CompanyResponse; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.LoginResponse;
import net.gepafin.tendermanagement.model.response.RoleResponseBean;
import net.gepafin.tendermanagement.model.response.UserSamlResponse;
import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.JWTToken;
import net.gepafin.tendermanagement.repositories.LoginAttemptRepository; import net.gepafin.tendermanagement.repositories.LoginAttemptRepository;
import net.gepafin.tendermanagement.repositories.SamlResponseRepository; import net.gepafin.tendermanagement.repositories.SamlResponseRepository;
@@ -122,7 +119,7 @@ public class AuthenticationService {
createFailedLoginAttempt(loginAttemptEntity, e.getMessage()); createFailedLoginAttempt(loginAttemptEntity, e.getMessage());
throw e; throw e;
} }
return getJWTTokenBean(user, loginReq.getRememberMe(), loginAttemptEntity.getId()); return getJWTTokenBean(user, loginReq.getRememberMe(), loginAttemptEntity.getId(),null);
} }
public LoginAttemptEntity prepareLoginAttemptEntity(LoginReq loginUserReq, HttpServletRequest request) { public LoginAttemptEntity prepareLoginAttemptEntity(LoginReq loginUserReq, HttpServletRequest request) {
@@ -145,7 +142,7 @@ public class AuthenticationService {
loginAttemptEntity.setErrorMsg(errorMsg); loginAttemptEntity.setErrorMsg(errorMsg);
loginAttemptDao.createLoginAttempt(loginAttemptEntity); loginAttemptDao.createLoginAttempt(loginAttemptEntity);
} }
public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId) { public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId, List<EmailSendResponse> emailSendResponse) {
UserEntity oldUserEntity = Utils.getClonedEntityForData(user); UserEntity oldUserEntity = Utils.getClonedEntityForData(user);
user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
user = userRepository.save(user); user = userRepository.save(user);
@@ -156,7 +153,7 @@ public class AuthenticationService {
LoginResponse loginResponse = getLoginResponse(user, roleResponseBean); LoginResponse loginResponse = getLoginResponse(user, roleResponseBean);
JWTToken jwtToken = new JWTToken(token, loginResponse); JWTToken jwtToken = new JWTToken(token, loginResponse , emailSendResponse);
/** This code is responsible for adding a version history log for the "Create user Or Update user" operation. **/ /** This code is responsible for adding a version history log for the "Create user Or Update user" operation. **/
loggingUtil.addVersionHistoryWithoutToken(VersionHistoryRequest.builder().request(request).oldData(oldUserEntity).newData(user).actionType(VersionActionTypeEnum.UPDATE).build()); loggingUtil.addVersionHistoryWithoutToken(VersionHistoryRequest.builder().request(request).oldData(oldUserEntity).newData(user).actionType(VersionActionTypeEnum.UPDATE).build());
@@ -238,7 +235,7 @@ public class AuthenticationService {
loginAttemptEntity = prepareLoginAttemptEntity(loginReq, request); loginAttemptEntity = prepareLoginAttemptEntity(loginReq, request);
loginAttemptEntity.setUserId(userEntity.getId()); loginAttemptEntity.setUserId(userEntity.getId());
LoginAttemptEntity loginAttempt = createSuccessLoginAttempt(loginAttemptEntity); LoginAttemptEntity loginAttempt = createSuccessLoginAttempt(loginAttemptEntity);
return getJWTTokenBean(userEntity, Boolean.TRUE, loginAttempt.getId()); return getJWTTokenBean(userEntity, Boolean.TRUE, loginAttempt.getId(),null);
} catch (Exception e) { } catch (Exception e) {
log.info("Authentication login failed for email: {}",e.getMessage()); log.info("Authentication login failed for email: {}",e.getMessage());
loginAttemptEntity.setUserId(userId); loginAttemptEntity.setUserId(userId);

View File

@@ -105,9 +105,9 @@ public class CallServiceImpl implements CallService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public PageableResponseBean<List<CallDetailsResponseBean>> getAllCallsByPagination(HttpServletRequest request,Long companyId , Boolean onlyPreferredCall, CallPageableRequestBean callPageableRequestBean) { public PageableResponseBean<List<CallDetailsResponseBean>> getAllCallsByPagination(HttpServletRequest request,Long companyId , Boolean onlyPreferredCall,Boolean onlyConfidiCall, CallPageableRequestBean callPageableRequestBean) {
UserEntity user = validator.validateUser(request); UserEntity user = validator.validateUser(request);
return callDao.getAllCallsByPagination(request,user,companyId,onlyPreferredCall,callPageableRequestBean); return callDao.getAllCallsByPagination(request,user,companyId,onlyPreferredCall,onlyConfidiCall,callPageableRequestBean);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)

View File

@@ -1,25 +1,32 @@
package net.gepafin.tendermanagement.service.impl; package net.gepafin.tendermanagement.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest; import com.mashape.unirest.http.Unirest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.dao.ApplicationDao;
import net.gepafin.tendermanagement.dao.EmailLogDao; import net.gepafin.tendermanagement.dao.EmailLogDao;
import net.gepafin.tendermanagement.entities.EmailLogEntity; import net.gepafin.tendermanagement.dao.NotificationDao;
import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum;
import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum;
import net.gepafin.tendermanagement.enums.NotificationTypeEnum;
import net.gepafin.tendermanagement.enums.StatusTypeEnum; import net.gepafin.tendermanagement.enums.StatusTypeEnum;
import net.gepafin.tendermanagement.model.request.EmailConfig; import net.gepafin.tendermanagement.model.request.EmailConfig;
import net.gepafin.tendermanagement.model.request.EmailLogRequest; import net.gepafin.tendermanagement.model.request.EmailLogRequest;
import net.gepafin.tendermanagement.model.request.NotificationReq;
import net.gepafin.tendermanagement.model.request.PecEmailRequest; import net.gepafin.tendermanagement.model.request.PecEmailRequest;
import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Utils;
import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.util.Validator;
import org.opensaml.xmlsec.signature.G;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Slf4j @Slf4j
@Service @Service
@@ -30,20 +37,26 @@ public class PecEmailService implements EmailService {
@Value("${isPecServiceEnabled}") @Value("${isPecServiceEnabled}")
private String isPecServiceEnabled; private String isPecServiceEnabled;
@Autowired @Autowired
private Validator validator; private Validator validator;
@Autowired @Autowired
private EmailLogDao emailLogDao; private EmailLogDao emailLogDao;
@Autowired
private NotificationDao notificationDao;
@Autowired
private ApplicationDao applicationDao;
@Override @Override
public void sendEmail(String subject, String body, List<String> recipientEmails, EmailConfig emailConfig, EmailLogRequest emailLogRequest) { public void sendEmail(String subject, String body, List<String> recipientEmails, EmailConfig emailConfig, EmailLogRequest emailLogRequest) {
if (Boolean.FALSE.equals(Boolean.parseBoolean(isEmailSendingEnabled))) { if (Boolean.FALSE.equals(Boolean.parseBoolean(isEmailSendingEnabled))) {
return; return;
} }
PecEmailRequest emailRequest = new PecEmailRequest(); PecEmailRequest emailRequest = new PecEmailRequest();
emailRequest.setSender(emailConfig.getSender()); emailRequest.setSender(emailConfig.getSender());
emailRequest.setSubject(subject); emailRequest.setSubject(subject);
@@ -67,13 +80,27 @@ public class PecEmailService implements EmailService {
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.body(Utils.convertObjectToJson(emailRequest)) // Serialize the emailRequest object to JSON .body(Utils.convertObjectToJson(emailRequest)) // Serialize the emailRequest object to JSON
.asString(); .asString();
if (!isSuccessfulPecResponse(response2.getBody())) {
String errorMsg = "PEC sending failed: " + response2.getBody();
emailLogRequest.setSendStatus(StatusTypeEnum.FAILED.getValue());
emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE);
emailLogRequest.setErrorMessage(errorMsg);
sendNotificationOnFailure(emailLogRequest.getUserId(),emailLogRequest.getEmailType());
if (EmailScenarioTypeEnum.APPLICATION_SUBMITTED.equals(emailLogRequest.getEmailType())) {
applicationDao.sendApplicationSubmissionFailureEmail(emailLogRequest);
}
}
} }
}catch(Exception e) { }catch(Exception e) {
emailLogRequest.setSendStatus(StatusTypeEnum.FAILED.getValue()); emailLogRequest.setSendStatus(StatusTypeEnum.FAILED.getValue());
emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE); emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE);
emailLogRequest.setErrorMessage(e.getMessage()); emailLogRequest.setErrorMessage(e.getMessage());
emailLogDao.createEmailLog(emailLogRequest); sendNotificationOnFailure(emailLogRequest.getUserId(),emailLogRequest.getEmailType());
throw new RuntimeException("Failed to send email via PEC: " + response2.getStatus()); if (EmailScenarioTypeEnum.APPLICATION_SUBMITTED.equals(emailLogRequest.getEmailType())) {
applicationDao.sendApplicationSubmissionFailureEmail(emailLogRequest);
}
} }
if(response2 != null) { if(response2 != null) {
emailLogRequest.setEmailServiceResponse(response2.getBody()); emailLogRequest.setEmailServiceResponse(response2.getBody());
@@ -82,6 +109,57 @@ public class PecEmailService implements EmailService {
emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE); emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE);
emailLogDao.createEmailLog(emailLogRequest); emailLogDao.createEmailLog(emailLogRequest);
} }
private void sendNotificationOnFailure(Long userId, EmailScenarioTypeEnum emailScenarioTypeEnum) {
if (userId == null) {
log.warn("Cannot send notification: userId is null.");
return;
}
Map<String, String> placeholders = new HashMap<>();
placeholders.put("{{email_scenario}}", emailScenarioTypeEnum.getValue());
NotificationReq notificationReq = notificationDao.createNotificationReq(
NotificationTypeEnum.PEC_EMAIL_SENDING_FAILURE.getValue(),
placeholders,
userId,
null,
null
);
try {
notificationDao.sendNotification(notificationReq);
log.info("Sent PEC failure notification to user {}", userId);
} catch (Exception e) {
log.error("Failed to send PEC failure notification to user {}: {}", userId, e.getMessage());
}
}
private boolean isSuccessfulPecResponse(String responseBody) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(responseBody);
boolean success = jsonNode.has("success") && jsonNode.get("success").asBoolean();
boolean hasNoError = !jsonNode.has("error") || jsonNode.get("error").isNull();
if (jsonNode.has("success") && !success) {
log.error("PEC response indicates failure: {}", responseBody);
return false;
}
if (responseBody.contains("403") || responseBody.toLowerCase().contains("<html") || responseBody.toLowerCase().contains("<!doctype html>")) {
log.error("PEC response is a 403 HTML Forbidden page or invalid format: {}", responseBody);
return false;
}
return success && hasNoError;
} catch (Exception e) {
log.error("Invalid PEC response format: {}", responseBody);
return false;
}
}
} }

View File

@@ -0,0 +1,25 @@
package net.gepafin.tendermanagement.service.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.dao.EmailDao;
import net.gepafin.tendermanagement.model.response.EmailResendResponseBean;
import net.gepafin.tendermanagement.service.ResendEmailService;
import net.gepafin.tendermanagement.util.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ResendEmailServiceImpl implements ResendEmailService {
@Autowired
Validator validator;
@Autowired
EmailDao emailDao;
@Override
public EmailResendResponseBean resendEmail(HttpServletRequest request, Long userActionId) {
validator.validateUser(request);
return emailDao.resendEmail(request,userActionId);
}
}

View File

@@ -11,9 +11,7 @@ import net.gepafin.tendermanagement.model.request.UpdateUserReq;
import net.gepafin.tendermanagement.model.request.UserReq; import net.gepafin.tendermanagement.model.request.UserReq;
import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.enums.UserStatusEnum;
import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.request.*;
import net.gepafin.tendermanagement.model.response.PageableResponseBean; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.UserSamlResponse;
import net.gepafin.tendermanagement.model.response.UserResponseBean;
import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.JWTToken;
import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.service.UserService;
import net.gepafin.tendermanagement.util.LoggingUtil; import net.gepafin.tendermanagement.util.LoggingUtil;
@@ -78,8 +76,8 @@ public class UserServiceImpl implements UserService {
} }
@Override @Override
public void initiatePasswordReset(InitiatePasswordResetReq resetReq) { public InitiatePasswordResetResponse initiatePasswordReset(InitiatePasswordResetReq resetReq) {
userDao.initiatePasswordReset(resetReq); return userDao.initiatePasswordReset(resetReq);
} }
@Override @Override

View File

@@ -15,6 +15,7 @@ import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -36,9 +37,11 @@ import jakarta.persistence.criteria.Root;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum;
import net.gepafin.tendermanagement.enums.MatchModeEnum; import net.gepafin.tendermanagement.enums.MatchModeEnum;
import net.gepafin.tendermanagement.model.request.FilterCriteria; import net.gepafin.tendermanagement.model.request.FilterCriteria;
import net.gepafin.tendermanagement.model.request.GlobalFilters; import net.gepafin.tendermanagement.model.request.GlobalFilters;
import net.gepafin.tendermanagement.model.response.EmailSendResponse;
import net.gepafin.tendermanagement.web.rest.api.errors.*; import net.gepafin.tendermanagement.web.rest.api.errors.*;
import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder; import net.objecthunter.exp4j.ExpressionBuilder;
@@ -1014,5 +1017,31 @@ public class Utils {
} }
} }
public static List<String> commaSeparatedStringToList(String emails) {
if (emails == null || emails.isEmpty()) {
return new ArrayList<>();
}
return Arrays.stream(emails.split(","))
.map(String::trim)
.collect(Collectors.toList());
}
public static List<EmailSendResponse> mergeEmailSendResponses(List<EmailSendResponse> existingResponses, EmailSendResponse newResponse) {
Map<EmailScenarioTypeEnum, EmailSendResponse> responseMap = Optional.ofNullable(existingResponses)
.orElse(new ArrayList<>())
.stream()
.collect(Collectors.toMap(
EmailSendResponse::getEmailScenario,
Function.identity(),
(oldVal, newVal) -> newVal,
LinkedHashMap::new
));
responseMap.put(newResponse.getEmailScenario(), newResponse);
return new ArrayList<>(responseMap.values());
}
} }

View File

@@ -183,7 +183,7 @@ public interface ApplicationAmendmentRequestApi {
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })) @ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) }))
}) })
@PostMapping(value = "/{amendmentId}/reminder", produces = MediaType.APPLICATION_JSON_VALUE) @PostMapping(value = "/{amendmentId}/reminder", produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<Response<Void>> sendReminderEmail(HttpServletRequest request, ResponseEntity<Response<EmailReminderResponse>> sendReminderEmail(HttpServletRequest request,
@Parameter( required = true) @Parameter( required = true)
@PathVariable(value = "amendmentId") Long amendmentId); @PathVariable(value = "amendmentId") Long amendmentId);

View File

@@ -159,7 +159,7 @@ public interface CallApi {
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = @ExampleObject(value = @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = @ExampleObject(value =
ErrorConstants.BADREQUEST_ERROR_EXAMPLE))) }) ErrorConstants.BADREQUEST_ERROR_EXAMPLE))) })
@PostMapping(value = "/pagination", consumes = "application/json", produces = "application/json") @PostMapping(value = "/pagination", consumes = "application/json", produces = "application/json")
ResponseEntity<Response<PageableResponseBean<List<CallDetailsResponseBean>>>> getAllCallsByPagination(HttpServletRequest request,@RequestParam(value = "companyId", required = false) Long companyId , @RequestParam(value = "onlyPreferredCall", required = false, defaultValue = "false") Boolean onlyPreferredCall, @RequestBody CallPageableRequestBean callPageableRequestBean); ResponseEntity<Response<PageableResponseBean<List<CallDetailsResponseBean>>>> getAllCallsByPagination(HttpServletRequest request,@RequestParam(value = "companyId", required = false) Long companyId , @RequestParam(value = "onlyPreferredCall", required = false, defaultValue = "false") Boolean onlyPreferredCall, @RequestParam(value = "onlyConfidiCall", required = false) Boolean onlyConfidiCall, @RequestBody CallPageableRequestBean callPageableRequestBean);
@Operation(summary = "Api to update call step 2 (Evaluation V2)", @Operation(summary = "Api to update call step 2 (Evaluation V2)",

View File

@@ -0,0 +1,40 @@
package net.gepafin.tendermanagement.web.rest.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import net.gepafin.tendermanagement.model.request.CreateCallRequestStep1;
import net.gepafin.tendermanagement.model.response.CallResponse;
import net.gepafin.tendermanagement.model.response.EmailResendResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@Validated
public interface EmailApi {
@Operation(summary = "Api to resend the email",
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) }))
})
@PostMapping(value = "/resend", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Response<EmailResendResponseBean>> resendEmail(
HttpServletRequest request,
@Parameter(description = "The User Action ID", required = true)
@RequestParam("userActionId") Long userActionId);
}

View File

@@ -10,10 +10,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.enums.UserStatusEnum;
import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.request.*;
import net.gepafin.tendermanagement.model.response.PageableResponseBean; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.SummaryPageResponseBean;
import net.gepafin.tendermanagement.model.response.UserSamlResponse;
import net.gepafin.tendermanagement.model.response.UserResponseBean;
import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.JWTToken;
import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
@@ -121,8 +118,8 @@ public interface UserApi {
@RequestMapping(value = "/reset-password/initiate", @RequestMapping(value = "/reset-password/initiate",
produces = {"application/json"}, produces = {"application/json"},
method = RequestMethod.POST) method = RequestMethod.POST)
ResponseEntity<Response<Void>> initiatePasswordReset(HttpServletRequest request, ResponseEntity<Response<InitiatePasswordResetResponse>> initiatePasswordReset(HttpServletRequest request,
@Parameter(description = "Initiate password reset request object", required = true) @Valid @RequestBody InitiatePasswordResetReq initiatePasswordResetReq); @Parameter(description = "Initiate password reset request object", required = true) @Valid @RequestBody InitiatePasswordResetReq initiatePasswordResetReq);
@Operation(summary = "Api to reset password", @Operation(summary = "Api to reset password",
responses = { responses = {

View File

@@ -8,10 +8,7 @@ import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum;
import net.gepafin.tendermanagement.enums.UserActionContextEnum; import net.gepafin.tendermanagement.enums.UserActionContextEnum;
import net.gepafin.tendermanagement.enums.UserActionLogsEnum; import net.gepafin.tendermanagement.enums.UserActionLogsEnum;
import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.request.*;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestViewResponse;
import net.gepafin.tendermanagement.model.response.PageableResponseBean;
import net.gepafin.tendermanagement.model.response.GetAllAmendmentResponseBean;
import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService; import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService;
import net.gepafin.tendermanagement.util.LoggingUtil; import net.gepafin.tendermanagement.util.LoggingUtil;
@@ -176,15 +173,20 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme
.body(new Response<>(applicationResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_UPDATE_SUCCESSFULLY_MSG))); .body(new Response<>(applicationResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_UPDATE_SUCCESSFULLY_MSG)));
} }
@Override @Override
public ResponseEntity<Response<Void>> sendReminderEmail( public ResponseEntity<Response<EmailReminderResponse>> sendReminderEmail(
HttpServletRequest request, HttpServletRequest request,
Long amendmentId) { Long amendmentId) {
log.info("Sending reminder email for Amendment ID: {}", amendmentId); log.info("Sending reminder email for Amendment ID: {}", amendmentId);
applicationAmendmentRequestService.sendReminderEmail(request,amendmentId);
/** This code is responsible for "sending reminder email" operation. **/
loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.EMAIL)
.actionContext(UserActionContextEnum.SEND_REMINDER_EMAIL).build());
EmailReminderResponse emailSendResponse = applicationAmendmentRequestService.sendReminderEmail(request,amendmentId);
return ResponseEntity.status(HttpStatus.OK) return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.REMINDER_EMAIL_SENT_SUCCESS_MSG))); .body(new Response<>(emailSendResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.REMINDER_EMAIL_SENT_SUCCESS_MSG)));
} }
@Override @Override

View File

@@ -152,12 +152,12 @@ public class CallApiController implements CallApi {
} }
@Override @Override
public ResponseEntity<Response<PageableResponseBean<List<CallDetailsResponseBean>>>> getAllCallsByPagination(HttpServletRequest request, Long companyId , Boolean onlyPreferredCall, CallPageableRequestBean callPageableRequestBean) { public ResponseEntity<Response<PageableResponseBean<List<CallDetailsResponseBean>>>> getAllCallsByPagination(HttpServletRequest request, Long companyId , Boolean onlyPreferredCall,Boolean onlyConfidiCall, CallPageableRequestBean callPageableRequestBean) {
/** This code is responsible for creating user action logs for the "get all call by pagination" operation. **/ /** This code is responsible for creating user action logs for the "get all call by pagination" operation. **/
loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_ALL_CALL_BY_PAGINATION).build()); loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_ALL_CALL_BY_PAGINATION).build());
PageableResponseBean<List<CallDetailsResponseBean>> callsByPagination=callService.getAllCallsByPagination(request,companyId,onlyPreferredCall,callPageableRequestBean); PageableResponseBean<List<CallDetailsResponseBean>> callsByPagination=callService.getAllCallsByPagination(request,companyId,onlyPreferredCall,onlyConfidiCall,callPageableRequestBean);
return ResponseEntity.status(HttpStatus.OK) return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(callsByPagination, Status.SUCCESS, Translator.toLocale(GepafinConstant.CALL_FETCH_SUCCESS_MSG))); .body(new Response<>(callsByPagination, Status.SUCCESS, Translator.toLocale(GepafinConstant.CALL_FETCH_SUCCESS_MSG)));
} }

View File

@@ -0,0 +1,52 @@
package net.gepafin.tendermanagement.web.rest.api.impl;
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.enums.UserActionContextEnum;
import net.gepafin.tendermanagement.enums.UserActionLogsEnum;
import net.gepafin.tendermanagement.model.request.UserActionRequest;
import net.gepafin.tendermanagement.model.response.EmailResendResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.service.ResendEmailService;
import net.gepafin.tendermanagement.util.LoggingUtil;
import net.gepafin.tendermanagement.web.rest.api.EmailApi;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("${openapi.gepafin.base-path:/v1/email}")
@Log4j2
public class EmailApiController implements EmailApi {
@Autowired
LoggingUtil loggingUtil;
@Autowired
ResendEmailService emailService;
@Override
public ResponseEntity<Response<EmailResendResponseBean>> resendEmail(HttpServletRequest request, Long userActionId) {
/** This code is responsible for creating user action logs for the "Resend Email" operation. **/
loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.INSERT)
.actionContext(UserActionContextEnum.RESEND_EMAIL).build());
EmailResendResponseBean emailResendResponseBean = emailService.resendEmail(request, userActionId);
if (!emailResendResponseBean.getEmailSendResponse().getIsEmailSend()) {
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(emailResendResponseBean, Status.EXCEPTION_ERROR, Translator.toLocale(GepafinConstant.RESEND_EMAIL_SENT_FAILED_MSG)));
}
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(emailResendResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.RESEND_EMAIL_SENT_SUCCESS_MSG)));
}
}

View File

@@ -11,9 +11,7 @@ import net.gepafin.tendermanagement.enums.UserActionContextEnum;
import net.gepafin.tendermanagement.enums.UserActionLogsEnum; import net.gepafin.tendermanagement.enums.UserActionLogsEnum;
import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.enums.UserStatusEnum;
import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.request.*;
import net.gepafin.tendermanagement.model.response.PageableResponseBean; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.UserSamlResponse;
import net.gepafin.tendermanagement.model.response.UserResponseBean;
import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.JWTToken;
import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.service.UserService;
@@ -135,16 +133,16 @@ public class UserApiController implements UserApi {
return ResponseEntity.ok(new Response<>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.SUCCESS_PASSWORD_CHANGED))); return ResponseEntity.ok(new Response<>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.SUCCESS_PASSWORD_CHANGED)));
} }
@Override @Override
public ResponseEntity<Response<Void>> initiatePasswordReset(HttpServletRequest httpServletRequest,InitiatePasswordResetReq request) { public ResponseEntity<Response<InitiatePasswordResetResponse>> initiatePasswordReset(HttpServletRequest httpServletRequest, InitiatePasswordResetReq request) {
log.info("Initiating password reset for email: {}", request.getEmail()); log.info("Initiating password reset for email: {}", request.getEmail());
/** This code is responsible for "Initiating Password Reset Request" operation. **/ /** This code is responsible for "Initiating Password Reset Request" operation. **/
loggingUtil.logUserAction(UserActionRequest.builder().request(httpServletRequest).actionType(UserActionLogsEnum.UPDATE) loggingUtil.logUserAction(UserActionRequest.builder().request(httpServletRequest).actionType(UserActionLogsEnum.UPDATE)
.actionContext(UserActionContextEnum.INITIATE_PASSWORD_RESET_REQUEST).build()); .actionContext(UserActionContextEnum.INITIATE_PASSWORD_RESET_REQUEST).build());
userService.initiatePasswordReset(request); InitiatePasswordResetResponse emailSendResponse = userService.initiatePasswordReset(request);
log.info("Password reset token generated for email: {}", request.getEmail()); log.info("Password reset token generated for email: {}", request.getEmail());
return ResponseEntity.ok(new Response<>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.RESET_PASSWORD_INITIATED))); return ResponseEntity.ok(new Response<>(emailSendResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.RESET_PASSWORD_INITIATED)));
} }
@Override @Override

View File

@@ -2653,6 +2653,8 @@
<column name="file_path" value="https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/local/template/PROCURA_BANDI_TEMPLATE_CONFIDI.docx"></column> <column name="file_path" value="https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/local/template/PROCURA_BANDI_TEMPLATE_CONFIDI.docx"></column>
<column name="type" value="DOCUMENT"></column> <column name="type" value="DOCUMENT"></column>
<column name="source" value="DELEGATION_TEMPLATE_CONFIDI"></column> <column name="source" value="DELEGATION_TEMPLATE_CONFIDI"></column>
<column name="created_date" value="2025-05-21 03:00:00"/>
<column name="updated_date" value="2025-05-21 03:00:00"/>
</insert> </insert>
</changeSet> </changeSet>
@@ -2666,12 +2668,16 @@
<column name="file_path" value="https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/local/template/true.png"></column> <column name="file_path" value="https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/local/template/true.png"></column>
<column name="type" value="IMAGE"></column> <column name="type" value="IMAGE"></column>
<column name="source" value="PDF_TRUE"></column> <column name="source" value="PDF_TRUE"></column>
<column name="created_date" value="2025-05-21 03:00:00"/>
<column name="updated_date" value="2025-05-21 03:00:00"/>
</insert> </insert>
<insert tableName="document"> <insert tableName="document">
<column name="file_name" value="GEPAFIN_PDF_FALSE.PNG"></column> <column name="file_name" value="GEPAFIN_PDF_FALSE.PNG"></column>
<column name="file_path" value="https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/local/template/false.png"></column> <column name="file_path" value="https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/local/template/false.png"></column>
<column name="type" value="IMAGE"></column> <column name="type" value="IMAGE"></column>
<column name="source" value="PDF_FALSE"></column> <column name="source" value="PDF_FALSE"></column>
<column name="created_date" value="2025-05-21 03:00:00"/>
<column name="updated_date" value="2025-05-21 03:00:00"/>
</insert> </insert>
</changeSet> </changeSet>
<changeSet id="14-04-2025_RK_161000" author="Rajesh Khore"> <changeSet id="14-04-2025_RK_161000" author="Rajesh Khore">
@@ -2747,6 +2753,60 @@
path="db/dump/update_system_email_template_28_04_2025.sql"/> path="db/dump/update_system_email_template_28_04_2025.sql"/>
</changeSet> </changeSet>
<changeSet id="22-04-2025_PK_192400" author="Piyush Kag">
<sqlFile dbms="postgresql"
path="db/dump/update_json_template_for_notification_22_04_2025.sql"/>
</changeSet>
<changeSet id="24-04-2025_PK_121820" author="Piyush Kag">
<addColumn tableName="email_log">
<column name="user_action_id" type="INTEGER">
<constraints foreignKeyName="fk_email_log_user_action" references="user_action(id)"/>
</column>
</addColumn>
</changeSet>
<changeSet id="30-04-2025_PK_125515" author="Piyush Kag">
<sqlFile dbms="postgresql"
path="db/dump/insert_system_email_template_for_application_submission_failure_30_04_2025.sql"/>
</changeSet>
<changeSet id="06-05-2025_PK_193412" author="Piyush Kag">
<addColumn tableName="application_amendment_request">
<column name="email_send_response" type="TEXT">
<constraints nullable="true"/>
</column>
</addColumn>
<addColumn tableName="application_evaluation">
<column name="email_send_response" type="TEXT">
<constraints nullable="true"/>
</column>
</addColumn>
<addColumn tableName="gepafin_user">
<column name="email_send_response" type="TEXT">
<constraints nullable="true"/>
</column>
</addColumn>
</changeSet>
<changeSet id="07-05-2025_PK_195815" author="Piyush Kag">
<sqlFile dbms="postgresql"
path="db/dump/update_application_amendment_request_view.sql"/>
</changeSet>
<changeSet id="07-05-2025_PK_201518" author="Piyush Kag">
<sqlFile dbms="postgresql"
path="db/dump/update_assigned_application_view.sql"/>
</changeSet>
<changeSet id="08-05-2025_PK_203515" author="Piyush Kag">
<sqlFile dbms="postgresql"
path="db/dump/update_system_email_template_for_application_submission_failure_08_05_2025.sql"/>
</changeSet>
<changeSet id="14-05-2025_NK_163815" author="Nisha Kashyap"> <changeSet id="14-05-2025_NK_163815" author="Nisha Kashyap">
<sqlFile dbms="postgresql" <sqlFile dbms="postgresql"
path="db/dump/update_assigned_application_view_14_5_2025.sql"/> path="db/dump/update_assigned_application_view_14_5_2025.sql"/>

View File

@@ -0,0 +1,46 @@
INSERT INTO gepafin_schema.system_email_template (
template_name,
"type",
html_content,
subject,
"json",
"system",
is_deleted,
created_date,
updated_date,
email_scenario)
VALUES (
'Application submission failure notification',
'APPLICATION_SUBMISSION_FAILURE_NOTIFICATION',
'<html>
<body style="font-family: Arial, sans-serif; color: #333; line-height: 1.6;">
<div style="padding: 20px; border: 1px solid #ddd; border-radius: 8px; max-width: 650px; margin: auto;">
<p>Buongiorno,</p>
<p>
Si prega di notare che si è verificato un errore durante linvio dell email "{{scenario}}" per la chiamata: <strong>{{call_name}}</strong>. </p>
<p>
<strong>Dettagli:</strong><br/>
- ID Applicazione: {{application_id}}<br/>
- Nome Azienda: {{company_name}}<br/>
- Numero Protocollo: {{protocol_number}}<br/>
- ID Azione Utente: {{user_action_id}}
</p>
<p>
Si prega di effettuare i controlli appropriati e di adottare le misure correttive necessarie.
</p>
<p>Cordiali saluti,</p>
<p><strong>Gepafin S.p.a.</strong></p>
</div>
</body>
</html>',
'ERRORE INVIO EMAIL - BANDO {{call_name}}',
NULL,
true,
false,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
'APPLICATION_SUBMISSION_FAILURE'
);

View File

@@ -0,0 +1,27 @@
CREATE OR REPLACE VIEW application_amendment_request_view AS
SELECT a.id,
a.application_id,
p.protocol_number,
cl.name AS call_name,
c.company_name,
a.start_date,
a.end_date AS expiration_date,
COALESCE(NULLIF(TRIM(BOTH FROM concat(COALESCE(u.first_name, ''), ' ', COALESCE(u.last_name, ''))), ''), '') AS assigned_user_name,
aa.user_id AS assigned_user_id,
a.status,
a.note,
a.internal_note,
app.user_id AS application_user_id,
a.created_date,
a.updated_date,
a.is_deleted,
a.email_send_response
FROM gepafin_schema.application_amendment_request a
LEFT JOIN gepafin_schema.application app ON a.application_id = app.id AND (app.is_deleted IS FALSE OR app.is_deleted IS NULL)
LEFT JOIN gepafin_schema.call cl ON app.call_id = cl.id
LEFT JOIN gepafin_schema.company c ON app.company_id = c.id
LEFT JOIN gepafin_schema.protocol p ON a.protocol_id = p.id
LEFT JOIN gepafin_schema.assigned_applications aa ON app.id = aa.application_id AND (aa.is_deleted IS FALSE OR aa.is_deleted IS NULL)
LEFT JOIN gepafin_schema.gepafin_user u ON aa.user_id = u.id
WHERE a.is_deleted IS FALSE OR a.is_deleted IS NULL ORDER BY id;

View File

@@ -0,0 +1,53 @@
CREATE OR REPLACE VIEW assigned_applications_view AS
SELECT
-- From assigned_applications
aa.id AS id,
aa.user_id AS user_id,
aa.status AS status,
aa.created_date AS created_date,
aa.updated_date AS updated_date,
aa.is_deleted AS is_deleted,
-- From application
a.id AS application_id,
a.status AS application_status,
a.submission_date AS submission_date,
ae.end_date AS evaluation_end_date,
a.ndg AS ndg,
a.appointment_id AS appointment_id,
-- From protocol (OneToOne)
p.protocol_number AS protocol_number,
-- From call (ManyToOne)
cl.name AS call_name,
-- From company (ManyToOne)
c.company_name AS company_name,
ae.email_send_response AS email_send_response
FROM gepafin_schema.assigned_applications aa
-- Join application (ManyToOne from assigned_applications)
LEFT JOIN gepafin_schema.application a
ON aa.application_id = a.id
AND (a.is_deleted IS FALSE OR a.is_deleted IS NULL)
-- Join application_evaluation (application_id matches + not deleted)
LEFT JOIN gepafin_schema.application_evaluation ae
ON ae.application_id = a.id
AND (ae.is_deleted IS FALSE OR ae.is_deleted IS NULL)
-- Join protocol (OneToOne from application)
LEFT JOIN gepafin_schema.protocol p
ON a.protocol_number = p.id
-- Join call (ManyToOne from application)
LEFT JOIN gepafin_schema.call cl
ON a.call_id = cl.id
-- Join company (ManyToOne from application)
LEFT JOIN gepafin_schema.company c
ON a.company_id = c.id
WHERE aa.is_deleted IS FALSE OR aa.is_deleted IS NULL;

View File

@@ -0,0 +1,9 @@
INSERT INTO notification_type (notification_name, title, json_template, created_date, updated_date, is_deleted)
VALUES
('PEC_EMAIL_SENDING_FAILURE',
'Invio Email Fallito',
'Non è stato possibile inviare lemail per lo scenario: {{email_scenario}}.',
'2025-01-03T10:16:26.472Z',
'2025-01-03T10:16:26.472Z',
'false'
);

View File

@@ -0,0 +1,29 @@
UPDATE gepafin_schema.system_email_template
SET html_content = '<html>
<body style="font-family: Arial, sans-serif; color: #333; line-height: 1.6;">
<div style="padding: 20px; border: 1px solid #ddd; border-radius: 8px; max-width: 650px; margin: auto;">
<p>Buongiorno,</p>
<p>
<p>
Si prega di notare che si è verificato un errore durante linvio dell e-mail nello scenario "{{scenario}}" per la chiamata: <strong>{{call_name}}</strong>.
</p>
</p>
<p>
<strong>Dettagli:</strong><br/>
- ID Applicazione: {{application_id}}<br/>
- Nome Azienda: {{company_name}}<br/>
- Numero Protocollo: {{protocol_number}}<br/>
- ID Azione Utente: {{user_action_id}}
</p>
<p>Si prega di effettuare i controlli appropriati e di adottare le misure correttive necessarie.</p>
<p>Cordiali saluti,</p>
<p><strong>Gepafin S.p.a.</strong></p>
</div>
</body>
</html>'
WHERE template_name = 'Application submission failure notification';

View File

@@ -400,4 +400,11 @@ insufficient.score.msg = Insufficient score to pass to the technical and economi
password.expired.for.login.to.odessa = Odessa login password has been expired. password.expired.for.login.to.odessa = Odessa login password has been expired.
invalid.user=Invalid user. invalid.user=Invalid user.
application.readmit.success=Application has been readmitted successfully.
reminder.email.sent.failed.msg = Failed to send reminder email
resend.email.sent.success.msg = Email resend successfully
resend.email.sent.failed.msg = Failed to resend the email.
application.readmit.success=Application has been readmitted successfully.
no.email.log.msg = No failed emails found for given userActionId.
user.action.id.not.found = User Action id not found.

View File

@@ -391,4 +391,11 @@ validation.table.message=I dati per il campo {0} non sono presenti.
password.expired.for.login.to.odessa = La password di accesso a Odessa <20> scaduta password.expired.for.login.to.odessa = La password di accesso a Odessa <20> scaduta
invalid.user=Utente non valido. invalid.user=Utente non valido.
reminder.email.sent.failed.msg = Impossibile inviare l'e-mail di promemoria
resend.email.sent.success.msg = Email reinviata con successo
resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail.
application.readmit.success=L'applicazione è stata riammessa con successo. application.readmit.success=L'applicazione è stata riammessa con successo.
no.email.log.msg = Nessuna email trovata per userActionId specificato.
user.action.id.not.found = ID azione utente non trovato.