From 0d7306cf7834d0c03ac549e4ae9e865cf209a13b Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 1 Apr 2025 11:42:19 +0530 Subject: [PATCH 01/63] Fixed call date and time check issue --- .../tendermanagement/dao/ApplicationDao.java | 30 ++++++++++--------- .../gepafin/tendermanagement/dao/CallDao.java | 4 +-- .../tendermanagement/util/DateTimeUtil.java | 11 +++++++ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index d49de7fd..c7592e3e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -941,7 +941,7 @@ public class ApplicationDao { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_IN_PREVIOUS_STATUS)); } if (status.equals(ApplicationStatusTypeEnum.SUBMIT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.READY.getValue()))) { - callService.validatePublishedCall(applicationEntity.getCall().getId(), userEntity.getHub().getId()); +// callService.validatePublishedCall(applicationEntity.getCall().getId(), userEntity.getHub().getId()); Long protocolNumber = protocolDao.getProtocolNumber(userEntity.getHub()); ProtocolEntity protocolEntity = protocolDao.createProtocolEntity(applicationEntity, protocolNumber, userEntity.getHub().getId(),true); applicationEntity.setProtocol(protocolEntity); @@ -1724,19 +1724,21 @@ public class ApplicationDao { public void checkCallEndDate(CallEntity call) { - LocalDateTime now = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); - - LocalDateTime callEndDateTime = LocalDateTime.of( - call.getEndDate().toLocalDate(), - call.getEndTime() - ); - - if (now.isAfter(callEndDateTime)) { - throw new CustomValidationException( - Status.BAD_REQUEST, - Translator.toLocale(GepafinConstant.CALL_EXPIRED) - ); - } + + callService.validatePublishedCall(call.getId(), call.getHub().getId()); +// LocalDateTime now = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); +// +// LocalDateTime callEndDateTime = LocalDateTime.of( +// call.getEndDate().toLocalDate(), +// call.getEndTime() +// ); +// +// if (now.isAfter(callEndDateTime)) { +// throw new CustomValidationException( +// Status.BAD_REQUEST, +// Translator.toLocale(GepafinConstant.CALL_EXPIRED) +// ); +// } } public void calculationProcessForFormula(ApplicationFormEntity applicationFormEntity, List contentResponseBeans, ApplicationFormFieldRequestBean applicationFormFieldRequestBean,FieldValidator fieldValidator) { diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index 86a19a42..7066021f 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -959,8 +959,8 @@ public class CallDao { Status.NOT_FOUND, Translator.toLocale(GepafinConstant.CALL_NOT_PUBLISHED)); } - LocalDate currentDate = LocalDate.now(); - LocalTime currentTime = LocalTime.now(); + LocalDate currentDate = DateTimeUtil.LocalDateServerToEurope(LocalDate.now()); + LocalTime currentTime = DateTimeUtil.LocalTimeServerToEurope(LocalTime.now()); if (currentDate.isBefore(callEntity.getStartDate().toLocalDate()) || (currentDate.isEqual(callEntity.getStartDate().toLocalDate()) && currentTime.isBefore(callEntity.getStartTime()))) { diff --git a/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java b/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java index 1a68818f..87f272c4 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java +++ b/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java @@ -4,6 +4,7 @@ import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationExceptio import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.springframework.stereotype.Component; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; @@ -27,6 +28,16 @@ public class DateTimeUtil { LocalDateTime localDatetime = ldtZoned.withZoneSameInstant(ZoneId.of("Europe/Rome")).toLocalDateTime(); return localDatetime; } + + public static LocalDate LocalDateServerToEurope(LocalDate systemDate) { + ZonedDateTime zonedDateTime = systemDate.atStartOfDay(ZoneId.systemDefault()); + return zonedDateTime.withZoneSameInstant(ZoneId.of("Europe/Rome")).toLocalDate(); + } + + public static LocalTime LocalTimeServerToEurope(LocalTime systemTime) { + ZonedDateTime zonedDateTime = systemTime.atDate(LocalDate.now()).atZone(ZoneId.systemDefault()); + return zonedDateTime.withZoneSameInstant(ZoneId.of("Europe/Rome")).toLocalTime(); + } public static LocalDateTime getPreviousMonthDate(int month) { Calendar c = Calendar.getInstance(); From 51eb7172d3452d23a0f6d4eb5111d96d63f34548 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 1 Apr 2025 18:09:01 +0530 Subject: [PATCH 02/63] Updated code for call exipration --- .../gepafin/tendermanagement/dao/CallDao.java | 56 +++++++------------ .../repositories/CallRepository.java | 5 ++ .../tendermanagement/util/DateTimeUtil.java | 5 -- 3 files changed, 24 insertions(+), 42 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index 7066021f..7b43dc3f 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -796,6 +796,7 @@ public class CallDao { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.COMPANY_ID_REQUIRED_FOR_PREFERRED_CALL)); } + expirePublishedCalls(request); Specification spec = buildCallSpecification(request, user, companyId, onlyPreferredCall, onlyConfidiCall, callStatusList); List calls = callRepository.findAll(spec); @@ -959,7 +960,7 @@ public class CallDao { Status.NOT_FOUND, Translator.toLocale(GepafinConstant.CALL_NOT_PUBLISHED)); } - LocalDate currentDate = DateTimeUtil.LocalDateServerToEurope(LocalDate.now()); + LocalDate currentDate = DateTimeUtil.DateServerToUTC(LocalDateTime.now()).toLocalDate(); LocalTime currentTime = DateTimeUtil.LocalTimeServerToEurope(LocalTime.now()); if (currentDate.isBefore(callEntity.getStartDate().toLocalDate()) || @@ -1000,6 +1001,7 @@ public class CallDao { Translator.toLocale(GepafinConstant.COMPANY_ID_REQUIRED_FOR_PREFERRED_CALL) ); } + expirePublishedCalls(request); Specification spec = search(request,user, callPageableRequestBean); Page entityPage; if (Boolean.TRUE.equals(onlyPreferredCall)) { @@ -1078,7 +1080,6 @@ public class CallDao { private List getPredicates(HttpServletRequest request,CallPageableRequestBean callPageableRequestBean, CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity) { - expirePublishedCalls(request); Integer year = null; String search = null; Map filters = new HashMap<>(); @@ -1162,42 +1163,24 @@ public class CallDao { } public void expirePublishedCalls(HttpServletRequest request) { - List expiredCalls = callRepository.findAll((root, query, criteriaBuilder) -> { - Predicate isPublished = criteriaBuilder.equal(root.get(GepafinConstant.STATUS), CallStatusEnum.PUBLISH.name()); - - // Concatenate date and time as a single string - Expression dateTimeString = criteriaBuilder.concat( - root.get(GepafinConstant.END_DATE), - criteriaBuilder.literal(" ") // Space between date and time - ); - Expression fullDateTimeString = criteriaBuilder.concat(dateTimeString, root.get(GepafinConstant.END_TIME)); - - // Convert the concatenated string into TIMESTAMP - Expression endDateTime = criteriaBuilder.function( - "to_timestamp", - LocalDateTime.class, - fullDateTimeString, - criteriaBuilder.literal("YYYY-MM-DD HH24:MI:SS") - ); - - Predicate isExpired = criteriaBuilder.lessThan(endDateTime, LocalDateTime.now()); - - return criteriaBuilder.and(isPublished, isExpired); - }); - - if (!expiredCalls.isEmpty()) { - for (CallEntity call : expiredCalls) { + + + LocalDate currentDate = DateTimeUtil.DateServerToUTC(LocalDateTime.now()).toLocalDate(); + LocalTime currentTime = DateTimeUtil.LocalTimeServerToEurope(LocalTime.now()); + + List expirdedCallList = callRepository.findExpiredCallsWhichIsPublished(CallStatusEnum.PUBLISH.getValue(), currentDate, currentTime); + + if (!expirdedCallList.isEmpty()) { + + loggingUtil.logUserAction(UserActionRequest.builder() + .request(request) + .actionType(UserActionLogsEnum.UPDATE) + .actionContext(UserActionContextEnum.UPDATE_EXPIRED_CALL) + .build()); + for (CallEntity call : expirdedCallList) { CallEntity oldCallEntity = Utils.getClonedEntityForData(call); // Clone before modification call.setStatus(CallStatusEnum.EXPIRED.getValue()); - if (!oldCallEntity.getStatus().equals(call.getStatus())) { - // Log user action - loggingUtil.logUserAction(UserActionRequest.builder() - .request(request) - .actionType(UserActionLogsEnum.UPDATE) - .actionContext(UserActionContextEnum.UPDATE_EXPIRED_CALL) - .build()); - // Add version history log loggingUtil.addVersionHistory(VersionHistoryRequest.builder() .request(request) @@ -1205,9 +1188,8 @@ public class CallDao { .oldData(oldCallEntity) .newData(call) .build()); - } } - callRepository.saveAll(expiredCalls); // Save all modified calls at once + callRepository.saveAll(expirdedCallList); // Save all modified calls at once } } private void applyFilters(Root root, CriteriaBuilder criteriaBuilder, List predicates, Map filters) { diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/CallRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/CallRepository.java index 5d2bf7f7..98a199d0 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/CallRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/CallRepository.java @@ -7,6 +7,8 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.List; @Repository @@ -58,5 +60,8 @@ public interface CallRepository extends JpaRepository, JpaSpec List findByIdInAndStatusInAndConfidi(@Param("ids") List ids, @Param("status") List status,Boolean confidi); public List findByStatusInAndHubIdAndConfidi(List callStatus, Long hubId,Boolean onlyConfidiCall); + + @Query("SELECT c FROM CallEntity c WHERE c.status = :status AND (FUNCTION('DATE', c.endDate) < :endDate OR (FUNCTION('DATE', c.endDate) = :endDate AND c.endTime <= :endTime))") + List findExpiredCallsWhichIsPublished(@Param("status") String status, @Param("endDate") LocalDate endDate, @Param("endTime") LocalTime endTime); } diff --git a/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java b/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java index 87f272c4..bafd5d6d 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java +++ b/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java @@ -28,11 +28,6 @@ public class DateTimeUtil { LocalDateTime localDatetime = ldtZoned.withZoneSameInstant(ZoneId.of("Europe/Rome")).toLocalDateTime(); return localDatetime; } - - public static LocalDate LocalDateServerToEurope(LocalDate systemDate) { - ZonedDateTime zonedDateTime = systemDate.atStartOfDay(ZoneId.systemDefault()); - return zonedDateTime.withZoneSameInstant(ZoneId.of("Europe/Rome")).toLocalDate(); - } public static LocalTime LocalTimeServerToEurope(LocalTime systemTime) { ZonedDateTime zonedDateTime = systemTime.atDate(LocalDate.now()).atZone(ZoneId.systemDefault()); From 2976984402cca3e53da83e70218485d65f127708 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 24 Mar 2025 19:29:43 +0530 Subject: [PATCH 03/63] Done ticket GEPAFINBE-192 Fixed NDG in-progress response case and updated status code to 200. --- .../config/NdgStatusResetHandler.java | 19 +++++++++++++++++++ .../tendermanagement/dao/AppointmentDao.java | 3 ++- .../repositories/ApplicationRepository.java | 7 +++++++ .../rest/api/impl/AppointmentController.java | 5 ++++- 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/config/NdgStatusResetHandler.java diff --git a/src/main/java/net/gepafin/tendermanagement/config/NdgStatusResetHandler.java b/src/main/java/net/gepafin/tendermanagement/config/NdgStatusResetHandler.java new file mode 100644 index 00000000..0e642669 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/config/NdgStatusResetHandler.java @@ -0,0 +1,19 @@ +package net.gepafin.tendermanagement.config; + +import jakarta.annotation.PostConstruct; +import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.repositories.ApplicationRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class NdgStatusResetHandler { + + @Autowired + private ApplicationRepository applicationRepository; + + @PostConstruct + public void resetNdgStatusOnStartup() { + applicationRepository.resetNdgStatusForInProgress(GepafinConstant.NDG_IN_PROGRESS); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 5a8ee2be..8bb955f4 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -171,8 +171,9 @@ public class AppointmentDao { HubEntity hub = hubRepository.findByHubId(application.getHubId()); loginToOdessa(hub, application); startAsyncNdgProcessing(applicationId); - throw new CustomValidationException(Status.SUCCESS, Translator.toLocale(GepafinConstant.NDG_GENERATION_IS_IN_PROGRESS)); + return ndgResponse; } + private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { try { //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java index 3b817314..b4fdfcaf 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java @@ -1,8 +1,10 @@ package net.gepafin.tendermanagement.repositories; +import jakarta.transaction.Transactional; import net.gepafin.tendermanagement.entities.ApplicationEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -170,4 +172,9 @@ public interface ApplicationRepository extends JpaRepository(appointmentLoginResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.NDG_FETCH_SUCCESSFULLY))); + // Determine the appropriate message + String responseMessage = (appointmentLoginResponse.getNdg() == null) ? Translator.toLocale(GepafinConstant.NDG_GENERATION_IS_IN_PROGRESS) : Translator.toLocale(GepafinConstant.NDG_FETCH_SUCCESSFULLY); + // Return response immediately with 200 OK + return ResponseEntity.status(HttpStatus.OK).body(new Response<>(appointmentLoginResponse, Status.SUCCESS, responseMessage)); } @Override From 1917a853bbda93ebb94595bb849fd038557ea160 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 7 Apr 2025 12:13:32 +0530 Subject: [PATCH 04/63] Done ticket GEPAFINBE-206 Handled the flagDaFirmare flag from the front-end request and removed it from the properties. --- .../net/gepafin/tendermanagement/dao/AppointmentDao.java | 5 +---- src/main/resources/application-dev.properties | 1 - src/main/resources/application-local.properties | 1 - src/main/resources/application-production.properties | 1 - src/main/resources/application-testing.properties | 1 - src/main/resources/application.properties | 2 +- 6 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 8bb955f4..46af8a26 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -96,9 +96,6 @@ public class AppointmentDao { @Value("${aws.s3.bucket.name}") private String OLD_BUCKET; - @Value("${flagDaFirmare}") - private Boolean flagDaFirmare; - @Autowired private HubRepository hubRepository; @@ -963,7 +960,7 @@ public class AppointmentDao { UploadDocToExternalSystemRequest.Input input = new UploadDocToExternalSystemRequest.Input(); input.setIdTipoProtocollo(docToExternalSystemRequest.getInput().getIdTipoProtocollo()); input.setIdClassificazione(docToExternalSystemRequest.getInput().getIdClassificazione()); - input.setFlagDaFirmare(flagDaFirmare); + input.setFlagDaFirmare(docToExternalSystemRequest.getInput().getFlagDaFirmare()); input.setDescrizione(docToExternalSystemRequest.getInput().getDescrizione()); UploadDocToExternalSystemRequest.Input.Attributes attributes = new UploadDocToExternalSystemRequest.Input.Attributes(); diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index fc0e08ce..58295500 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -23,7 +23,6 @@ appointment.portal.user=UtenzaAPIPortal@621 appointment.portal.password=u13nzaAP1P0rtal! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL -flagDaFirmare=false # RabbitMQ properties for STOMP broker relay for Notification #spring.rabbitmq.host=rabbitmq.bflows.ai diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index b67592dc..c49961d5 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -21,7 +21,6 @@ appointment.portal.user=UtenzaAPIPortal@621 appointment.portal.password=u13nzaAP1P0rtal! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL -flagDaFirmare=false # RabbitMQ properties for STOMP broker relay for Notification spring.rabbitmq.host=localhost diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index 30cb6bee..65842ebb 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -30,7 +30,6 @@ appointment.portal.user=UtenzaAPIPortal@621 appointment.portal.password=u13nzaAP1P0rtal! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL -flagDaFirmare=true # RabbitMQ properties for STOMP broker relay for Notification #spring.rabbitmq.host=rabbitmq.bflows.ai diff --git a/src/main/resources/application-testing.properties b/src/main/resources/application-testing.properties index c8e93e85..6fb983e5 100644 --- a/src/main/resources/application-testing.properties +++ b/src/main/resources/application-testing.properties @@ -19,7 +19,6 @@ appointment.portal.user=UtenzaAPIPortal@621 appointment.portal.password=u13nzaAP1P0rtal! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL -flagDaFirmare=false # RabbitMQ properties for STOMP broker relay for Notification spring.rabbitmq.host=rabbitmq.bflows.ai diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3b9bd853..c1cb62c7 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -4,7 +4,7 @@ spring.application.name=tendermanagement spring.servlet.multipart.max-file-size=300MB spring.servlet.multipart.max-request-size=300MB -spring.profiles.active=testing +spring.profiles.active=local # JPA Configuration From cfc9db1d89e5bc75a1792d8b8ff1965aa4e98cfd Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 7 Apr 2025 12:15:08 +0530 Subject: [PATCH 05/63] Updated code. --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c1cb62c7..3b9bd853 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -4,7 +4,7 @@ spring.application.name=tendermanagement spring.servlet.multipart.max-file-size=300MB spring.servlet.multipart.max-request-size=300MB -spring.profiles.active=local +spring.profiles.active=testing # JPA Configuration From f5bee331afab83a0828a6701990ab0df47de807d Mon Sep 17 00:00:00 2001 From: piyushkag Date: Thu, 10 Apr 2025 14:55:08 +0530 Subject: [PATCH 06/63] Fixed automatically publish call issue --- .../java/net/gepafin/tendermanagement/dao/CallDao.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index 7b43dc3f..94c586b9 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -598,8 +598,8 @@ public class CallDao { if (!requestEndDate.equals(storedEndDate)) { // Check if dates are different setIfUpdated(callEntity::getEndDate, callEntity::setEndDate, dates.get(1)); - callEntity.setStatus(CallStatusEnum.PUBLISH.getValue()); - callRepository.save(callEntity); +// callEntity.setStatus(CallStatusEnum.PUBLISH.getValue()); +// callRepository.save(callEntity); isEndDateUpdated = true; } } @@ -611,13 +611,13 @@ public class CallDao { if (!requestEndTime.equals(storedEndTime)) { setIfUpdated(callEntity::getEndTime, callEntity::setEndTime, DateTimeUtil.parseTime(updateCallRequest.getEndTime())); - callEntity.setStatus(CallStatusEnum.PUBLISH.getValue()); - callRepository.save(callEntity); +// callEntity.setStatus(CallStatusEnum.PUBLISH.getValue()); +// callRepository.save(callEntity); isEndTimeUpdated = true; } } if (isEndDateUpdated || isEndTimeUpdated) { - + callRepository.save(callEntity); loggingUtil.logUserAction(UserActionRequest.builder() .request(request) .actionType(UserActionLogsEnum.UPDATE) From e2c19ccafb99bee72f6977fbbd82e2dbb0855664 Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 11 Apr 2025 12:21:25 +0530 Subject: [PATCH 07/63] Done Ticket GEPAFINBE-204 --- .../constants/GepafinConstant.java | 5 + .../dao/AssignedApplicationsDao.java | 110 +++++++++++++----- .../entities/AssignedApplicationsView.java | 61 ++++++++++ .../entities/AssignedApplicationsViewId.java | 17 +++ .../AssignedApplicationsViewRepository.java | 9 ++ .../db/changelog/db.changelog-1.0.0.xml | 6 + .../dump/create_assigned_application_view.sql | 52 +++++++++ 7 files changed, 230 insertions(+), 30 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsViewId.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsViewRepository.java create mode 100644 src/main/resources/db/dump/create_assigned_application_view.sql diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 9ccfe7e5..4371d92f 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -510,6 +510,11 @@ public class GepafinConstant { public static final String INVALID_USER_ID="invalid.user"; public static final String COMPANY_NAME="companyName"; + public static final String APPOINTMENT_ID="appointmentId"; + public static final String APPLICATION_STATUS="applicationStatus"; + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java index 95e808a8..65035e47 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java @@ -20,6 +20,7 @@ import net.gepafin.tendermanagement.model.util.SortBy; import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository; import net.gepafin.tendermanagement.repositories.ApplicationRepository; import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository; +import net.gepafin.tendermanagement.repositories.AssignedApplicationsViewRepository; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.UserService; @@ -77,6 +78,9 @@ public class AssignedApplicationsDao { @Autowired private ApplicationEvaluationRepository applicationEvaluationRepository; + @Autowired + private AssignedApplicationsViewRepository assignedApplicationsViewRepository; + public AssignedApplicationsResponse createAssignedApplications(Long applicationId, Long userId, UserEntity assignedByUser, AssignedApplicationsRequest assignedApplicationsRequest) { log.info("Assigning application to pre-Instructor with details: {}", applicationId, userId); @@ -310,14 +314,13 @@ public class AssignedApplicationsDao { if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } - Specification spec = searchByPagination( assignedApplicationPageableRequestBean, user,userId); - Page entityPage = assignedApplicationsRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); + Specification spec = searchByPagination( assignedApplicationPageableRequestBean, user,userId); + Page entityPage = assignedApplicationsViewRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response - List assignedApplicationsResponses = entityPage.getContent().stream() .map(application -> { - AssignedApplicationsResponse response = convertEntityToResponse(application); + AssignedApplicationsResponse response = getAssignedApplicationResponseByView(application); return response; }) .collect(Collectors.toList()); @@ -334,7 +337,7 @@ public class AssignedApplicationsDao { return pageableResponseBean; } - public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, UserEntity userEntity,Long userId) { + public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, UserEntity userEntity,Long userId) { return (root, query, criteriaBuilder) -> { List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, userEntity,userId); @@ -350,30 +353,35 @@ public class AssignedApplicationsDao { sortBy.setSortDesc(assignedApplicationPageableRequestBean.getGlobalFilters().getSortBy().getSortDesc()); } } - Path sortPath; - Join applicationJoin = root.join(GepafinConstant.APPLICATION, JoinType.LEFT); +// Path sortPath; +// Join applicationJoin = root.join(GepafinConstant.APPLICATION, JoinType.LEFT); +// +// if (GepafinConstant.APPLICATION_ID.equals(sortBy.getColumnName())) { +// sortPath = root.join(GepafinConstant.APPLICATION, JoinType.LEFT).get(GepafinConstant.ID); // Join ApplicationEntity and sort by application.id +// } +// else if (GepafinConstant.PROTOCOL_NUMBER.equals(sortBy.getColumnName())) { +// Join protocolJoin = applicationJoin.join(GepafinConstant.PROTOCOL, JoinType.LEFT); +// sortPath = protocolJoin.get(GepafinConstant.PROTOCOL_NUMBER); +// } +// else { +// sortPath = root.get(sortBy.getColumnName()); // Sorting by a field in AmendmentEntity +// } +// query.orderBy(criteriaBuilder.desc(sortPath)); +// if (Boolean.FALSE.equals(sortBy.getSortDesc())) { +// query.orderBy(criteriaBuilder.asc(sortPath)); +// } +// return query.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))).getRestriction(); + + Path sortPath = root.get(sortBy.getColumnName()); // All fields are accessible directly in the view + query.orderBy(sortBy.getSortDesc() ? criteriaBuilder.desc(sortPath) : criteriaBuilder.asc(sortPath)); - if (GepafinConstant.APPLICATION_ID.equals(sortBy.getColumnName())) { - sortPath = root.join(GepafinConstant.APPLICATION, JoinType.LEFT).get(GepafinConstant.ID); // Join ApplicationEntity and sort by application.id - } - else if (GepafinConstant.PROTOCOL_NUMBER.equals(sortBy.getColumnName())) { - Join protocolJoin = applicationJoin.join(GepafinConstant.PROTOCOL, JoinType.LEFT); - sortPath = protocolJoin.get(GepafinConstant.PROTOCOL_NUMBER); - } - else { - sortPath = root.get(sortBy.getColumnName()); // Sorting by a field in AmendmentEntity - } - query.orderBy(criteriaBuilder.desc(sortPath)); - if (Boolean.FALSE.equals(sortBy.getSortDesc())) { - query.orderBy(criteriaBuilder.asc(sortPath)); - } return query.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))).getRestriction(); }; } private List getPredicates(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, - CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity,Long userId) { + CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity,Long userId) { Integer year = null; String search = null; @@ -404,12 +412,35 @@ public class AssignedApplicationsDao { } // Search in `title` and `message` (if search term is provided) - if (search != null && !search.isEmpty()) { - Predicate titlePredicate = criteriaBuilder.like( - criteriaBuilder.upper(root.get(GepafinConstant.NOTE)), - "%" + search.toUpperCase() + "%" - ); - predicates.add(criteriaBuilder.or(titlePredicate)); +// if (search != null && !search.isEmpty()) { +// Predicate titlePredicate = criteriaBuilder.like( +// criteriaBuilder.upper(root.get(GepafinConstant.NOTE)), +// "%" + search.toUpperCase() + "%" +// ); +// predicates.add(criteriaBuilder.or(titlePredicate)); +// } + + if (search != null && !search.trim().isEmpty()) { + String pattern = "%" + search.toUpperCase() + "%"; + List searchPredicates = new ArrayList<>(); + + searchPredicates.add(criteriaBuilder.like(criteriaBuilder.upper(root.get(GepafinConstant.CALL_NAME)), pattern)); + searchPredicates.add(criteriaBuilder.like(criteriaBuilder.upper(root.get(GepafinConstant.COMPANY_NAME)), pattern)); + searchPredicates.add(criteriaBuilder.like(criteriaBuilder.upper(root.get(GepafinConstant.STATUS)), pattern)); + searchPredicates.add(criteriaBuilder.like(criteriaBuilder.upper(root.get(GepafinConstant.NDG_STRING)), pattern)); + searchPredicates.add(criteriaBuilder.like(criteriaBuilder.upper(root.get(GepafinConstant.APPOINTMENT_ID)), pattern)); + searchPredicates.add(criteriaBuilder.like(criteriaBuilder.upper(root.get(GepafinConstant.APPLICATION_STATUS)), pattern)); + + // Convert numeric fields to string for search (optional and DB-specific; otherwise exact match) + try { + Long searchLong = Long.parseLong(search); + searchPredicates.add(criteriaBuilder.equal(root.get(GepafinConstant.APPLICATION_ID), searchLong)); + searchPredicates.add(criteriaBuilder.equal(root.get(GepafinConstant.PROTOCOL_NUMBER), searchLong)); + } catch (NumberFormatException ignored) { + // Ignore if search is not a number + } + + predicates.add(criteriaBuilder.or(searchPredicates.toArray(new Predicate[0]))); } // Filter by `status` (if status list is provided) @@ -421,12 +452,31 @@ public class AssignedApplicationsDao { } predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); - applyFilters(root, criteriaBuilder, predicates, filters); - + Utils.applyFiltersByPagination(root, criteriaBuilder, predicates, filters); return predicates; } + + private AssignedApplicationsResponse getAssignedApplicationResponseByView(AssignedApplicationsView view) { + AssignedApplicationsResponse response = new AssignedApplicationsResponse(); + response.setId(view.getId()); + response.setUserId(view.getUserId()); + response.setStatus(AssignedApplicationEnum.valueOf(view.getStatus())); + response.setApplicationId(view.getApplicationId()); + response.setApplicationStatus(ApplicationStatusTypeEnum.valueOf(view.getApplicationStatus())); + response.setSubmissionDate(view.getSubmissionDate()); + response.setEvaluationEndDate(view.getEvaluationEndDate()); + response.setNdg(view.getNdg()); + response.setAppointmentId(view.getAppointmentId()); + response.setProtocolNumber(view.getProtocolNumber()); + response.setCallName(view.getCallName()); + response.setCompanyName(view.getCompanyName()); + response.setCreatedDate(view.getCreatedDate()); + response.setUpdatedDate(view.getUpdatedDate()); + return response; + } + public AssignedApplicationsResponse updateAssignedApplicationStatus(HttpServletRequest request, Long assignedApplicationId, AssignedApplicationEnum status) { AssignedApplicationsEntity assignedApplication = validateAssignedApplication(assignedApplicationId); diff --git a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java new file mode 100644 index 00000000..a446daff --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java @@ -0,0 +1,61 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.*; +import lombok.Data; +import org.hibernate.annotations.Immutable; + +import java.time.LocalDateTime; + +@Entity +@Immutable +@Data +@Table(name = "assigned_applications_view") +@IdClass(AssignedApplicationsViewId.class) +public class AssignedApplicationsView{ + + @Id + @Column(name = "ID") + private Long id; + + @Column(name = "APPLICATION_ID") + private Long applicationId; + + @Column(name = "USER_ID") + private Long userId; + + @Column(name = "PROTOCOL_NUMBER") + private Long protocolNumber; + + @Column(name = "CALL_NAME") + private String callName; + + @Column(name = "COMPANY_NAME") + private String companyName; + + @Column(name = "STATUS") + private String status; + + @Column(name = "NDG") + private String ndg; + + @Column(name = "APPOINTMENT_ID") + private String appointmentId; + + @Column(name = "APPLICATION_STATUS") + private String applicationStatus; + + @Column(name = "SUBMISSION_DATE") + private LocalDateTime submissionDate; + + @Column(name = "EVALUATION_END_DATE") + private LocalDateTime evaluationEndDate; + + @Column(name = "CREATED_DATE") + private LocalDateTime createdDate; + + @Column(name = "UPDATED_DATE") + private LocalDateTime updatedDate; + + @Column(name = "IS_DELETED") + private Boolean isDeleted; +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsViewId.java b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsViewId.java new file mode 100644 index 00000000..99c9609c --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsViewId.java @@ -0,0 +1,17 @@ +package net.gepafin.tendermanagement.entities; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class AssignedApplicationsViewId implements Serializable{ + private static final long serialVersionUID = 1L; + private Long id; + + public AssignedApplicationsViewId() {} + + public AssignedApplicationsViewId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsViewRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsViewRepository.java new file mode 100644 index 00000000..231c7d88 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsViewRepository.java @@ -0,0 +1,9 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.AssignedApplicationsView; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface AssignedApplicationsViewRepository extends JpaRepository , JpaSpecificationExecutor { + +} diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index f4e71555..648d76e8 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2722,4 +2722,10 @@ + + + + + diff --git a/src/main/resources/db/dump/create_assigned_application_view.sql b/src/main/resources/db/dump/create_assigned_application_view.sql new file mode 100644 index 00000000..f1900b37 --- /dev/null +++ b/src/main/resources/db/dump/create_assigned_application_view.sql @@ -0,0 +1,52 @@ +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 + +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; From 31cc5ae1ac83fbe31635516ded5060c615e6599a Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 11 Apr 2025 12:57:14 +0530 Subject: [PATCH 08/63] updated code --- .../dao/AssignedApplicationsDao.java | 18 ++++++-------- .../AssignedApplicationViewResponse.java | 24 +++++++++++++++++++ .../service/AssignedApplicationsService.java | 3 ++- .../impl/AssignedApplicationsServiceImpl.java | 3 ++- .../web/rest/api/AssignedApplicationsApi.java | 5 ++-- .../impl/AssignedApplicationsController.java | 9 +++---- 6 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java index 65035e47..17f18c9c 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java @@ -14,6 +14,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationEvaluationRequest; import net.gepafin.tendermanagement.model.request.AssignedApplicationsRequest; import net.gepafin.tendermanagement.model.request.UpdateAssignedApplicationRequest; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; +import net.gepafin.tendermanagement.model.response.AssignedApplicationViewResponse; import net.gepafin.tendermanagement.model.response.AssignedApplicationsResponse; import net.gepafin.tendermanagement.model.response.PageableResponseBean; import net.gepafin.tendermanagement.model.util.SortBy; @@ -301,7 +302,7 @@ public class AssignedApplicationsDao { log.info("Assigned application fetched successfully: {}", response); return response; } - public PageableResponseBean> getAllAssignedApplicationsByPagination(UserEntity user, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean,Long userId) { + public PageableResponseBean> getAllAssignedApplicationsByPagination(UserEntity user, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean,Long userId) { Integer pageNo = null; Integer pageLimit = null; if (assignedApplicationPageableRequestBean.getGlobalFilters() != null) { @@ -318,16 +319,11 @@ public class AssignedApplicationsDao { Page entityPage = assignedApplicationsViewRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response - List assignedApplicationsResponses = entityPage.getContent().stream() - .map(application -> { - AssignedApplicationsResponse response = getAssignedApplicationResponseByView(application); - return response; - }) + List assignedApplicationsResponses = entityPage.getContent().stream() + .map(this::getAssignedApplicationResponseByView) .collect(Collectors.toList()); - - - PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); + PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); pageableResponseBean.setBody(assignedApplicationsResponses); pageableResponseBean.setCurrentPage(entityPage.getNumber() + 1); pageableResponseBean.setTotalPages(entityPage.getTotalPages()); @@ -458,8 +454,8 @@ public class AssignedApplicationsDao { } - private AssignedApplicationsResponse getAssignedApplicationResponseByView(AssignedApplicationsView view) { - AssignedApplicationsResponse response = new AssignedApplicationsResponse(); + private AssignedApplicationViewResponse getAssignedApplicationResponseByView(AssignedApplicationsView view) { + AssignedApplicationViewResponse response = new AssignedApplicationViewResponse(); response.setId(view.getId()); response.setUserId(view.getUserId()); response.setStatus(AssignedApplicationEnum.valueOf(view.getStatus())); diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java new file mode 100644 index 00000000..94c2335a --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java @@ -0,0 +1,24 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; +import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; +import net.gepafin.tendermanagement.model.BaseBean; + +import java.time.LocalDateTime; + +@Data +public class AssignedApplicationViewResponse extends BaseBean { + private Long userId; + private Long applicationId; + private AssignedApplicationEnum status; + private LocalDateTime submissionDate; + private ApplicationStatusTypeEnum applicationStatus; + private LocalDateTime evaluationEndDate; + private String ndg; + private String appointmentId; + private Long protocolNumber; + private String callName; + private String companyName; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/AssignedApplicationsService.java b/src/main/java/net/gepafin/tendermanagement/service/AssignedApplicationsService.java index 6c03d8f4..85a4ec82 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/AssignedApplicationsService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/AssignedApplicationsService.java @@ -7,6 +7,7 @@ import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.model.request.AssignedApplicationsRequest; import net.gepafin.tendermanagement.model.request.UpdateAssignedApplicationRequest; +import net.gepafin.tendermanagement.model.response.AssignedApplicationViewResponse; import net.gepafin.tendermanagement.model.response.AssignedApplicationsResponse; import net.gepafin.tendermanagement.model.response.PageableResponseBean; @@ -23,6 +24,6 @@ public interface AssignedApplicationsService { AssignedApplicationsResponse updateAssignedApplication(HttpServletRequest request, Long id, UpdateAssignedApplicationRequest assignedApplicationsRequest); AssignedApplicationsResponse getAssignedApplicationById(HttpServletRequest request, Long id); AssignedApplicationsEntity validateAssignedApplication(Long assignedApplicationId); - PageableResponseBean> getAllAssignedApplicationsByPagination(HttpServletRequest request, Long userId, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean); + PageableResponseBean> getAllAssignedApplicationsByPagination(HttpServletRequest request, Long userId, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean); AssignedApplicationsResponse updateAssignedApplicationStatus(HttpServletRequest request, Long assignedApplicationId, AssignedApplicationEnum status); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AssignedApplicationsServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AssignedApplicationsServiceImpl.java index 48017b57..b6d67ed2 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AssignedApplicationsServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AssignedApplicationsServiceImpl.java @@ -9,6 +9,7 @@ import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.model.request.AssignedApplicationsRequest; import net.gepafin.tendermanagement.model.request.UpdateAssignedApplicationRequest; +import net.gepafin.tendermanagement.model.response.AssignedApplicationViewResponse; import net.gepafin.tendermanagement.model.response.AssignedApplicationsResponse; import net.gepafin.tendermanagement.model.response.PageableResponseBean; import net.gepafin.tendermanagement.service.AssignedApplicationsService; @@ -66,7 +67,7 @@ public class AssignedApplicationsServiceImpl implements AssignedApplicationsServ } @Override - public PageableResponseBean> getAllAssignedApplicationsByPagination(HttpServletRequest request, Long userId, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean) { + public PageableResponseBean> getAllAssignedApplicationsByPagination(HttpServletRequest request, Long userId, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean) { UserEntity user=validator.validateUser(request); return assignedApplicationsDao.getAllAssignedApplicationsByPagination(user,assignedApplicationPageableRequestBean,userId); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/AssignedApplicationsApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/AssignedApplicationsApi.java index caa2fa32..b3724765 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/AssignedApplicationsApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/AssignedApplicationsApi.java @@ -12,6 +12,7 @@ import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.model.request.AssignedApplicationsRequest; import net.gepafin.tendermanagement.model.request.UpdateAssignedApplicationRequest; import net.gepafin.tendermanagement.model.response.ApplicationResponse; +import net.gepafin.tendermanagement.model.response.AssignedApplicationViewResponse; import net.gepafin.tendermanagement.model.response.AssignedApplicationsResponse; import net.gepafin.tendermanagement.model.response.PageableResponseBean; import net.gepafin.tendermanagement.model.util.Response; @@ -128,8 +129,8 @@ public interface AssignedApplicationsApi { @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) @PostMapping(value = "/pagination", produces = "application/json") - ResponseEntity>>> getAllAssignedApplicationsByPagination(HttpServletRequest request, - @Parameter(description = "The User ID", required = false) @RequestParam(value = "userId",required = false) Long userId, @RequestBody AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean); + ResponseEntity>>> getAllAssignedApplicationsByPagination(HttpServletRequest request, + @Parameter(description = "The User ID", required = false) @RequestParam(value = "userId",required = false) Long userId, @RequestBody AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/AssignedApplicationsController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/AssignedApplicationsController.java index f6487d12..ec5becc7 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/AssignedApplicationsController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/AssignedApplicationsController.java @@ -12,10 +12,7 @@ import net.gepafin.tendermanagement.model.request.AssignedApplicationPageableReq import net.gepafin.tendermanagement.model.request.AssignedApplicationsRequest; import net.gepafin.tendermanagement.model.request.UpdateAssignedApplicationRequest; import net.gepafin.tendermanagement.model.request.UserActionRequest; -import net.gepafin.tendermanagement.model.response.ApplicationResponse; -import net.gepafin.tendermanagement.model.response.AssignedApplicationsResponse; -import net.gepafin.tendermanagement.model.response.NotificationResponse; -import net.gepafin.tendermanagement.model.response.PageableResponseBean; +import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.service.AssignedApplicationsService; import net.gepafin.tendermanagement.util.LoggingUtil; @@ -96,11 +93,11 @@ public class AssignedApplicationsController implements AssignedApplicationsApi { } @Override - public ResponseEntity>>> getAllAssignedApplicationsByPagination(HttpServletRequest request, Long userId, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean) { + public ResponseEntity>>> getAllAssignedApplicationsByPagination(HttpServletRequest request, Long userId, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean) { loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW) .actionContext(UserActionContextEnum.GET_ALL_ASSIGNED_APPLICATION_BY_PAGINATION).build()); - PageableResponseBean> assigenedApplicationResponses=assignedApplicationsService.getAllAssignedApplicationsByPagination(request, userId,assignedApplicationPageableRequestBean); + PageableResponseBean> assigenedApplicationResponses=assignedApplicationsService.getAllAssignedApplicationsByPagination(request, userId,assignedApplicationPageableRequestBean); return ResponseEntity.status(HttpStatus.OK).body(new Response<>(assigenedApplicationResponses, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_ASSIGNED_APPLICATION_SUCCESS_MSG))); } From 5df4987193f1182af09ab577f30ebb6074d7a170 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 14 Apr 2025 16:17:14 +0530 Subject: [PATCH 09/63] Done ticket GEPAFINBE-208 --- .../db/changelog/db.changelog-1.0.0.xml | 5 +- .../update_form_field_data_14_04_2025.sql | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/db/dump/update_form_field_data_14_04_2025.sql diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 648d76e8..ee993774 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2727,5 +2727,8 @@ - + + + diff --git a/src/main/resources/db/dump/update_form_field_data_14_04_2025.sql b/src/main/resources/db/dump/update_form_field_data_14_04_2025.sql new file mode 100644 index 00000000..aba19419 --- /dev/null +++ b/src/main/resources/db/dump/update_form_field_data_14_04_2025.sql @@ -0,0 +1,84 @@ +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Testo Breve"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 1; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Testo Lungo"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 2; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Testo Formattato"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]', + validators = '{"isRequired":false,"minLength":null,"maxLength":null,"custom":null}' +WHERE id = 3; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Numero"},{"name":"placeholder","value":0},{"name":"step","value":0},{"name":"isRequestedAmount","value":false},{"name":"variable","value":[]},{"name":"formula","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 4; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Scelta Singola"},{"name":"options","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 5; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Menu a Tendina"},{"name":"options","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 6; +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Scelta Multipla"},{"name":"options","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 7; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Casella di Spunta"},{"name":"isChecklistItem","value":false},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 8; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Data"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]', + validators = '{"isRequired":false,"custom":null}' +WHERE id = 9; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Caricamento File"},{"name":"mime","value":[]},{"name":"isDelegation","value":false}]', + validators = '{"isRequired":false,"maxSize":100000,"custom":null}' +WHERE id = 10; +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Partita IVA"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 11; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Codice Fiscale"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 12; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"CAP"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 13; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"IBAN"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 14; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Campo Email"},{"name":"placeholder","value":"nome@esempio.it"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 15; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Campo PEC"},{"name":"placeholder","value":"nome@pec.it"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 16; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Indirizzo URL"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 17; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Marca da bollo"},{"name":"placeholder","value":"Numero identificativo"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 18; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Tabella"},{"name":"table_columns","value":{}},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]', + validators = '{"custom":"nonEmptyTables"}' +WHERE id = 20; +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Tabella"},{"name":"criteria_table_columns","value":{}},{"name":"variable","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 21; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Casella di Spunta"},{"name":"isChecklistItem","value":true},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 22; \ No newline at end of file From 809c89deed7d820e511a4f857b1c9845520ead85 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Thu, 17 Apr 2025 12:27:38 +0530 Subject: [PATCH 10/63] Done ticket GEPAFINBE-202 --- pom.xml | 13 +- .../constants/GepafinConstant.java | 23 +- .../tendermanagement/dao/ApplicationDao.java | 339 +++++++++++++++++- .../dao/ApplicationEvaluationDao.java | 2 +- .../entities/ApplicationFormView.java | 118 ++++++ .../entities/ApplicationFormViewId.java | 20 ++ .../ApplicationFormViewRepository.java | 17 + .../ApplicationViewRepository.java | 2 + .../service/ApplicationService.java | 4 + .../service/impl/ApplicationServiceImpl.java | 17 + .../gepafin/tendermanagement/util/Utils.java | 25 ++ .../web/rest/api/ApplicationApi.java | 23 +- .../api/impl/ApplicationApiController.java | 14 +- .../db/changelog/db.changelog-1.0.0.xml | 6 + .../db/dump/create_application_form_view.sql | 125 +++++++ 15 files changed, 730 insertions(+), 18 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java create mode 100644 src/main/resources/db/dump/create_application_form_view.sql diff --git a/pom.xml b/pom.xml index a42534bf..9c84bcc4 100644 --- a/pom.xml +++ b/pom.xml @@ -251,6 +251,13 @@ 0.4.8 + + org.apache.commons + commons-csv + 1.10.0 + + + @@ -271,8 +278,8 @@ liquibase-maven-plugin src/main/resources/application.properties - - - + + + diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 9ccfe7e5..f3878818 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -509,7 +509,28 @@ public class GepafinConstant { public static final String APPLICATION_USER_ID="applicationUserId"; public static final String INVALID_USER_ID="invalid.user"; public static final String COMPANY_NAME="companyName"; - + public static final String TABLE_COLUMNS="table_columns"; + public static final String PREDEFINED="predefined"; + public static final String EBABLE_CSV="enableCsv"; + public static final String LABEL_CSV="labelCsv"; + public static final String GET="get"; + public static final String REPORT_COLUMNS="reportColumns"; + public static final String FIELD_TYPE="fieldtype"; + public static final String ENABLE_FORMULA="enableFormula"; + public static final String STATE_FIELD_DATA="stateFieldData"; + public static final String REPORT_ENABLE="reportEnable"; + public static final String TABLE="table"; + public static final String GET_FIELD_TYPE="getFieldType"; + public static final String GET_APPLICATION_FORM_ID="getApplicationFormId"; + public static final String GET_APPLICATION_ID="getApplicationId"; + public static final String GET_ID="getId"; + public static final String GET_CLASS="getClass"; + public static final String GET_FORM_ID="getFormId"; + public static final String GET_FIELD_ID="getFieldId"; + public static final String GET_FIELD_LABEL="getFieldLabel"; + public static final String GET_FIELD_VALUE="getFieldValue"; + public static final String GET_REPORT_ENABLE="getReportEnable"; + public static final String GET_REPORT_HEADER="getReportHeader"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index a98b3ff9..89a0de69 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -1,10 +1,15 @@ package net.gepafin.tendermanagement.dao; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.itextpdf.text.BaseColor; +import com.itextpdf.text.Font; +import com.itextpdf.text.FontFactory; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.*; +import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; @@ -23,15 +28,14 @@ import net.gepafin.tendermanagement.service.FormService; import net.gepafin.tendermanagement.service.HubService; import net.gepafin.tendermanagement.service.SystemEmailTemplatesService; import net.gepafin.tendermanagement.service.UserService; -import net.gepafin.tendermanagement.util.DateTimeUtil; -import net.gepafin.tendermanagement.util.FieldValidator; -import net.gepafin.tendermanagement.util.LoggingUtil; -import net.gepafin.tendermanagement.util.Utils; -import net.gepafin.tendermanagement.util.Validator; +import net.gepafin.tendermanagement.util.*; 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.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.lang3.StringUtils; import org.h2.util.IOUtils; import org.json.JSONObject; import org.slf4j.Logger; @@ -49,11 +53,15 @@ import jakarta.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Method; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import java.sql.Timestamp; import java.text.MessageFormat; import java.text.NumberFormat; import java.text.ParseException; +import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -196,6 +204,15 @@ public class ApplicationDao { @Autowired private ApplicationViewRepository applicationViewRepository; + @Autowired + private ApplicationFormViewRepository applicationFormViewRepository; + + @Autowired + private FormRepository formRepository; + + @Autowired + private ApplicationEvaluationDao applicationEvaluationDao; + public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) { FormEntity formEntity = formService.validateForm(formId); @@ -1828,4 +1845,316 @@ public class ApplicationDao { responseBean.setDateRejected(applicationView.getDateRejected()); return responseBean; } + + public List getApplicationFormData(Long callId) { + List applicationFormViews=new ArrayList<>(); + + applicationFormViews= applicationFormViewRepository.findByCallId(callId); + + return applicationFormViews; + } + + private List getStaticGetterMethods() { + List excluded = Arrays.asList( + GepafinConstant.GET_FIELD_TYPE,GepafinConstant.GET_APPLICATION_FORM_ID,GepafinConstant.GET_ID,GepafinConstant.GET_CLASS,GepafinConstant.GET_FORM_ID,GepafinConstant.GET_FIELD_ID,GepafinConstant.GET_FIELD_LABEL,GepafinConstant.GET_FIELD_VALUE,GepafinConstant.GET_REPORT_HEADER,GepafinConstant.GET_REPORT_ENABLE + ); + + Method applicationIdMethod = null; + + List methods = new ArrayList<>(); + + for (Method m : ApplicationFormView.class.getMethods()) { + if (m.getName().equals(GepafinConstant.GET_APPLICATION_ID)) { + applicationIdMethod = m; + } else if (m.getName().startsWith(GepafinConstant.GET) && m.getParameterCount() == 0 && !excluded.contains(m.getName())) { + methods.add(m); + } + } + + methods.sort(Comparator.comparing(Method::getName)); // Sort remaining + + if (applicationIdMethod != null) { + methods.add(0, applicationIdMethod); // Add it to the beginning + } + + return methods; + + } + + private String methodToHeader(Method method) { + String name = method.getName().substring(3); // strip "get" + return Arrays.stream(name.split("(?=[A-Z])")) + .map(String::toLowerCase) + .map(word -> Character.toUpperCase(word.charAt(0)) + word.substring(1)) + .collect(Collectors.joining(" ")); + } + + private String invokeGetter(ApplicationFormView view, Method method) { + try { + Object value = method.invoke(view); + if (value == null) return ""; + + String stringValue; + + if (value instanceof LocalDate) { + stringValue = ((LocalDate) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } else if (value instanceof LocalDateTime) { + stringValue = ((LocalDateTime) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } else if (value instanceof Date) { + stringValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) value); + } else { + stringValue = value.toString(); + } + + // Wrap it in ="..." to make Excel treat it as a literal string + return "=\"" + stringValue.replace("\"", "\"\"") + "\""; + + } catch (Exception e) { + return ""; + } + } + + + public byte[] exportCsv(Long callId) { + + List results = getApplicationFormData(callId); + + + Map appInfo = new HashMap<>(); + Map> appFieldValues = new LinkedHashMap<>(); + Set tableFieldIds = new HashSet<>(); + Map fieldIdToLabel = new LinkedHashMap<>(); + + for (ApplicationFormView row : results) { + appInfo.putIfAbsent(row.getApplicationId(), row); + String label=row.getReportHeader(); + if(Boolean.TRUE.equals(StringUtils.isEmpty(label))){ + label=row.getFieldLabel(); + } + fieldIdToLabel.putIfAbsent(row.getFieldId(), label); + + if (GepafinConstant.TABLE.equalsIgnoreCase(row.getFieldType())) { + tableFieldIds.add(row.getFieldId()); + continue; + } + + String value = Optional.ofNullable(row.getFieldValue()) + .map(v -> v.startsWith("\"") && v.endsWith("\"") ? v.substring(1, v.length() - 1) : v) + .orElse(""); + + appFieldValues + .computeIfAbsent(row.getApplicationId(), k -> new LinkedHashMap<>()) + .merge(row.getFieldId(), value, (v1, v2) -> v1.equals(v2) ? v1 : String.join(", ", v1, v2)); + } + + Map> tableHeadersByFieldId = new LinkedHashMap<>(); + Map> tableDataByApp = new HashMap<>(); + prepareTableFieldData(results, tableFieldIds, tableHeadersByFieldId, tableDataByApp); + + // Final header construction + List staticMethods = getStaticGetterMethods(); + List staticHeaders = staticMethods.stream().map(this::methodToHeader).toList(); + + List dynamicHeaders = new ArrayList<>(); + for (String fieldId : fieldIdToLabel.keySet()) { + if (tableHeadersByFieldId.containsKey(fieldId)) { + dynamicHeaders.addAll(tableHeadersByFieldId.get(fieldId)); + } else { + dynamicHeaders.add(fieldIdToLabel.get(fieldId)); + } + } + + List allHeaders = new ArrayList<>(staticHeaders); + allHeaders.addAll(dynamicHeaders); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (CSVPrinter printer = new CSVPrinter(new OutputStreamWriter(out), CSVFormat.DEFAULT.withHeader(allHeaders.toArray(new String[0])))) { + for (Long appId : appFieldValues.keySet()) { + ApplicationFormView appRow = appInfo.get(appId); + Map flatFieldVals = appFieldValues.get(appId); + Map tableVals = tableDataByApp.getOrDefault(appId, Collections.emptyMap()); + + List row = new ArrayList<>(); + for (Method method : staticMethods) { + row.add(invokeGetter(appRow, method)); + } + + for (String fieldId : fieldIdToLabel.keySet()) { + if (tableHeadersByFieldId.containsKey(fieldId)) { + for (String header : tableHeadersByFieldId.get(fieldId)) { + row.add(tableVals.getOrDefault(header, "")); + } + } else { + row.add(flatFieldVals.getOrDefault(fieldId, "")); + } + } + + printer.printRecord(row); + } + + } catch (IOException e) { + throw new RuntimeException("CSV generation failed", e); + } + + return out.toByteArray(); + } + private Map extractTableData(String fieldType, + ContentResponseBean content, String fieldValue) { + + if (content == null) return Map.of(); + + Map result = new LinkedHashMap<>(); + + List> rows = null; + try { + rows = GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(fieldType) + ? Utils.convertJsonToListMap(String.valueOf(PdfUtils.extractRows(fieldValue))) + : Utils.convertJsonToListMap(fieldValue); + } catch (Exception e) { + throw new RuntimeException(e); + } + + Map fieldLabelMap = new LinkedHashMap<>(); + Set predefinedIds = new LinkedHashSet<>(); + Set dynamicIds = new LinkedHashSet<>(); + Set numericFormulaIds = new LinkedHashSet<>(); + + for (SettingResponseBean setting : content.getSettings()) { + String settingName = setting.getName(); + if(settingName.equals(GepafinConstant.REPORT_ENABLE)){ + Boolean enable= (Boolean) setting.getValue(); + if(Boolean.FALSE.equals(enable)){ + return null; + } + } + + if (Boolean.TRUE.equals(GepafinConstant.TABLE_COLUMNS.equals(settingName)) || Boolean.TRUE.equals(GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(settingName))) { + Map valueMap = (Map) setting.getValue(); + if (valueMap == null) continue; + + List> columns = (List>) valueMap.get(GepafinConstant.STATE_FIELD_DATA); + if (columns != null) { + for (Map col : columns) { + String id = String.valueOf(col.get(GepafinConstant.NAME)); + if (Boolean.FALSE.equals(col.get(GepafinConstant.PREDEFINED))) { + if (GepafinConstant.NUMERIC.equals(col.get(GepafinConstant.FIELD_TYPE)) && Boolean.TRUE.equals(col.get(GepafinConstant.ENABLE_FORMULA))) { + numericFormulaIds.add(id); + } + } + } + } + } + + if (Boolean.TRUE.equals(GepafinConstant.REPORT_COLUMNS.equals(settingName))) { + List> reportColumns = (List>) setting.getValue(); + if (reportColumns != null) { + for (Map col : reportColumns) { + Boolean enableCsv = (Boolean) col.get(GepafinConstant.EBABLE_CSV); + if (Boolean.TRUE.equals(enableCsv)) { + String id = String.valueOf(col.get(GepafinConstant.NAME)); + + String fieldCsvLabel = col.get(GepafinConstant.LABEL_CSV) != null + ? String.valueOf(col.get(GepafinConstant.LABEL_CSV)) + : String.valueOf(col.get(GepafinConstant.LABEL)); + + fieldLabelMap.put(id, fieldCsvLabel); + + if (Boolean.TRUE.equals(col.get(GepafinConstant.PREDEFINED))) { + predefinedIds.add(id); + } else { + dynamicIds.add(id); + } + } + } + } + } + } + + + + if (predefinedIds.isEmpty()) { + return null; + } + for (Map row : rows) { + String prefix = predefinedIds.stream() + .map(id -> String.valueOf(row.getOrDefault(id, ""))) + .filter(s -> !s.isBlank()) + .findFirst().orElse(""); + + + for (String dynId : dynamicIds) { + String dynLabel = fieldLabelMap.get(dynId); + for (String preId : predefinedIds.isEmpty() ? List.of("") : predefinedIds) { + String preLabel = fieldLabelMap.get(preId); + String key = dynLabel + " " + (preLabel != null ? preLabel + " " : "") + prefix; + result.put(key, String.valueOf(row.getOrDefault(dynId, ""))); + } + } + } + + // Add totals for numeric formula-enabled columns + for (String dynId : numericFormulaIds) { + double sum = rows.stream() + .mapToDouble(r -> { + try { + return Double.parseDouble(String.valueOf(r.getOrDefault(dynId, "0"))); + } catch (NumberFormatException e) { + return 0.0; + } + }).sum(); + String dynLabel = fieldLabelMap.get(dynId); + result.put("TOTAL " + dynLabel, String.valueOf(sum)); + } + + return result; + } + private void prepareTableFieldData( + List results, + Set tableFieldIds, + Map> tableHeadersByFieldId, + Map> tableDataByApp) { + + if (tableFieldIds.isEmpty()) return; + + Map> groupedByApp = results.stream() + .filter(r -> tableFieldIds.contains(r.getFieldId())) + .collect(Collectors.groupingBy(ApplicationFormView::getApplicationId)); + + for (Map.Entry> entry : groupedByApp.entrySet()) { + Long appId = entry.getKey(); + Map flattenedAll = new LinkedHashMap<>(); + + for (ApplicationFormView row : entry.getValue()) { + formRepository.findById(row.getFormId()).ifPresent(form -> { + List contentList = Utils.convertJsonStringToList(form.getContent(), ContentResponseBean.class); + ContentResponseBean content = contentList.stream() + .filter(c -> c.getId().equals(row.getFieldId())) + .findFirst() + .orElse(null); + + if (content == null) return; + + content.getSettings().stream() + .filter(setting -> GepafinConstant.TABLE_COLUMNS.equals(setting.getName()) + || GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(setting.getName())) + .findFirst() + .ifPresent(setting -> { + Map flattened = extractTableData( + row.getFieldType(), + content, + row.getFieldValue() + ); + if (flattened != null) { + tableHeadersByFieldId.putIfAbsent(row.getFieldId(), new ArrayList<>(flattened.keySet())); + flattenedAll.putAll(flattened); + } + }); + }); + } + + tableDataByApp.put(appId, flattenedAll); + } + } + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 17cac4c4..7052aad0 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -1665,7 +1665,7 @@ public class ApplicationEvaluationDao { }); } - private String getLabelFromSettings(ContentResponseBean contentResponseBean) { + public String getLabelFromSettings(ContentResponseBean contentResponseBean) { String label = contentResponseBean.getLabel(); if (contentResponseBean.getSettings() != null) { for (SettingResponseBean setting : contentResponseBean.getSettings()) { diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java new file mode 100644 index 00000000..b3733afc --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java @@ -0,0 +1,118 @@ +package net.gepafin.tendermanagement.entities; + + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Immutable; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; + +@Entity +@Immutable +@Table(name = "application_form_view") +@Getter +@Setter +@IdClass(ApplicationFormViewId.class) +public class ApplicationFormView { + + @Id + @Column(name = "id") + private Long id; + + @Column(name = "application_id") + private Long applicationId; + + @Column(name = "call_id") + private Long callId; + + @Column(name = "form_id") + private Long formId; + + @Column(name = "application_form_id") + private Long applicationFormId; + + @Column(name = "field_id") + private String fieldId; + + @Column(name = "field_label") + private String fieldLabel; + + @Column(name = "field_type") + private String fieldType; + + @Column(name = "field_value") + private String fieldValue; + + @Column(name = "report_enable") + private Boolean reportEnable; + + @Column(name = "report_header") + private String reportHeader; + + @Column(name = "status") + private String status; + + @Column(name = "amount_requested") + private BigDecimal amountRequested; + + @Column(name = "amount_accepted") + private BigDecimal amountAccepted; + + @Column(name = "is_deleted") + private boolean isDeleted; + + @Column(name = "hub_id") + private Long hubId; + + @Column(name = "user_id") + private Long userId; + + @Column(name = "evaluation_version") + private String evaluationVersion; + + @Column(name = "company_id") + private Long companyId; + + @Column(name = "company_name") + private String companyName; + + @Column(name = "company_vat_number") + private String companyVatNumber; + + @Column(name = "codice_ateco") + private String codiceAteco; + + @Column(name = "company_codice_fiscale") + private String companyCodiceFiscale; + + @Column(name = "protocol_number") + private Long protocolNumber; + + @Column(name = "user_codice_fiscale") + private String userCodiceFiscale; + + @Column(name = "user_name") + private String userName; + + @Column(name = "legal_representative") + private Boolean legalRepresentative; + + @Column(name = "call_title") + private String callTitle; + + @Column(name = "call_end_date") + private LocalDate callEndDate; + + @Column(name = "call_end_time") + private LocalTime callEndTime; + + @Column(name = "call_start_date") + private LocalDate callStartDate; + + @Column(name = "call_start_time") + private LocalTime callStartTime; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java new file mode 100644 index 00000000..37d0cbb7 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java @@ -0,0 +1,20 @@ +package net.gepafin.tendermanagement.entities; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Objects; + +@Data +public class ApplicationFormViewId implements Serializable { + + private static final long serialVersionUID = 1L; + private Long id; + + public ApplicationFormViewId() { + } + + public ApplicationFormViewId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java new file mode 100644 index 00000000..ecfe17c7 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java @@ -0,0 +1,17 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.ApplicationFormView; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ApplicationFormViewRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query("SELECT v FROM ApplicationFormView v WHERE v.callId = :callId AND v.reportEnable = true") + List findByCallId(Long callId); + +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationViewRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationViewRepository.java index da641685..a8d0e90a 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationViewRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationViewRepository.java @@ -3,6 +3,8 @@ package net.gepafin.tendermanagement.repositories; import net.gepafin.tendermanagement.entities.ApplicationView; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; +@Repository public interface ApplicationViewRepository extends JpaRepository , JpaSpecificationExecutor { } diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index 4565668c..24fde801 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -1,6 +1,7 @@ package net.gepafin.tendermanagement.service; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean; import net.gepafin.tendermanagement.model.request.ApplicationRequest; @@ -46,4 +47,7 @@ public interface ApplicationService { PageableResponseBean> getAllApplicationByPagination(HttpServletRequest request, Long callId, Long companyId, ApplicationPageableRequestBean applicationPageableRequestBean); public ApplicationEntity validateApplicationWithCompany(Long applicationId,Long companyId); + + public byte[] exportCsv(HttpServletRequest request, Long callId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index 0c84086b..879c72cf 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -1,11 +1,13 @@ package net.gepafin.tendermanagement.service.impl; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.dao.ApplicationDao; import net.gepafin.tendermanagement.dao.FlowFormDao; import net.gepafin.tendermanagement.entities.ApplicationEntity; +import net.gepafin.tendermanagement.entities.CallEntity; import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean; @@ -15,6 +17,7 @@ import net.gepafin.tendermanagement.enums.FormActionEnum; import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.service.ApplicationService; +import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; @@ -39,6 +42,9 @@ public class ApplicationServiceImpl implements ApplicationService { @Autowired private Validator validator; + @Autowired + private CallService callService; + @Override @Transactional(rollbackFor = Exception.class) public ApplicationResponseBean createApplication(HttpServletRequest request, @@ -154,4 +160,15 @@ public class ApplicationServiceImpl implements ApplicationService { public ApplicationEntity validateApplicationWithCompany(Long applicationId,Long companyId) { return applicationDao.validateApplicationWithCompany(applicationId,companyId); } + + @Override + public byte[] exportCsv(HttpServletRequest request, Long callId) { + UserEntity userEntity = validator.validateUser(request); + CallEntity call=callService.validateCall(callId); + validator.validateHubId(request,call.getHub().getId()); + byte[] csvBytes= applicationDao.exportCsv(callId); + + return csvBytes; + } + } diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index e2e06771..343e742a 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -986,5 +986,30 @@ public class Utils { } } } + public static List> convertJsonToListMap(String jsonString) { + try { + if (jsonString == null || jsonString.trim().isEmpty()) { + return Collections.emptyList(); + } + + ObjectMapper objectMapper = new ObjectMapper(); + String unescaped; + + // First try: parse as if it's double-encoded (escaped string containing a JSON array) + try { + unescaped = objectMapper.readValue(jsonString, String.class); + } catch (Exception e) { + // If that fails, assume it's already a proper JSON array + unescaped = jsonString; + } + + // Now parse the actual JSON array + return objectMapper.readValue(unescaped, new TypeReference>>() {}); + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index 9db1d79e..00609f68 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -2,11 +2,12 @@ package net.gepafin.tendermanagement.web.rest.api; import java.util.List; -import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean; -import net.gepafin.tendermanagement.model.request.NotificationRequestBean; +import jakarta.servlet.http.HttpServletResponse; +import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.response.*; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -18,10 +19,8 @@ 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.ApplicationRequest; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.FormActionEnum; -import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; @@ -224,5 +223,21 @@ public interface ApplicationApi { ResponseEntity>>> getAllApplicationByPagination(HttpServletRequest request,@Parameter(description = "The call id", required = false) @RequestParam(value = "callId", required = false) Long callId, @Parameter(description = "The company id", required = false) @RequestParam(value = "companyId", required = false) Long companyId, @RequestBody ApplicationPageableRequestBean applicationPageableRequestBean); + @Operation(summary = "Api to download application data as a CSV file using the call ID", + 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)})) + }) + @GetMapping(value = "/call/{callId}/csv") + @PreAuthorize("hasRole('ROLE_SUPER_ADMIN')") + public ResponseEntity exportCsv( + HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable(value = "callId", required = true) Long callId); + + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index a9c148bb..a06f5dc4 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -1,16 +1,14 @@ package net.gepafin.tendermanagement.web.rest.api.impl; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; 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.ApplicationPageableRequestBean; -import net.gepafin.tendermanagement.model.request.ApplicationRequest; +import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.FormActionEnum; -import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; -import net.gepafin.tendermanagement.model.request.UserActionRequest; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.service.ApplicationService; @@ -236,5 +234,13 @@ public class ApplicationApiController implements ApplicationApi { .getAllApplicationByPagination(request, callId,companyId,applicationPageableRequestBean); return ResponseEntity.status(HttpStatus.OK).body(new Response<>(pageableResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_APPLICATION_SUCCESS_MSG))); } + @Override + public ResponseEntity exportCsv(HttpServletRequest request, Long callId) { + byte[] csvBytes =applicationService.exportCsv(request,callId); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=applications.csv") + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(csvBytes); + } } diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index f4e71555..c6194504 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2722,4 +2722,10 @@ + + + + diff --git a/src/main/resources/db/dump/create_application_form_view.sql b/src/main/resources/db/dump/create_application_form_view.sql new file mode 100644 index 00000000..b84eaa25 --- /dev/null +++ b/src/main/resources/db/dump/create_application_form_view.sql @@ -0,0 +1,125 @@ +CREATE OR REPLACE VIEW gepafin_schema.application_form_view AS +SELECT app_data.id, + app_data.call_id, + app_data.application_form_id, + app_data.form_id, + app_data.application_id, + field_data.value ->> 'id' AS field_id, + COALESCE( + (SELECT s.value ->> 'value' + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'label' + LIMIT 1), + field_data.value ->> 'label' + ) AS field_label, + ( + SELECT (s.value ->> 'value')::boolean + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'reportEnable' + LIMIT 1 + ) AS report_enable, + COALESCE( (SELECT s.value ->> 'value' + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'reportHeader' + LIMIT 1), + field_data.value ->> 'reportHeader' + ) AS report_header, + field_data.value ->> 'name' AS field_type, + CASE + WHEN field_data.value ->> 'name' = 'fileupload' THEN + to_jsonb(( + SELECT string_agg(d.file_name, ', ') + FROM unnest(string_to_array(app_data.field_value, ',')) file_ids(file_id) + JOIN gepafin_schema.document d ON d.id::text = file_ids.file_id + WHERE d.is_deleted = false + )) + WHEN field_data.value ->> 'name' IN ('checkboxes', 'select', 'radio') THEN + CASE + WHEN app_data.field_value ~~ '[%' THEN + to_jsonb(( + SELECT string_agg(opt.value ->> 'label', ', ') + FROM jsonb_array_elements_text(app_data.field_value::jsonb) selected_id(value) + CROSS JOIN LATERAL ( + SELECT s.value + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'options' + ) options_setting, + LATERAL jsonb_array_elements(options_setting.value -> 'value') opt(value) + WHERE opt.value ->> 'name' = selected_id.value + )) + ELSE + to_jsonb(( + SELECT opt.value ->> 'label' + FROM ( + SELECT s.value + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'options' + ) options_setting, + LATERAL jsonb_array_elements(options_setting.value -> 'value') opt(value) + WHERE opt.value ->> 'name' = app_data.field_value + LIMIT 1 + )) + END + ELSE + to_jsonb(app_data.field_value) + END AS field_value, + app_data.status, + app_data.amount_requested, + app_data.amount_accepted, + app_data.is_deleted, + app_data.hub_id, + app_data.user_id, + app_data.evaluation_version, + app_data.company_id, + c.company_name, + c.vat_number AS company_vat_number, + c.codice_ateco, + c.codice_fiscale AS company_codice_fiscale, + p.protocol_number, + b.codice_fiscale AS user_codice_fiscale, + COALESCE(NULLIF(TRIM(BOTH FROM CONCAT(COALESCE(u.first_name, ''), ' ', COALESCE(u.last_name, ''))), ''), '') AS user_name, + uwc.is_legal_representant AS legal_representative, + cl.name AS call_title, + cl.end_date AS call_end_date, + cl.end_time AS call_end_time, + cl.start_date AS call_start_date, + cl.start_time AS call_start_time +FROM ( + SELECT a.id AS application_id, + a.call_id, + a.protocol_number, + af.id AS application_form_id, + af.form_id AS form_id, + aff.id AS id, + aff.field_value, + a.status, + a.amount_requested, + a.amount_accepted, + a.is_deleted, + a.hub_id, + a.user_id, + a.evaluation_version, + a.created_date, + a.company_id, + aff.field_id, + f.content + FROM gepafin_schema.application a + JOIN gepafin_schema.application_form af ON af.application_id = a.id + JOIN gepafin_schema.application_form_field aff ON aff.application_form_id = af.id + JOIN gepafin_schema.form f ON f.id = af.form_id + WHERE a.is_deleted = false +) app_data +CROSS JOIN LATERAL ( + SELECT jsonb_array_elements.value + FROM jsonb_array_elements(app_data.content::jsonb) jsonb_array_elements(value) + WHERE jsonb_array_elements.value ->> 'id' = app_data.field_id::text +) field_data(value) +LEFT JOIN gepafin_schema.call cl ON app_data.call_id = cl.id +LEFT JOIN gepafin_schema.company c ON app_data.company_id = c.id +LEFT JOIN gepafin_schema.protocol p ON app_data.protocol_number = p.id +LEFT JOIN gepafin_schema.gepafin_user u ON app_data.user_id = u.id +LEFT JOIN gepafin_schema.user_with_company uwc ON app_data.user_id = uwc.user_id AND app_data.company_id = uwc.company_id AND uwc.is_deleted = false +LEFT JOIN gepafin_schema.beneficiary b ON u.beneficiary_id = b.id +WHERE app_data.id IS NOT NULL + AND app_data.status NOT IN ('DRAFT', 'AWAITING', 'READY') +ORDER BY app_data.id, field_data.value ->> 'id'; \ No newline at end of file From 8e1dcecf66c066396a33ac8145278b743dfd26b4 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Fri, 18 Apr 2025 18:48:49 +0530 Subject: [PATCH 11/63] Done ticket GEPAFINBE-199 Implemented the code to send the email to rinaldo from mailgun service like bflows. --- pom.xml | 11 +++ .../constants/GepafinConstant.java | 1 + .../tendermanagement/dao/ApplicationDao.java | 29 ------- .../dao/EmailNotificationDao.java | 21 +++-- .../tendermanagement/dao/NotificationDao.java | 12 +-- .../enums/EmailServiceTypeEnum.java | 3 +- .../service/impl/EmailServiceFactory.java | 16 ++-- .../service/impl/SystemEmailService.java | 83 +++++++++++++++++++ src/main/resources/application.properties | 4 +- 9 files changed, 128 insertions(+), 52 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java diff --git a/pom.xml b/pom.xml index a42534bf..e59892b4 100644 --- a/pom.xml +++ b/pom.xml @@ -251,6 +251,17 @@ 0.4.8 + + + + + + com.sun.mail + jakarta.mail + 2.0.1 + + + diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 9b37da79..c7bf075e 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -505,6 +505,7 @@ public class GepafinConstant { public static final String APPLICATION_ID="applicationId"; public static final String USER_WITH_COMPANY_ID="userWithCompanyId"; + public static final String RINALDO_EMAIL = "rinaldo.bonazzo@bflows.net"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index b63a63fc..e060120e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -1,7 +1,5 @@ package net.gepafin.tendermanagement.dao; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.*; @@ -50,16 +48,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; -import java.sql.Timestamp; import java.text.MessageFormat; -import java.text.NumberFormat; -import java.text.ParseException; -import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,7 +59,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static org.apache.commons.lang3.StringUtils.isEmpty; -import static org.hibernate.validator.internal.engine.messageinterpolation.el.RootResolver.FORMATTER; @Component public class ApplicationDao { @@ -1146,24 +1135,6 @@ public class ApplicationDao { EmailLogRequest emailLogRequest=emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(),RecipientTypeEnum.PROPERTIES,null,userEntity.getEmail(),userEntity.getId(),applicationEntity.getId(),null,applicationEntity.getCall().getId()); -// mailUtil.sendByMailGun(subject, body, List.of(defaultSystemReceiverEmail), null); -// mailUtil.sendByMailGun(subject, body, List.of(gepafinEmail), null); -// mailUtil.sendByMailGun(subject, body, List.of(rinaldoEmail), null); -// if(Boolean.TRUE.equals(hub.getUniqueUuid().equals(defaultHubUuid))) { -// if (validator.isProductionProfileActivated()) { -// emailLogRequest.setRecipientEmails(carloEmail); -//// mailUtil.sendByMailGun(subject, body, List.of(carloEmail), null); -// emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(carloEmail),emailLogRequest); -// } -// List listDefaultSystemReceiverEmail = Arrays.stream(defaultSystemReceiverEmail.split(",")) -// .map(String::trim) -// .filter(email -> !email.isEmpty()) -// .toList(); -// -// emailLogRequest.setRecipientEmails(defaultSystemReceiverEmail); -// emailNotificationDao.sendMail(hub.getId(), subject, body, listDefaultSystemReceiverEmail, emailLogRequest); -// } - List hubEmails = Arrays.stream(hub.getEmail().split(",")) .map(String::trim) .filter(email -> !email.isEmpty()) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index 185d1c62..171ccbfa 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; +import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.RecipientTypeEnum; import net.gepafin.tendermanagement.model.request.EmailConfig; import net.gepafin.tendermanagement.model.request.EmailLogRequest; @@ -15,6 +16,7 @@ import net.gepafin.tendermanagement.service.*; import net.gepafin.tendermanagement.service.impl.EmailService; import net.gepafin.tendermanagement.service.impl.EmailServiceFactory; import net.gepafin.tendermanagement.util.DateTimeUtil; +import net.gepafin.tendermanagement.service.impl.SystemEmailService; import net.gepafin.tendermanagement.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -140,7 +142,9 @@ public class EmailNotificationDao { if (rinaldoEmail != null) { EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(systemEmailTemplateResponse.getEmailScenario(), RecipientTypeEnum.PROPERTIES,null , rinaldoEmail, userEntity.getId(), applicationEntity.getId(), amendmentId, applicationEntity.getCall().getId()); - sendMail(applicationEntity.getHubId(), subject, body, List.of(rinaldoEmail), emailLogRequest); + + //SMTP + sendMail(null, subject, body, List.of(rinaldoEmail), emailLogRequest); } if (applicationEvaluationEntity.isPresent()) { Long preInstructorId = applicationEvaluationEntity.get().getUserId(); // Assuming UserEntity has an email field @@ -275,10 +279,17 @@ public class EmailNotificationDao { public void sendMail(Long hubId, String subject, String body, List recipientEmails, EmailLogRequest emailLogRequest) { - EmailConfig emailConfig = retrieveEmailConfig(hubId); - EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType()); - emailService.sendEmail(subject, body, recipientEmails, emailConfig,emailLogRequest); -// emailService.sendEmail(subject, body, recipientEmails, emailConfig); + EmailConfig emailConfig = new EmailConfig(); + if (recipientEmails.stream().anyMatch(email -> email.equals(GepafinConstant.RINALDO_EMAIL))) { + emailConfig.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE.getValue()); + EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType()); + emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); + } else { + emailConfig = retrieveEmailConfig(hubId); + EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType()); + emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); + + } } public EmailConfig retrieveEmailConfig(Long hubId) { diff --git a/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java index 3a32373c..17b86d6e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java @@ -1,10 +1,8 @@ package net.gepafin.tendermanagement.dao; import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; -import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; @@ -12,7 +10,6 @@ import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.NotificationEnum; import net.gepafin.tendermanagement.enums.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.RoleStatusEnum; -import net.gepafin.tendermanagement.model.request.GlobalFilters; import net.gepafin.tendermanagement.model.request.NotificationReq; import net.gepafin.tendermanagement.model.request.NotificationRequestBean; import net.gepafin.tendermanagement.model.response.NotificationResponse; @@ -28,22 +25,19 @@ import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; -import org.opensaml.xmlsec.signature.G; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isEmpty; @@ -92,7 +86,7 @@ public class NotificationDao { log.info("Sending notification to user {} with content: {}", userId, notificationReq.getMessage()); List companyIds = notificationReq.getCompanyIds(); - if (companyIds == null || companyIds.isEmpty()) { + if (companyIds == null || companyIds.isEmpty() || companyIds.stream().allMatch(Objects::isNull)) { sendToUser(userId, notificationEntity); } else { sendToCompanies(userId, companyIds, notificationEntity); @@ -154,7 +148,7 @@ public class NotificationDao { notificationEntity.setUserId(notificationReq.getUserId()); notificationEntity.setStatus(NotificationEnum.UNREAD.getValue()); notificationEntity.setIsDeleted(Boolean.FALSE); - notificationEntity.setUserWithCompany(notificationReq.getUserWithCompanyEntity() != null ? notificationReq.getUserWithCompanyEntity() : null); + notificationEntity.setUserWithCompany(notificationReq.getUserWithCompanyEntity()); notificationEntity.setMessage(message); notificationEntity.setTitle(notificationReq.getTitle()); return notificationEntity; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/EmailServiceTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/EmailServiceTypeEnum.java index 49c14743..7cf34d0e 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/EmailServiceTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/EmailServiceTypeEnum.java @@ -5,7 +5,8 @@ import com.fasterxml.jackson.annotation.JsonValue; public enum EmailServiceTypeEnum { MAILGUN_SERVICE("MAILGUN_SERVICE"), - PEC_SERVICE("PEC_SERVICE"); + PEC_SERVICE("PEC_SERVICE"), + SYSTEM_EMAIL_SERVICE("SYSTEM_EMAIL_SERVICE"); private String value; diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/EmailServiceFactory.java b/src/main/java/net/gepafin/tendermanagement/service/impl/EmailServiceFactory.java index 6ab6b270..fd8f757b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/EmailServiceFactory.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/EmailServiceFactory.java @@ -12,13 +12,15 @@ public class EmailServiceFactory { @Autowired private MailgunEmailService mailgunEmailService; + @Autowired + private SystemEmailService systemEmailService; + public EmailService getEmailService(String serviceType) { - if ("MAILGUN_SERVICE".equals(serviceType)) { - return mailgunEmailService; - } else if ("PEC_SERVICE".equals(serviceType)) { - return pecEmailService; - } else { - throw new IllegalArgumentException("Invalid email service type: " + serviceType); - } + + return switch (serviceType) { + case "PEC_SERVICE" -> pecEmailService; + case "SYSTEM_EMAIL_SERVICE" -> systemEmailService; + default -> mailgunEmailService; + }; } } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java new file mode 100644 index 00000000..fde6fd3e --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java @@ -0,0 +1,83 @@ +package net.gepafin.tendermanagement.service.impl; + +import com.mailgun.api.v3.MailgunMessagesApi; +import com.mailgun.client.MailgunClient; +import com.mailgun.model.message.MessageResponse; +import net.gepafin.tendermanagement.dao.EmailLogDao; +import net.gepafin.tendermanagement.entities.EmailLogEntity; +import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; +import net.gepafin.tendermanagement.enums.StatusTypeEnum; +import net.gepafin.tendermanagement.model.request.EmailConfig; +import net.gepafin.tendermanagement.model.request.EmailLogRequest; +import net.gepafin.tendermanagement.util.Utils; +import net.gepafin.tendermanagement.util.Validator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class SystemEmailService implements EmailService { + + @Value("${mailGun_user}") + public String mailGunUser; + + @Value("${mailGun_apiKey}") + public String mailGunApiKey; + + @Value("${mailGun_domainName}") + public String mailGunDomainName; + + @Value("${mailGun_base_url}") + public String mailGunBaseUrl; + + @Value("${isMailSendingEnabled}") + private String isEmailSendingEnabled; + + @Autowired + private Validator validator; + + @Autowired + private EmailLogDao emailLogDao; + + public final Logger log = LoggerFactory.getLogger(SystemEmailService.class); + + public void sendEmail(String subject, String body, List recipientEmails, EmailConfig emailConfig, EmailLogRequest emailLogRequest) { + + if (Boolean.FALSE.equals(Boolean.parseBoolean(isEmailSendingEnabled))) { + return; + } + + emailLogRequest.setEmailSubject(subject); + emailLogRequest.setEmailBody(body); + emailLogRequest.setSendStatus(StatusTypeEnum.SUCCESS.getValue()); + emailLogRequest.setRecipientEmails(Utils.listToCommaSeparatedString(recipientEmails)); + + if (Boolean.FALSE.equals(validator.isTestProfileActivated())) { + MessageResponse response = null; + try { + MailgunMessagesApi mailgunMessagesApi = MailgunClient.config(mailGunBaseUrl, mailGunApiKey).createApi(MailgunMessagesApi.class); + + String mailFrom = mailGunUser; + com.mailgun.model.message.Message message = com.mailgun.model.message.Message.builder().from(mailFrom).to(recipientEmails).subject(subject).html(body).build(); + + response = mailgunMessagesApi.sendMessage(mailGunDomainName, message); + } catch (Exception e) { + emailLogRequest.setSendStatus(StatusTypeEnum.FAILED.getValue()); + emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE); + emailLogRequest.setErrorMessage(e.getMessage()); + emailLogDao.createEmailLog(emailLogRequest); + + throw new RuntimeException("Failed to send email via Mailgun: " + (response != null ? response.getMessage() : "No response from Mailgun"), e); + } + emailLogRequest.setEmailServiceResponse(response.toString()); + emailLogDao.createEmailLog(emailLogRequest); + } + } + +} + + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 54498aa1..c9685077 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -55,7 +55,9 @@ active.profile.folder=dev # MailGun API mailGun_base_url=https://api.eu.mailgun.net/ - +mailGun_apiKey= 398e3dea1911fe941af261906ec99362-07e2c238-8094421f +mailGun_user=comunicazione@paghiamoci.ai +mailGun_domainName=paghiamoci.ai api.pecUrl=https://ws.pecmassiva.com #senderEmail=mailer@bflows.net From 50b1b5d5c4e24908d8d0c429c1621f7938d45a1b Mon Sep 17 00:00:00 2001 From: piyushkag Date: Fri, 18 Apr 2025 19:06:27 +0530 Subject: [PATCH 12/63] Updated code. --- src/main/resources/application.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d23905b8..b165e997 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -56,6 +56,7 @@ active.profile.folder=dev # MailGun API mailGun_base_url=https://api.eu.mailgun.net/ +#Below credentials are only for sending mail to rinaldo mailGun_apiKey= 398e3dea1911fe941af261906ec99362-07e2c238-8094421f mailGun_user=comunicazione@paghiamoci.ai mailGun_domainName=paghiamoci.ai From f94cd66d3ba11a0ef1c3c9a0ea0f54a03493ee85 Mon Sep 17 00:00:00 2001 From: Piyush Date: Mon, 28 Apr 2025 17:07:17 +0530 Subject: [PATCH 13/63] Done ticket GEPAFINBE-211 --- .../db/changelog/db.changelog-1.0.0.xml | 10 ++++++++++ ...on_template_for_notification_28_04_2025.sql | 9 +++++++++ ...update_system_email_template_28_04_2025.sql | 7 +++++++ src/main/resources/message_it.properties | 18 +++++++++--------- 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql create mode 100644 src/main/resources/db/dump/update_system_email_template_28_04_2025.sql diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index aed4d0ab..76144c0e 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2737,4 +2737,14 @@ + + + + + + + + diff --git a/src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql b/src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql new file mode 100644 index 00000000..8fe353ef --- /dev/null +++ b/src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql @@ -0,0 +1,9 @@ +UPDATE notification_type +SET + title = regexp_replace(title, 'emendamento', 'soccorso istruttorio', 'gi'), + json_template = regexp_replace(json_template, 'emendamento', 'soccorso istruttorio', 'gi') +WHERE + title ~* 'emendamento' + OR json_template ~* 'emendamento'; + + diff --git a/src/main/resources/db/dump/update_system_email_template_28_04_2025.sql b/src/main/resources/db/dump/update_system_email_template_28_04_2025.sql new file mode 100644 index 00000000..2e6490dd --- /dev/null +++ b/src/main/resources/db/dump/update_system_email_template_28_04_2025.sql @@ -0,0 +1,7 @@ +UPDATE gepafin_schema.system_email_template +SET + html_content = regexp_replace(html_content, 'emendamento', 'Soccorso Istruttorio', 'gi'), + subject = regexp_replace(subject, 'emendamento', 'Soccorso Istruttorio', 'gi') +WHERE + html_content ~* 'emendamento' + OR subject ~* 'emendamento'; diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 6e2352b7..fd7f09e1 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -288,22 +288,22 @@ application.not.in.draft.status=La domanda non ? in stato DRAFT. get.error.s3=Impossibile recuperare il file da S3. application.data.amendment.success = Recupero riuscito dei dati dell'applicazione per il processo di modifica -delete.application.amendment.success =Emendamento all'applicazione eliminato con successo. +delete.application.amendment.success =Soccorso Istruttorio all'applicazione eliminato con successo. application.amendment.not.found = Richiesta di modifica dell'applicazione non trovata con l'ID indicato. application.amendment.get.success = Dettagli della modifica dell'applicazione recuperati correttamente con l'ID fornito. -application.amendment.update.successfully = Emendamento all'applicazione aggiornato con successo. -application.amendment.closed.successfully = Emendamento alla domanda chiuso con successo. +application.amendment.update.successfully = Soccorso Istruttorio all'applicazione aggiornato con successo. +application.amendment.closed.successfully = Soccorso Istruttorio alla domanda chiuso con successo. response.days.extended.success=Giorni di risposta estesi con successo. -added.comment.to.amendment.request.success = Commento aggiunto con successo alla richiesta di emendamento. +added.comment.to.amendment.request.success = Commento aggiunto con successo alla richiesta di soccorso istruttorio. comment.not.found = Commento non trovato. comment.updated.successfully = Commento aggiornato con successo. comment.deleted.successfully = Commento eliminato con successo. -comment.not.associate.with.amendment = Il commento non ? associato alla richiesta di emendamento. -amendment.found.success = Richiesta di emendamento trovata con successo. -invalid.amendment.for.comment = Richiesta di emendamento non valida per il commento fornito. +comment.not.associate.with.amendment = Il commento non ? associato alla richiesta di soccorso istruttorio. +amendment.found.success = Richiesta di soccorso istruttorio trovata con successo. +invalid.amendment.for.comment = Richiesta di soccorso istruttorio non valida per il commento fornito. DD_MM_YYYY_HH_MM = dd_MM_yyyy HH:mm -create.application.data.amendment.msg =Emendamento alla domanda inviato con successo +create.application.data.amendment.msg =soccorso istruttorio alla domanda inviato con successo beneficiary.email.not.found.msg=L'indirizzo email per il beneficiario non ? stato trovato. Si prega di assicurarsi che il beneficiario abbia un indirizzo email valido. reminder.email.sent.success.msg=Email di promemoria inviata con successo! application.documents.not.found=Nessun documento trovato per la domanda. @@ -312,7 +312,7 @@ user.must.be.associated.with.company.to.create.application=Devi essere associato company.id.required.for.preferred.call=ID azienda obbligatorio quando si richiedono solo chiamate preferite. response.days.not.null=I giorni di risposta non devono essere nulli e maggiori di zero. valid.vatnumber.message=Il numero di partita IVA � valido. -application.cannot.approved.or.rejected=La domanda non pu? essere approvata o rifiutata perch? l'emendamento ? attivo. +application.cannot.approved.or.rejected=La domanda non pu? essere approvata o rifiutata perch? Il Soccorso Istruttorio ? attivo. atleast.one.id.required=Almeno uno tra companyId o applicationId deve essere fornito. From 9692988b37d56ec0bebf4d4d8bcabc63344819dd Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 28 Apr 2025 17:45:23 +0530 Subject: [PATCH 14/63] Updated odessa portal password for production. --- src/main/resources/application-production.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index 86ec0f29..c4ad1fe9 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -26,7 +26,7 @@ default.hub.uuid=p4lk3bcx1RStqTaIVVbXs #Login to Odessa, Appointment Creation, Upload document Configuration appointment.base.url=https://prd.galileonetwork.it/gateway/rest appointment.portal.user=UtenzaAPIPortal@621 -appointment.portal.password=u13nzaAP1P0rtal! +appointment.portal.password=Valeria2016!! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL From cfe5df9941eecce96b20b70e74d7ca5c8acbf30f Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 14 Apr 2025 16:17:14 +0530 Subject: [PATCH 15/63] Resolved conflict --- .../db/changelog/db.changelog-1.0.0.xml | 5 +- .../update_form_field_data_14_04_2025.sql | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/db/dump/update_form_field_data_14_04_2025.sql diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 568c4030..82104fcb 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2674,5 +2674,8 @@ - + + + diff --git a/src/main/resources/db/dump/update_form_field_data_14_04_2025.sql b/src/main/resources/db/dump/update_form_field_data_14_04_2025.sql new file mode 100644 index 00000000..aba19419 --- /dev/null +++ b/src/main/resources/db/dump/update_form_field_data_14_04_2025.sql @@ -0,0 +1,84 @@ +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Testo Breve"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 1; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Testo Lungo"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 2; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Testo Formattato"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]', + validators = '{"isRequired":false,"minLength":null,"maxLength":null,"custom":null}' +WHERE id = 3; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Numero"},{"name":"placeholder","value":0},{"name":"step","value":0},{"name":"isRequestedAmount","value":false},{"name":"variable","value":[]},{"name":"formula","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 4; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Scelta Singola"},{"name":"options","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 5; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Menu a Tendina"},{"name":"options","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 6; +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Scelta Multipla"},{"name":"options","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 7; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Casella di Spunta"},{"name":"isChecklistItem","value":false},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 8; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Data"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]', + validators = '{"isRequired":false,"custom":null}' +WHERE id = 9; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Caricamento File"},{"name":"mime","value":[]},{"name":"isDelegation","value":false}]', + validators = '{"isRequired":false,"maxSize":100000,"custom":null}' +WHERE id = 10; +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Partita IVA"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 11; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Codice Fiscale"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 12; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"CAP"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 13; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"IBAN"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 14; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Campo Email"},{"name":"placeholder","value":"nome@esempio.it"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 15; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Campo PEC"},{"name":"placeholder","value":"nome@pec.it"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 16; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Indirizzo URL"},{"name":"placeholder","value":""},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 17; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Marca da bollo"},{"name":"placeholder","value":"Numero identificativo"},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 18; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Tabella"},{"name":"table_columns","value":{}},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]', + validators = '{"custom":"nonEmptyTables"}' +WHERE id = 20; +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Tabella"},{"name":"criteria_table_columns","value":{}},{"name":"variable","value":[]},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 21; + +UPDATE FORM_FIELD +SET settings = '[{"name":"label","value":"Casella di Spunta"},{"name":"isChecklistItem","value":true},{"name":"reportEnable","value":false},{"name":"reportHeader","value":""}]' +WHERE id = 22; \ No newline at end of file From d68644c366c79f9532654764f05fe135a70ca485 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Thu, 17 Apr 2025 12:27:38 +0530 Subject: [PATCH 16/63] Resolved conflict --- pom.xml | 13 +- .../constants/GepafinConstant.java | 30 ++ .../tendermanagement/dao/ApplicationDao.java | 341 +++++++++++++++++- .../dao/ApplicationEvaluationDao.java | 2 +- .../entities/ApplicationFormView.java | 118 ++++++ .../entities/ApplicationFormViewId.java | 20 + .../ApplicationFormViewRepository.java | 17 + .../service/ApplicationService.java | 4 + .../service/impl/ApplicationServiceImpl.java | 16 + .../gepafin/tendermanagement/util/Utils.java | 26 +- .../web/rest/api/ApplicationApi.java | 23 +- .../api/impl/ApplicationApiController.java | 14 +- .../db/changelog/db.changelog-1.0.0.xml | 5 + .../db/dump/create_application_form_view.sql | 125 +++++++ 14 files changed, 731 insertions(+), 23 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java create mode 100644 src/main/resources/db/dump/create_application_form_view.sql diff --git a/pom.xml b/pom.xml index a42534bf..9c84bcc4 100644 --- a/pom.xml +++ b/pom.xml @@ -251,6 +251,13 @@ 0.4.8 + + org.apache.commons + commons-csv + 1.10.0 + + + @@ -271,8 +278,8 @@ liquibase-maven-plugin src/main/resources/application.properties - - - + + + diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index b192fba5..4f15580c 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -499,6 +499,36 @@ public class GepafinConstant { public static final String PASSWORD_EXPIRED = "PasswordExpired"; public static final String PASSWORD_EXPIRED_LOGIN_TO_ODESSA = "password.expired.for.login.to.odessa"; + + public static final String APPLICATION="application"; + public static final String APPLICATION_ID="applicationId"; + public static final String USER_WITH_COMPANY_ID="userWithCompanyId"; + public static final String ASSIGNED_USER_ID="assignedUserId"; + public static final String APPLICATION_USER_ID="applicationUserId"; + public static final String INVALID_USER_ID="invalid.user"; + public static final String COMPANY_NAME="companyName"; + public static final String TABLE_COLUMNS="table_columns"; + public static final String PREDEFINED="predefined"; + public static final String EBABLE_CSV="enableCsv"; + public static final String LABEL_CSV="labelCsv"; + public static final String GET="get"; + public static final String REPORT_COLUMNS="reportColumns"; + public static final String FIELD_TYPE="fieldtype"; + public static final String ENABLE_FORMULA="enableFormula"; + public static final String STATE_FIELD_DATA="stateFieldData"; + public static final String REPORT_ENABLE="reportEnable"; + public static final String TABLE="table"; + public static final String GET_FIELD_TYPE="getFieldType"; + public static final String GET_APPLICATION_FORM_ID="getApplicationFormId"; + public static final String GET_APPLICATION_ID="getApplicationId"; + public static final String GET_ID="getId"; + public static final String GET_CLASS="getClass"; + public static final String GET_FORM_ID="getFormId"; + public static final String GET_FIELD_ID="getFieldId"; + public static final String GET_FIELD_LABEL="getFieldLabel"; + public static final String GET_FIELD_VALUE="getFieldValue"; + public static final String GET_REPORT_ENABLE="getReportEnable"; + public static final String GET_REPORT_HEADER="getReportHeader"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index c7592e3e..d6b66527 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -1,10 +1,15 @@ package net.gepafin.tendermanagement.dao; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.itextpdf.text.BaseColor; +import com.itextpdf.text.Font; +import com.itextpdf.text.FontFactory; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.*; +import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; @@ -23,15 +28,14 @@ import net.gepafin.tendermanagement.service.FormService; import net.gepafin.tendermanagement.service.HubService; import net.gepafin.tendermanagement.service.SystemEmailTemplatesService; import net.gepafin.tendermanagement.service.UserService; -import net.gepafin.tendermanagement.util.DateTimeUtil; -import net.gepafin.tendermanagement.util.FieldValidator; -import net.gepafin.tendermanagement.util.LoggingUtil; -import net.gepafin.tendermanagement.util.Utils; -import net.gepafin.tendermanagement.util.Validator; +import net.gepafin.tendermanagement.util.*; 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.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.lang3.StringUtils; import org.h2.util.IOUtils; import org.json.JSONObject; import org.slf4j.Logger; @@ -49,17 +53,17 @@ import jakarta.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Method; import java.math.BigDecimal; + import java.sql.Timestamp; import java.text.MessageFormat; -import java.text.NumberFormat; -import java.text.ParseException; +import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,7 +73,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static org.apache.commons.lang3.StringUtils.isEmpty; -import static org.hibernate.validator.internal.engine.messageinterpolation.el.RootResolver.FORMATTER; @Component public class ApplicationDao { @@ -195,6 +198,15 @@ public class ApplicationDao { @Autowired private ApplicationEvaluationRepository applicationEvaluationRepository; + @Autowired + private ApplicationFormViewRepository applicationFormViewRepository; + + @Autowired + private FormRepository formRepository; + + @Autowired + private ApplicationEvaluationDao applicationEvaluationDao; + public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) { FormEntity formEntity = formService.validateForm(formId); @@ -1878,4 +1890,313 @@ public class ApplicationDao { } return application; } + public List getApplicationFormData(Long callId) { + List applicationFormViews=new ArrayList<>(); + + applicationFormViews= applicationFormViewRepository.findByCallId(callId); + + return applicationFormViews; + } + + private List getStaticGetterMethods() { + List excluded = Arrays.asList( + GepafinConstant.GET_FIELD_TYPE,GepafinConstant.GET_APPLICATION_FORM_ID,GepafinConstant.GET_ID,GepafinConstant.GET_CLASS,GepafinConstant.GET_FORM_ID,GepafinConstant.GET_FIELD_ID,GepafinConstant.GET_FIELD_LABEL,GepafinConstant.GET_FIELD_VALUE,GepafinConstant.GET_REPORT_HEADER,GepafinConstant.GET_REPORT_ENABLE + ); + + Method applicationIdMethod = null; + + List methods = new ArrayList<>(); + + for (Method m : ApplicationFormView.class.getMethods()) { + if (m.getName().equals(GepafinConstant.GET_APPLICATION_ID)) { + applicationIdMethod = m; + } else if (m.getName().startsWith(GepafinConstant.GET) && m.getParameterCount() == 0 && !excluded.contains(m.getName())) { + methods.add(m); + } + } + + methods.sort(Comparator.comparing(Method::getName)); // Sort remaining + + if (applicationIdMethod != null) { + methods.add(0, applicationIdMethod); // Add it to the beginning + } + + return methods; + + } + + private String methodToHeader(Method method) { + String name = method.getName().substring(3); // strip "get" + return Arrays.stream(name.split("(?=[A-Z])")) + .map(String::toLowerCase) + .map(word -> Character.toUpperCase(word.charAt(0)) + word.substring(1)) + .collect(Collectors.joining(" ")); + } + + private String invokeGetter(ApplicationFormView view, Method method) { + try { + Object value = method.invoke(view); + if (value == null) return ""; + + String stringValue; + + if (value instanceof LocalDate) { + stringValue = ((LocalDate) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } else if (value instanceof LocalDateTime) { + stringValue = ((LocalDateTime) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } else if (value instanceof Date) { + stringValue = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) value); + } else { + stringValue = value.toString(); + } + + // Wrap it in ="..." to make Excel treat it as a literal string + return "=\"" + stringValue.replace("\"", "\"\"") + "\""; + + } catch (Exception e) { + return ""; + } + } + + + public byte[] exportCsv(Long callId) { + + List results = getApplicationFormData(callId); + + + Map appInfo = new HashMap<>(); + Map> appFieldValues = new LinkedHashMap<>(); + Set tableFieldIds = new HashSet<>(); + Map fieldIdToLabel = new LinkedHashMap<>(); + + for (ApplicationFormView row : results) { + appInfo.putIfAbsent(row.getApplicationId(), row); + String label=row.getReportHeader(); + if(Boolean.TRUE.equals(StringUtils.isEmpty(label))){ + label=row.getFieldLabel(); + } + fieldIdToLabel.putIfAbsent(row.getFieldId(), label); + + if (GepafinConstant.TABLE.equalsIgnoreCase(row.getFieldType())) { + tableFieldIds.add(row.getFieldId()); + continue; + } + + String value = Optional.ofNullable(row.getFieldValue()) + .map(v -> v.startsWith("\"") && v.endsWith("\"") ? v.substring(1, v.length() - 1) : v) + .orElse(""); + + appFieldValues + .computeIfAbsent(row.getApplicationId(), k -> new LinkedHashMap<>()) + .merge(row.getFieldId(), value, (v1, v2) -> v1.equals(v2) ? v1 : String.join(", ", v1, v2)); + } + + Map> tableHeadersByFieldId = new LinkedHashMap<>(); + Map> tableDataByApp = new HashMap<>(); + prepareTableFieldData(results, tableFieldIds, tableHeadersByFieldId, tableDataByApp); + + // Final header construction + List staticMethods = getStaticGetterMethods(); + List staticHeaders = staticMethods.stream().map(this::methodToHeader).toList(); + + List dynamicHeaders = new ArrayList<>(); + for (String fieldId : fieldIdToLabel.keySet()) { + if (tableHeadersByFieldId.containsKey(fieldId)) { + dynamicHeaders.addAll(tableHeadersByFieldId.get(fieldId)); + } else { + dynamicHeaders.add(fieldIdToLabel.get(fieldId)); + } + } + + List allHeaders = new ArrayList<>(staticHeaders); + allHeaders.addAll(dynamicHeaders); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (CSVPrinter printer = new CSVPrinter(new OutputStreamWriter(out), CSVFormat.DEFAULT.withHeader(allHeaders.toArray(new String[0])))) { + for (Long appId : appFieldValues.keySet()) { + ApplicationFormView appRow = appInfo.get(appId); + Map flatFieldVals = appFieldValues.get(appId); + Map tableVals = tableDataByApp.getOrDefault(appId, Collections.emptyMap()); + + List row = new ArrayList<>(); + for (Method method : staticMethods) { + row.add(invokeGetter(appRow, method)); + } + + for (String fieldId : fieldIdToLabel.keySet()) { + if (tableHeadersByFieldId.containsKey(fieldId)) { + for (String header : tableHeadersByFieldId.get(fieldId)) { + row.add(tableVals.getOrDefault(header, "")); + } + } else { + row.add(flatFieldVals.getOrDefault(fieldId, "")); + } + } + + printer.printRecord(row); + } + + } catch (IOException e) { + throw new RuntimeException("CSV generation failed", e); + } + + return out.toByteArray(); + } + private Map extractTableData(String fieldType, + ContentResponseBean content, String fieldValue) { + + if (content == null) return Map.of(); + + Map result = new LinkedHashMap<>(); + + List> rows = null; + try { + rows = GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(fieldType) + ? Utils.convertJsonToListMap(String.valueOf(PdfUtils.extractRows(fieldValue))) + : Utils.convertJsonToListMap(fieldValue); + } catch (Exception e) { + throw new RuntimeException(e); + } + + Map fieldLabelMap = new LinkedHashMap<>(); + Set predefinedIds = new LinkedHashSet<>(); + Set dynamicIds = new LinkedHashSet<>(); + Set numericFormulaIds = new LinkedHashSet<>(); + + for (SettingResponseBean setting : content.getSettings()) { + String settingName = setting.getName(); + if(settingName.equals(GepafinConstant.REPORT_ENABLE)){ + Boolean enable= (Boolean) setting.getValue(); + if(Boolean.FALSE.equals(enable)){ + return null; + } + } + + if (Boolean.TRUE.equals(GepafinConstant.TABLE_COLUMNS.equals(settingName)) || Boolean.TRUE.equals(GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(settingName))) { + Map valueMap = (Map) setting.getValue(); + if (valueMap == null) continue; + + List> columns = (List>) valueMap.get(GepafinConstant.STATE_FIELD_DATA); + if (columns != null) { + for (Map col : columns) { + String id = String.valueOf(col.get(GepafinConstant.NAME)); + if (Boolean.FALSE.equals(col.get(GepafinConstant.PREDEFINED))) { + if (GepafinConstant.NUMERIC.equals(col.get(GepafinConstant.FIELD_TYPE)) && Boolean.TRUE.equals(col.get(GepafinConstant.ENABLE_FORMULA))) { + numericFormulaIds.add(id); + } + } + } + } + } + + if (Boolean.TRUE.equals(GepafinConstant.REPORT_COLUMNS.equals(settingName))) { + List> reportColumns = (List>) setting.getValue(); + if (reportColumns != null) { + for (Map col : reportColumns) { + Boolean enableCsv = (Boolean) col.get(GepafinConstant.EBABLE_CSV); + if (Boolean.TRUE.equals(enableCsv)) { + String id = String.valueOf(col.get(GepafinConstant.NAME)); + + String fieldCsvLabel = col.get(GepafinConstant.LABEL_CSV) != null + ? String.valueOf(col.get(GepafinConstant.LABEL_CSV)) + : String.valueOf(col.get(GepafinConstant.LABEL)); + + fieldLabelMap.put(id, fieldCsvLabel); + + if (Boolean.TRUE.equals(col.get(GepafinConstant.PREDEFINED))) { + predefinedIds.add(id); + } else { + dynamicIds.add(id); + } + } + } + } + } + } + + + + if (predefinedIds.isEmpty()) { + return null; + } + for (Map row : rows) { + String prefix = predefinedIds.stream() + .map(id -> String.valueOf(row.getOrDefault(id, ""))) + .filter(s -> !s.isBlank()) + .findFirst().orElse(""); + + + for (String dynId : dynamicIds) { + String dynLabel = fieldLabelMap.get(dynId); + for (String preId : predefinedIds.isEmpty() ? List.of("") : predefinedIds) { + String preLabel = fieldLabelMap.get(preId); + String key = dynLabel + " " + (preLabel != null ? preLabel + " " : "") + prefix; + result.put(key, String.valueOf(row.getOrDefault(dynId, ""))); + } + } + } + + // Add totals for numeric formula-enabled columns + for (String dynId : numericFormulaIds) { + double sum = rows.stream() + .mapToDouble(r -> { + try { + return Double.parseDouble(String.valueOf(r.getOrDefault(dynId, "0"))); + } catch (NumberFormatException e) { + return 0.0; + } + }).sum(); + String dynLabel = fieldLabelMap.get(dynId); + result.put("TOTAL " + dynLabel, String.valueOf(sum)); + } + + return result; + } + private void prepareTableFieldData( + List results, + Set tableFieldIds, + Map> tableHeadersByFieldId, + Map> tableDataByApp) { + + if (tableFieldIds.isEmpty()) return; + + Map> groupedByApp = results.stream() + .filter(r -> tableFieldIds.contains(r.getFieldId())) + .collect(Collectors.groupingBy(ApplicationFormView::getApplicationId)); + + for (Map.Entry> entry : groupedByApp.entrySet()) { + Long appId = entry.getKey(); + Map flattenedAll = new LinkedHashMap<>(); + + for (ApplicationFormView row : entry.getValue()) { + formRepository.findById(row.getFormId()).ifPresent(form -> { + List contentList = Utils.convertJsonStringToList(form.getContent(), ContentResponseBean.class); + ContentResponseBean content = contentList.stream() + .filter(c -> c.getId().equals(row.getFieldId())) + .findFirst() + .orElse(null); + + if (content == null) return; + + content.getSettings().stream() + .filter(setting -> GepafinConstant.TABLE_COLUMNS.equals(setting.getName()) + || GepafinConstant.CRITERIA_TABLE_COLUMNS.equals(setting.getName())) + .findFirst() + .ifPresent(setting -> { + Map flattened = extractTableData( + row.getFieldType(), + content, + row.getFieldValue() + ); + if (flattened != null) { + tableHeadersByFieldId.putIfAbsent(row.getFieldId(), new ArrayList<>(flattened.keySet())); + flattenedAll.putAll(flattened); + } + }); + }); + } + + tableDataByApp.put(appId, flattenedAll); + } + } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 17cac4c4..7052aad0 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -1665,7 +1665,7 @@ public class ApplicationEvaluationDao { }); } - private String getLabelFromSettings(ContentResponseBean contentResponseBean) { + public String getLabelFromSettings(ContentResponseBean contentResponseBean) { String label = contentResponseBean.getLabel(); if (contentResponseBean.getSettings() != null) { for (SettingResponseBean setting : contentResponseBean.getSettings()) { diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java new file mode 100644 index 00000000..b3733afc --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormView.java @@ -0,0 +1,118 @@ +package net.gepafin.tendermanagement.entities; + + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Immutable; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; + +@Entity +@Immutable +@Table(name = "application_form_view") +@Getter +@Setter +@IdClass(ApplicationFormViewId.class) +public class ApplicationFormView { + + @Id + @Column(name = "id") + private Long id; + + @Column(name = "application_id") + private Long applicationId; + + @Column(name = "call_id") + private Long callId; + + @Column(name = "form_id") + private Long formId; + + @Column(name = "application_form_id") + private Long applicationFormId; + + @Column(name = "field_id") + private String fieldId; + + @Column(name = "field_label") + private String fieldLabel; + + @Column(name = "field_type") + private String fieldType; + + @Column(name = "field_value") + private String fieldValue; + + @Column(name = "report_enable") + private Boolean reportEnable; + + @Column(name = "report_header") + private String reportHeader; + + @Column(name = "status") + private String status; + + @Column(name = "amount_requested") + private BigDecimal amountRequested; + + @Column(name = "amount_accepted") + private BigDecimal amountAccepted; + + @Column(name = "is_deleted") + private boolean isDeleted; + + @Column(name = "hub_id") + private Long hubId; + + @Column(name = "user_id") + private Long userId; + + @Column(name = "evaluation_version") + private String evaluationVersion; + + @Column(name = "company_id") + private Long companyId; + + @Column(name = "company_name") + private String companyName; + + @Column(name = "company_vat_number") + private String companyVatNumber; + + @Column(name = "codice_ateco") + private String codiceAteco; + + @Column(name = "company_codice_fiscale") + private String companyCodiceFiscale; + + @Column(name = "protocol_number") + private Long protocolNumber; + + @Column(name = "user_codice_fiscale") + private String userCodiceFiscale; + + @Column(name = "user_name") + private String userName; + + @Column(name = "legal_representative") + private Boolean legalRepresentative; + + @Column(name = "call_title") + private String callTitle; + + @Column(name = "call_end_date") + private LocalDate callEndDate; + + @Column(name = "call_end_time") + private LocalTime callEndTime; + + @Column(name = "call_start_date") + private LocalDate callStartDate; + + @Column(name = "call_start_time") + private LocalTime callStartTime; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java new file mode 100644 index 00000000..37d0cbb7 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationFormViewId.java @@ -0,0 +1,20 @@ +package net.gepafin.tendermanagement.entities; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Objects; + +@Data +public class ApplicationFormViewId implements Serializable { + + private static final long serialVersionUID = 1L; + private Long id; + + public ApplicationFormViewId() { + } + + public ApplicationFormViewId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java new file mode 100644 index 00000000..ecfe17c7 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationFormViewRepository.java @@ -0,0 +1,17 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.ApplicationFormView; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ApplicationFormViewRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query("SELECT v FROM ApplicationFormView v WHERE v.callId = :callId AND v.reportEnable = true") + List findByCallId(Long callId); + +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index 4565668c..24fde801 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -1,6 +1,7 @@ package net.gepafin.tendermanagement.service; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean; import net.gepafin.tendermanagement.model.request.ApplicationRequest; @@ -46,4 +47,7 @@ public interface ApplicationService { PageableResponseBean> getAllApplicationByPagination(HttpServletRequest request, Long callId, Long companyId, ApplicationPageableRequestBean applicationPageableRequestBean); public ApplicationEntity validateApplicationWithCompany(Long applicationId,Long companyId); + + public byte[] exportCsv(HttpServletRequest request, Long callId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index 8426390e..ea3f22c2 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -6,6 +6,7 @@ import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.dao.ApplicationDao; import net.gepafin.tendermanagement.dao.FlowFormDao; import net.gepafin.tendermanagement.entities.ApplicationEntity; +import net.gepafin.tendermanagement.entities.CallEntity; import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean; @@ -15,6 +16,7 @@ import net.gepafin.tendermanagement.enums.FormActionEnum; import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.service.ApplicationService; +import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.ForbiddenAccessException; @@ -38,6 +40,9 @@ public class ApplicationServiceImpl implements ApplicationService { @Autowired private Validator validator; + @Autowired + private CallService callService; + @Override @Transactional(rollbackFor = Exception.class) public ApplicationResponseBean createApplication(HttpServletRequest request, @@ -152,4 +157,15 @@ public class ApplicationServiceImpl implements ApplicationService { public ApplicationEntity validateApplicationWithCompany(Long applicationId,Long companyId) { return applicationDao.validateApplicationWithCompany(applicationId,companyId); } + + @Override + public byte[] exportCsv(HttpServletRequest request, Long callId) { + UserEntity userEntity = validator.validateUser(request); + CallEntity call=callService.validateCall(callId); + validator.validateHubId(request,call.getHub().getId()); + byte[] csvBytes= applicationDao.exportCsv(callId); + + return csvBytes; + } + } diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 1838bd57..30ac3687 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -796,4 +796,28 @@ public class Utils { return null; } } -} \ No newline at end of file + public static List> convertJsonToListMap(String jsonString) { + try { + if (jsonString == null || jsonString.trim().isEmpty()) { + return Collections.emptyList(); + } + + ObjectMapper objectMapper = new ObjectMapper(); + String unescaped; + + // First try: parse as if it's double-encoded (escaped string containing a JSON array) + try { + unescaped = objectMapper.readValue(jsonString, String.class); + } catch (Exception e) { + // If that fails, assume it's already a proper JSON array + unescaped = jsonString; + } + + // Now parse the actual JSON array + return objectMapper.readValue(unescaped, new TypeReference>>() {}); + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index 9db1d79e..00609f68 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -2,11 +2,12 @@ package net.gepafin.tendermanagement.web.rest.api; import java.util.List; -import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean; -import net.gepafin.tendermanagement.model.request.NotificationRequestBean; +import jakarta.servlet.http.HttpServletResponse; +import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.response.*; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -18,10 +19,8 @@ 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.ApplicationRequest; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.FormActionEnum; -import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; @@ -224,5 +223,21 @@ public interface ApplicationApi { ResponseEntity>>> getAllApplicationByPagination(HttpServletRequest request,@Parameter(description = "The call id", required = false) @RequestParam(value = "callId", required = false) Long callId, @Parameter(description = "The company id", required = false) @RequestParam(value = "companyId", required = false) Long companyId, @RequestBody ApplicationPageableRequestBean applicationPageableRequestBean); + @Operation(summary = "Api to download application data as a CSV file using the call ID", + 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)})) + }) + @GetMapping(value = "/call/{callId}/csv") + @PreAuthorize("hasRole('ROLE_SUPER_ADMIN')") + public ResponseEntity exportCsv( + HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable(value = "callId", required = true) Long callId); + + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index a9c148bb..a06f5dc4 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -1,16 +1,14 @@ package net.gepafin.tendermanagement.web.rest.api.impl; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; 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.ApplicationPageableRequestBean; -import net.gepafin.tendermanagement.model.request.ApplicationRequest; +import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.FormActionEnum; -import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; -import net.gepafin.tendermanagement.model.request.UserActionRequest; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.service.ApplicationService; @@ -236,5 +234,13 @@ public class ApplicationApiController implements ApplicationApi { .getAllApplicationByPagination(request, callId,companyId,applicationPageableRequestBean); return ResponseEntity.status(HttpStatus.OK).body(new Response<>(pageableResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_APPLICATION_SUCCESS_MSG))); } + @Override + public ResponseEntity exportCsv(HttpServletRequest request, Long callId) { + byte[] csvBytes =applicationService.exportCsv(request,callId); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=applications.csv") + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(csvBytes); + } } diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 82104fcb..7e349dea 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2678,4 +2678,9 @@ + + + diff --git a/src/main/resources/db/dump/create_application_form_view.sql b/src/main/resources/db/dump/create_application_form_view.sql new file mode 100644 index 00000000..b84eaa25 --- /dev/null +++ b/src/main/resources/db/dump/create_application_form_view.sql @@ -0,0 +1,125 @@ +CREATE OR REPLACE VIEW gepafin_schema.application_form_view AS +SELECT app_data.id, + app_data.call_id, + app_data.application_form_id, + app_data.form_id, + app_data.application_id, + field_data.value ->> 'id' AS field_id, + COALESCE( + (SELECT s.value ->> 'value' + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'label' + LIMIT 1), + field_data.value ->> 'label' + ) AS field_label, + ( + SELECT (s.value ->> 'value')::boolean + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'reportEnable' + LIMIT 1 + ) AS report_enable, + COALESCE( (SELECT s.value ->> 'value' + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'reportHeader' + LIMIT 1), + field_data.value ->> 'reportHeader' + ) AS report_header, + field_data.value ->> 'name' AS field_type, + CASE + WHEN field_data.value ->> 'name' = 'fileupload' THEN + to_jsonb(( + SELECT string_agg(d.file_name, ', ') + FROM unnest(string_to_array(app_data.field_value, ',')) file_ids(file_id) + JOIN gepafin_schema.document d ON d.id::text = file_ids.file_id + WHERE d.is_deleted = false + )) + WHEN field_data.value ->> 'name' IN ('checkboxes', 'select', 'radio') THEN + CASE + WHEN app_data.field_value ~~ '[%' THEN + to_jsonb(( + SELECT string_agg(opt.value ->> 'label', ', ') + FROM jsonb_array_elements_text(app_data.field_value::jsonb) selected_id(value) + CROSS JOIN LATERAL ( + SELECT s.value + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'options' + ) options_setting, + LATERAL jsonb_array_elements(options_setting.value -> 'value') opt(value) + WHERE opt.value ->> 'name' = selected_id.value + )) + ELSE + to_jsonb(( + SELECT opt.value ->> 'label' + FROM ( + SELECT s.value + FROM jsonb_array_elements(field_data.value -> 'settings') s(value) + WHERE s.value ->> 'name' = 'options' + ) options_setting, + LATERAL jsonb_array_elements(options_setting.value -> 'value') opt(value) + WHERE opt.value ->> 'name' = app_data.field_value + LIMIT 1 + )) + END + ELSE + to_jsonb(app_data.field_value) + END AS field_value, + app_data.status, + app_data.amount_requested, + app_data.amount_accepted, + app_data.is_deleted, + app_data.hub_id, + app_data.user_id, + app_data.evaluation_version, + app_data.company_id, + c.company_name, + c.vat_number AS company_vat_number, + c.codice_ateco, + c.codice_fiscale AS company_codice_fiscale, + p.protocol_number, + b.codice_fiscale AS user_codice_fiscale, + COALESCE(NULLIF(TRIM(BOTH FROM CONCAT(COALESCE(u.first_name, ''), ' ', COALESCE(u.last_name, ''))), ''), '') AS user_name, + uwc.is_legal_representant AS legal_representative, + cl.name AS call_title, + cl.end_date AS call_end_date, + cl.end_time AS call_end_time, + cl.start_date AS call_start_date, + cl.start_time AS call_start_time +FROM ( + SELECT a.id AS application_id, + a.call_id, + a.protocol_number, + af.id AS application_form_id, + af.form_id AS form_id, + aff.id AS id, + aff.field_value, + a.status, + a.amount_requested, + a.amount_accepted, + a.is_deleted, + a.hub_id, + a.user_id, + a.evaluation_version, + a.created_date, + a.company_id, + aff.field_id, + f.content + FROM gepafin_schema.application a + JOIN gepafin_schema.application_form af ON af.application_id = a.id + JOIN gepafin_schema.application_form_field aff ON aff.application_form_id = af.id + JOIN gepafin_schema.form f ON f.id = af.form_id + WHERE a.is_deleted = false +) app_data +CROSS JOIN LATERAL ( + SELECT jsonb_array_elements.value + FROM jsonb_array_elements(app_data.content::jsonb) jsonb_array_elements(value) + WHERE jsonb_array_elements.value ->> 'id' = app_data.field_id::text +) field_data(value) +LEFT JOIN gepafin_schema.call cl ON app_data.call_id = cl.id +LEFT JOIN gepafin_schema.company c ON app_data.company_id = c.id +LEFT JOIN gepafin_schema.protocol p ON app_data.protocol_number = p.id +LEFT JOIN gepafin_schema.gepafin_user u ON app_data.user_id = u.id +LEFT JOIN gepafin_schema.user_with_company uwc ON app_data.user_id = uwc.user_id AND app_data.company_id = uwc.company_id AND uwc.is_deleted = false +LEFT JOIN gepafin_schema.beneficiary b ON u.beneficiary_id = b.id +WHERE app_data.id IS NOT NULL + AND app_data.status NOT IN ('DRAFT', 'AWAITING', 'READY') +ORDER BY app_data.id, field_data.value ->> 'id'; \ No newline at end of file From ec1c104f8c05cb274c7208d1e88d7afe70c810b7 Mon Sep 17 00:00:00 2001 From: Piyush Date: Mon, 28 Apr 2025 17:07:17 +0530 Subject: [PATCH 17/63] Resolved conflict --- .../db/changelog/db.changelog-1.0.0.xml | 10 ++++++++++ ...on_template_for_notification_28_04_2025.sql | 9 +++++++++ ...update_system_email_template_28_04_2025.sql | 7 +++++++ src/main/resources/message_it.properties | 18 +++++++++--------- 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql create mode 100644 src/main/resources/db/dump/update_system_email_template_28_04_2025.sql diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 7e349dea..aa166039 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2683,4 +2683,14 @@ dbms="postgresql" path="db/dump/create_application_form_view.sql"/> + + + + + + + + diff --git a/src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql b/src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql new file mode 100644 index 00000000..8fe353ef --- /dev/null +++ b/src/main/resources/db/dump/update_json_template_for_notification_28_04_2025.sql @@ -0,0 +1,9 @@ +UPDATE notification_type +SET + title = regexp_replace(title, 'emendamento', 'soccorso istruttorio', 'gi'), + json_template = regexp_replace(json_template, 'emendamento', 'soccorso istruttorio', 'gi') +WHERE + title ~* 'emendamento' + OR json_template ~* 'emendamento'; + + diff --git a/src/main/resources/db/dump/update_system_email_template_28_04_2025.sql b/src/main/resources/db/dump/update_system_email_template_28_04_2025.sql new file mode 100644 index 00000000..2e6490dd --- /dev/null +++ b/src/main/resources/db/dump/update_system_email_template_28_04_2025.sql @@ -0,0 +1,7 @@ +UPDATE gepafin_schema.system_email_template +SET + html_content = regexp_replace(html_content, 'emendamento', 'Soccorso Istruttorio', 'gi'), + subject = regexp_replace(subject, 'emendamento', 'Soccorso Istruttorio', 'gi') +WHERE + html_content ~* 'emendamento' + OR subject ~* 'emendamento'; diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 7b0293bf..7a77bd5e 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -288,22 +288,22 @@ application.not.in.draft.status=La domanda non ? in stato DRAFT. get.error.s3=Impossibile recuperare il file da S3. application.data.amendment.success = Recupero riuscito dei dati dell'applicazione per il processo di modifica -delete.application.amendment.success =Emendamento all'applicazione eliminato con successo. +delete.application.amendment.success =Soccorso Istruttorio all'applicazione eliminato con successo. application.amendment.not.found = Richiesta di modifica dell'applicazione non trovata con l'ID indicato. application.amendment.get.success = Dettagli della modifica dell'applicazione recuperati correttamente con l'ID fornito. -application.amendment.update.successfully = Emendamento all'applicazione aggiornato con successo. -application.amendment.closed.successfully = Emendamento alla domanda chiuso con successo. +application.amendment.update.successfully = Soccorso Istruttorio all'applicazione aggiornato con successo. +application.amendment.closed.successfully = Soccorso Istruttorio alla domanda chiuso con successo. response.days.extended.success=Giorni di risposta estesi con successo. -added.comment.to.amendment.request.success = Commento aggiunto con successo alla richiesta di emendamento. +added.comment.to.amendment.request.success = Commento aggiunto con successo alla richiesta di soccorso istruttorio. comment.not.found = Commento non trovato. comment.updated.successfully = Commento aggiornato con successo. comment.deleted.successfully = Commento eliminato con successo. -comment.not.associate.with.amendment = Il commento non ? associato alla richiesta di emendamento. -amendment.found.success = Richiesta di emendamento trovata con successo. -invalid.amendment.for.comment = Richiesta di emendamento non valida per il commento fornito. +comment.not.associate.with.amendment = Il commento non ? associato alla richiesta di soccorso istruttorio. +amendment.found.success = Richiesta di soccorso istruttorio trovata con successo. +invalid.amendment.for.comment = Richiesta di soccorso istruttorio non valida per il commento fornito. DD_MM_YYYY_HH_MM = dd_MM_yyyy HH:mm -create.application.data.amendment.msg =Emendamento alla domanda inviato con successo +create.application.data.amendment.msg =soccorso istruttorio alla domanda inviato con successo beneficiary.email.not.found.msg=L'indirizzo email per il beneficiario non ? stato trovato. Si prega di assicurarsi che il beneficiario abbia un indirizzo email valido. reminder.email.sent.success.msg=Email di promemoria inviata con successo! application.documents.not.found=Nessun documento trovato per la domanda. @@ -312,7 +312,7 @@ user.must.be.associated.with.company.to.create.application=Devi essere associato company.id.required.for.preferred.call=ID azienda obbligatorio quando si richiedono solo chiamate preferite. response.days.not.null=I giorni di risposta non devono essere nulli e maggiori di zero. valid.vatnumber.message=Il numero di partita IVA � valido. -application.cannot.approved.or.rejected=La domanda non pu? essere approvata o rifiutata perch? l'emendamento ? attivo. +application.cannot.approved.or.rejected=La domanda non pu? essere approvata o rifiutata perch? Il Soccorso Istruttorio ? attivo. atleast.one.id.required=Almeno uno tra companyId o applicationId deve essere fornito. From 5fdf05fbbbc3e4bd77a5f56981cb174554f31f12 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 28 Apr 2025 17:45:23 +0530 Subject: [PATCH 18/63] Updated odessa portal password for production. --- src/main/resources/application-production.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index 65842ebb..cf3396fa 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -27,7 +27,7 @@ default.hub.uuid=p4lk3bcx1RStqTaIVVbXs #Login to Odessa, Appointment Creation, Upload document Configuration appointment.base.url=https://prd.galileonetwork.it/gateway/rest appointment.portal.user=UtenzaAPIPortal@621 -appointment.portal.password=u13nzaAP1P0rtal! +appointment.portal.password=Valeria2016!! appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL From 98bb6442b7c77f027bda246aeb3813c5199c9608 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 28 Apr 2025 19:04:53 +0530 Subject: [PATCH 19/63] Updated Code. --- .../net/gepafin/tendermanagement/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java index 462d5cc9..baa4c0d0 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java @@ -99,7 +99,7 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable).headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin) - .contentSecurityPolicy(csp -> csp.policyDirectives("frame-ancestors 'self' https://bandi-staging.memento.credit https://bandi.gepafin.it"))) + .contentSecurityPolicy(csp -> csp.policyDirectives("frame-ancestors 'self' https://bandi-staging.memento.credit https://bandi.gepafin.it https://api-dev-gepafin.memento.credit https://bandi-api.gepafin.it"))) .authorizeHttpRequests(auth -> auth // Allow public access to the login endpoints .requestMatchers("/v1/user/login").permitAll() // JWT-based login From 9990dc349e1187566740cecb14ec8843cda48853 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 28 Apr 2025 19:08:48 +0530 Subject: [PATCH 20/63] Updated Code. --- .../net/gepafin/tendermanagement/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java index baa4c0d0..462d5cc9 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java @@ -99,7 +99,7 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable).headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin) - .contentSecurityPolicy(csp -> csp.policyDirectives("frame-ancestors 'self' https://bandi-staging.memento.credit https://bandi.gepafin.it https://api-dev-gepafin.memento.credit https://bandi-api.gepafin.it"))) + .contentSecurityPolicy(csp -> csp.policyDirectives("frame-ancestors 'self' https://bandi-staging.memento.credit https://bandi.gepafin.it"))) .authorizeHttpRequests(auth -> auth // Allow public access to the login endpoints .requestMatchers("/v1/user/login").permitAll() // JWT-based login From 1ef09ce1d72d3f3c43fa2fbf9d809b9935385571 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Tue, 29 Apr 2025 17:50:46 +0530 Subject: [PATCH 21/63] Done ticket GEPAFINBE-212 Fixed the filename decode issue for external doc upload API. --- .../tendermanagement/dao/AppointmentDao.java | 22 ++++++++++--------- .../service/AmazonS3Service.java | 1 + .../service/impl/AmazonS3ServiceImpl.java | 5 +++++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 46af8a26..f2a3aca4 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -37,6 +37,7 @@ import net.gepafin.tendermanagement.repositories.CompanyRepository; import net.gepafin.tendermanagement.repositories.DocumentRepository; import net.gepafin.tendermanagement.repositories.HubRepository; import net.gepafin.tendermanagement.repositories.UserRepository; +import net.gepafin.tendermanagement.service.AmazonS3Service; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.feignClient.AppointmentApiService; @@ -141,6 +142,9 @@ public class AppointmentDao { @Autowired private ApplicationEvaluationServiceImpl applicationEvaluationService; + @Autowired + private AmazonS3Service amazonS3Service; + private final Map executorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap threadForDocumentMap = new ConcurrentHashMap<>(); @@ -720,9 +724,11 @@ public class AppointmentDao { // Build the appointment request body AppointmentCreationRequest appointmentCreationRequest = buildAppointmentCreationRequest(applicationId, createAppointmentRequest, appointmentTemplateId, templateRichiestaData); + log.info("AppointmentCreationRequest {}", appointmentCreationRequest); String appointmentRequestBody = Utils.convertObjectToJson(appointmentCreationRequest); // Make API call to create the appointment + log.info("Context:{}, Authorization Token {}, RequestBody {}", context, authorizationToken, appointmentRequestBody); ResponseEntity appointmentResponse = appointmentApiService.createAppointment(authorizationToken, context, appointmentRequestBody); String appointmentId = extractAppointmentIdFromResponse(appointmentResponse); @@ -751,6 +757,7 @@ public class AppointmentDao { private String extractAppointmentIdFromResponse(ResponseEntity appointmentResponse) { if (appointmentResponse.getBody() != null) { + log.info("Appointment API Response {}", appointmentResponse.getBody()); Map responseBody = (Map) appointmentResponse.getBody(); if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { Map data = (Map) responseBody.get(GepafinConstant.DATA_STRING); @@ -979,12 +986,12 @@ public class AppointmentDao { private File downloadFileFromS3(String fileUrl) throws Exception { - String key = extractS3KeyFromUrl(fileUrl); - File localFile = new File(GepafinConstant.TEMP_FILE_PATH + extractFileName(key)); + String key = amazonS3Service.extractS3KeyFromUrl(fileUrl); + String fileName = extractFileName(key); + String folderPath = key.substring(0, key.lastIndexOf("/")); + File localFile = new File(GepafinConstant.TEMP_FILE_PATH + fileName); - GetObjectRequest getObjectRequest = new GetObjectRequest(OLD_BUCKET, key); - - try (InputStream s3Stream = s3Client.getObject(getObjectRequest).getObjectContent(); FileOutputStream outputStream = new FileOutputStream(localFile)) { + try (InputStream s3Stream = amazonS3Service.getFile(folderPath, key); FileOutputStream outputStream = new FileOutputStream(localFile)) { s3Stream.transferTo(outputStream); } @@ -992,11 +999,6 @@ public class AppointmentDao { return localFile; } - private String extractS3KeyFromUrl(String url) { - - return url.replace(s3Url, ""); - } - private String extractFileName(String filePath) { String[] parts = filePath.split("/"); diff --git a/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java index 642bbcfc..9766d58c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java +++ b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java @@ -21,4 +21,5 @@ AmazonS3Service { UploadFileOnAmazonS3Response copyFile(String fileName, String oldS3Path, String newS3Path); + String extractS3KeyFromUrl(String url); } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java index 7566f935..8f87e40c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java @@ -217,4 +217,9 @@ public class AmazonS3ServiceImpl implements AmazonS3Service { } } + + public String extractS3KeyFromUrl(String url) { + + return url.replace(s3Url, ""); + } } \ No newline at end of file From b884f5aeffaddc11641ad039d3590d5988178f1a Mon Sep 17 00:00:00 2001 From: piyushkag Date: Tue, 29 Apr 2025 17:50:46 +0530 Subject: [PATCH 22/63] Resolved conflicts. --- .../tendermanagement/dao/AppointmentDao.java | 25 +++++++++---------- .../service/AmazonS3Service.java | 1 + .../service/impl/AmazonS3ServiceImpl.java | 5 ++++ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 9f135199..f2a3aca4 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -37,6 +37,7 @@ import net.gepafin.tendermanagement.repositories.CompanyRepository; import net.gepafin.tendermanagement.repositories.DocumentRepository; import net.gepafin.tendermanagement.repositories.HubRepository; import net.gepafin.tendermanagement.repositories.UserRepository; +import net.gepafin.tendermanagement.service.AmazonS3Service; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.feignClient.AppointmentApiService; @@ -141,6 +142,9 @@ public class AppointmentDao { @Autowired private ApplicationEvaluationServiceImpl applicationEvaluationService; + @Autowired + private AmazonS3Service amazonS3Service; + private final Map executorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap threadForDocumentMap = new ConcurrentHashMap<>(); @@ -720,11 +724,11 @@ public class AppointmentDao { // Build the appointment request body AppointmentCreationRequest appointmentCreationRequest = buildAppointmentCreationRequest(applicationId, createAppointmentRequest, appointmentTemplateId, templateRichiestaData); - log.info("AppointmentCreationRequest : {}", appointmentCreationRequest); + log.info("AppointmentCreationRequest {}", appointmentCreationRequest); String appointmentRequestBody = Utils.convertObjectToJson(appointmentCreationRequest); // Make API call to create the appointment - log.info("Context:{}, Authorization Token : {}, RequestBody : {}", context, authorizationToken, appointmentRequestBody); + log.info("Context:{}, Authorization Token {}, RequestBody {}", context, authorizationToken, appointmentRequestBody); ResponseEntity appointmentResponse = appointmentApiService.createAppointment(authorizationToken, context, appointmentRequestBody); String appointmentId = extractAppointmentIdFromResponse(appointmentResponse); @@ -753,7 +757,7 @@ public class AppointmentDao { private String extractAppointmentIdFromResponse(ResponseEntity appointmentResponse) { if (appointmentResponse.getBody() != null) { - log.info("Appointment API Response : {}", appointmentResponse.getBody()); + log.info("Appointment API Response {}", appointmentResponse.getBody()); Map responseBody = (Map) appointmentResponse.getBody(); if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { Map data = (Map) responseBody.get(GepafinConstant.DATA_STRING); @@ -982,12 +986,12 @@ public class AppointmentDao { private File downloadFileFromS3(String fileUrl) throws Exception { - String key = extractS3KeyFromUrl(fileUrl); - File localFile = new File(GepafinConstant.TEMP_FILE_PATH + extractFileName(key)); + String key = amazonS3Service.extractS3KeyFromUrl(fileUrl); + String fileName = extractFileName(key); + String folderPath = key.substring(0, key.lastIndexOf("/")); + File localFile = new File(GepafinConstant.TEMP_FILE_PATH + fileName); - GetObjectRequest getObjectRequest = new GetObjectRequest(OLD_BUCKET, key); - - try (InputStream s3Stream = s3Client.getObject(getObjectRequest).getObjectContent(); FileOutputStream outputStream = new FileOutputStream(localFile)) { + try (InputStream s3Stream = amazonS3Service.getFile(folderPath, key); FileOutputStream outputStream = new FileOutputStream(localFile)) { s3Stream.transferTo(outputStream); } @@ -995,11 +999,6 @@ public class AppointmentDao { return localFile; } - private String extractS3KeyFromUrl(String url) { - - return url.replace(s3Url, ""); - } - private String extractFileName(String filePath) { String[] parts = filePath.split("/"); diff --git a/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java index 642bbcfc..9766d58c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java +++ b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java @@ -21,4 +21,5 @@ AmazonS3Service { UploadFileOnAmazonS3Response copyFile(String fileName, String oldS3Path, String newS3Path); + String extractS3KeyFromUrl(String url); } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java index 7566f935..8f87e40c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java @@ -217,4 +217,9 @@ public class AmazonS3ServiceImpl implements AmazonS3Service { } } + + public String extractS3KeyFromUrl(String url) { + + return url.replace(s3Url, ""); + } } \ No newline at end of file From 2531c5e951a0a49ecac23a893674721b282c3bb1 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Tue, 29 Apr 2025 17:55:12 +0530 Subject: [PATCH 23/63] Resolved Conflicts. --- .../net/gepafin/tendermanagement/dao/AppointmentDao.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index f2a3aca4..cb83406e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -724,11 +724,11 @@ public class AppointmentDao { // Build the appointment request body AppointmentCreationRequest appointmentCreationRequest = buildAppointmentCreationRequest(applicationId, createAppointmentRequest, appointmentTemplateId, templateRichiestaData); - log.info("AppointmentCreationRequest {}", appointmentCreationRequest); + log.info("AppointmentCreationRequest : {}", appointmentCreationRequest); String appointmentRequestBody = Utils.convertObjectToJson(appointmentCreationRequest); // Make API call to create the appointment - log.info("Context:{}, Authorization Token {}, RequestBody {}", context, authorizationToken, appointmentRequestBody); + log.info("Context:{}, Authorization Token : {}, RequestBody : {}", context, authorizationToken, appointmentRequestBody); ResponseEntity appointmentResponse = appointmentApiService.createAppointment(authorizationToken, context, appointmentRequestBody); String appointmentId = extractAppointmentIdFromResponse(appointmentResponse); @@ -757,7 +757,7 @@ public class AppointmentDao { private String extractAppointmentIdFromResponse(ResponseEntity appointmentResponse) { if (appointmentResponse.getBody() != null) { - log.info("Appointment API Response {}", appointmentResponse.getBody()); + log.info("Appointment API Response : {}", appointmentResponse.getBody()); Map responseBody = (Map) appointmentResponse.getBody(); if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { Map data = (Map) responseBody.get(GepafinConstant.DATA_STRING); From 11e09b8eb9cd1103d381e3dbb560cc72f9de6567 Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 30 Apr 2025 17:44:00 +0530 Subject: [PATCH 24/63] Done ticket GEPAFINBE-214 --- .../net/gepafin/tendermanagement/dao/CallDao.java | 12 ++++++------ .../model/request/CallPageableRequestBean.java | 2 -- .../tendermanagement/service/CallService.java | 2 +- .../service/impl/CallServiceImpl.java | 4 ++-- .../tendermanagement/web/rest/api/CallApi.java | 2 +- .../web/rest/api/impl/CallApiController.java | 4 ++-- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index fa02eac1..3cb86a50 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -986,7 +986,7 @@ public class CallDao { return callEntity; } - public PageableResponseBean> getAllCallsByPagination(HttpServletRequest request,UserEntity user,Long companyId , Boolean onlyPreferredCall, CallPageableRequestBean callPageableRequestBean) { + public PageableResponseBean> getAllCallsByPagination(HttpServletRequest request,UserEntity user,Long companyId , Boolean onlyPreferredCall, Boolean onlyConfidiCall, CallPageableRequestBean callPageableRequestBean) { Integer pageNo = null; Integer pageLimit = null; if (callPageableRequestBean.getGlobalFilters() != null) { @@ -1006,7 +1006,7 @@ public class CallDao { ); } expirePublishedCalls(request); - Specification spec = search(request,user, callPageableRequestBean); + Specification spec = search(request,user, callPageableRequestBean,onlyConfidiCall); Page entityPage; if (Boolean.TRUE.equals(onlyPreferredCall)) { validator.validateUserWithCompany(request, companyId); @@ -1056,10 +1056,10 @@ public class CallDao { return pageableResponseBean; } - public Specification search(HttpServletRequest request,UserEntity userEntity, CallPageableRequestBean callPageableRequestBean) { + public Specification search(HttpServletRequest request,UserEntity userEntity, CallPageableRequestBean callPageableRequestBean,Boolean onlyConfidiCall) { return (root, query, criteriaBuilder) -> { - List predicates = getPredicates(request,callPageableRequestBean, criteriaBuilder, root, userEntity); + List predicates = getPredicates(request,callPageableRequestBean, criteriaBuilder, root, userEntity,onlyConfidiCall); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (callPageableRequestBean.getGlobalFilters() != null @@ -1083,7 +1083,7 @@ public class CallDao { private List getPredicates(HttpServletRequest request,CallPageableRequestBean callPageableRequestBean, - CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity) { + CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity,Boolean onlyConfidiCall) { Integer year = null; String search = null; Map filters = new HashMap<>(); @@ -1137,7 +1137,7 @@ public class CallDao { predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); } applyFilters(root, criteriaBuilder, predicates, filters); - Boolean isConfidi = callPageableRequestBean.getConfidi(); + Boolean isConfidi =onlyConfidiCall; if (validator.checkIsConfidi()) { diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/CallPageableRequestBean.java b/src/main/java/net/gepafin/tendermanagement/model/request/CallPageableRequestBean.java index 5a76ad97..260a45e5 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/CallPageableRequestBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/CallPageableRequestBean.java @@ -14,6 +14,4 @@ public class CallPageableRequestBean { private List status; private Map filters; - - private Boolean confidi; } diff --git a/src/main/java/net/gepafin/tendermanagement/service/CallService.java b/src/main/java/net/gepafin/tendermanagement/service/CallService.java index 925c71cd..f0130c29 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/CallService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/CallService.java @@ -33,7 +33,7 @@ public interface CallService { byte[] downloadCallDocumentsAsZip(HttpServletRequest request, Long callId); - PageableResponseBean> getAllCallsByPagination(HttpServletRequest request, Long companyId , Boolean onlyPreferredCall,CallPageableRequestBean callPageableRequestBean); + PageableResponseBean> getAllCallsByPagination(HttpServletRequest request, Long companyId , Boolean onlyPreferredCall,Boolean onlyConfidiCall,CallPageableRequestBean callPageableRequestBean); CallResponse createCallStep2EvaluationV2(HttpServletRequest request, Long callId, CreateCallRequestStep2EvaluationV2 createCallRequest); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java index d58a7644..0036cbb7 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java @@ -105,9 +105,9 @@ public class CallServiceImpl implements CallService { @Override @Transactional(rollbackFor = Exception.class) - public PageableResponseBean> getAllCallsByPagination(HttpServletRequest request,Long companyId , Boolean onlyPreferredCall, CallPageableRequestBean callPageableRequestBean) { + public PageableResponseBean> getAllCallsByPagination(HttpServletRequest request,Long companyId , Boolean onlyPreferredCall,Boolean onlyConfidiCall, CallPageableRequestBean callPageableRequestBean) { UserEntity user = validator.validateUser(request); - return callDao.getAllCallsByPagination(request,user,companyId,onlyPreferredCall,callPageableRequestBean); + return callDao.getAllCallsByPagination(request,user,companyId,onlyPreferredCall,onlyConfidiCall,callPageableRequestBean); } @Override @Transactional(rollbackFor = Exception.class) diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java index e1893f5a..11c6069c 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java @@ -159,7 +159,7 @@ public interface CallApi { @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE))) }) @PostMapping(value = "/pagination", consumes = "application/json", produces = "application/json") - ResponseEntity>>> getAllCallsByPagination(HttpServletRequest request,@RequestParam(value = "companyId", required = false) Long companyId , @RequestParam(value = "onlyPreferredCall", required = false, defaultValue = "false") Boolean onlyPreferredCall, @RequestBody CallPageableRequestBean callPageableRequestBean); + ResponseEntity>>> 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)", diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java index 5673bb2b..4eb80c83 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java @@ -152,12 +152,12 @@ public class CallApiController implements CallApi { } @Override - public ResponseEntity>>> getAllCallsByPagination(HttpServletRequest request, Long companyId , Boolean onlyPreferredCall, CallPageableRequestBean callPageableRequestBean) { + public ResponseEntity>>> 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. **/ loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_ALL_CALL_BY_PAGINATION).build()); - PageableResponseBean> callsByPagination=callService.getAllCallsByPagination(request,companyId,onlyPreferredCall,callPageableRequestBean); + PageableResponseBean> callsByPagination=callService.getAllCallsByPagination(request,companyId,onlyPreferredCall,onlyConfidiCall,callPageableRequestBean); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(callsByPagination, Status.SUCCESS, Translator.toLocale(GepafinConstant.CALL_FETCH_SUCCESS_MSG))); } From cffd25a4026739580268d45047570212cf273fbb Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 30 Apr 2025 20:30:24 +0530 Subject: [PATCH 25/63] Done ticket GEPAFINBE-215 --- .../gepafin/tendermanagement/dao/FormDao.java | 7 +-- .../tendermanagement/dao/VatCheckDao.java | 45 ++++++++++++++++++- .../model/response/VatCheckResponseBean.java | 3 ++ .../service/impl/CompanyServiceImpl.java | 4 +- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java b/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java index 598f6477..47859a3b 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java @@ -420,7 +420,8 @@ public class FormDao { .matchesPattern(value, fieldValidatorBean.getPattern(), fieldLabel) // Only applies if pattern is present .validateCustom(value, fieldValidatorBean.getCustom(), fieldLabel,contentResponseBean); // Add the custom validation here if (fieldValidatorBean.getCustom() != null && fieldValidatorBean.getCustom().equals(GepafinConstant.IS_PIVA)) { - String error = validateVatNumber(value, fieldValidatorBean.getCustom(), fieldLabel); + Long hubId = applicationEntity.getHubId(); + String error = validateVatNumber(value, fieldLabel,hubId); if(error != null) { validator.addError(error); } @@ -504,14 +505,14 @@ public class FormDao { }).filter(value -> !value.isEmpty()).findFirst().orElse(contentResponseBean.getId()); } - public String validateVatNumber(String value,String customRule,String fieldId){ + public String validateVatNumber(String value,String fieldId, Long hubId){ String error=null; if (value!=null && value.matches("^\\d{1,11}$")) { // Map customData=null; try { // Map vatCheckResponse = vatCheckDao.checkVatNumberApi(value); - vatCheckDao.checkVatNumber(value); + vatCheckDao.checkVatNumber(value, hubId); // if (Boolean.FALSE.equals(CollectionUtils.isEmpty(vatCheckResponse))) { // customData = vatCheckResponse; // } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java b/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java index 1c6869ad..342a853e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java @@ -3,12 +3,17 @@ package net.gepafin.tendermanagement.dao; import feign.FeignException; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.entities.CompanyEntity; +import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.VatCheckVersionTypeEnum; import net.gepafin.tendermanagement.model.response.VatCheckResponseBean; +import net.gepafin.tendermanagement.repositories.CompanyRepository; import net.gepafin.tendermanagement.repositories.GlobalConfigRepository; import net.gepafin.tendermanagement.service.feignClient.VatCheckV1Service; import net.gepafin.tendermanagement.service.feignClient.VatCheckV2Service; import net.gepafin.tendermanagement.util.Utils; +import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; +import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,6 +53,9 @@ public class VatCheckDao { @Autowired private GlobalConfigRepository globalConfigRepository; + @Autowired + private CompanyRepository companyRepository; + public final Logger log = LoggerFactory.getLogger(VatCheckDao.class); public VatCheckResponseBean checkVatNumberV1(String vatNumber) { @@ -56,6 +64,7 @@ public class VatCheckDao { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); if (Boolean.TRUE.equals(Boolean.parseBoolean(isVatCheckGloballyDisabled))) { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V1); return vatCheckResponseBean; } try { @@ -96,6 +105,7 @@ public class VatCheckDao { public static void processValidResponseV1(Map responseMap, VatCheckResponseBean vatCheckResponseBean) { Object dataObj = responseMap.get("data"); + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V1); if (dataObj instanceof Map rawDataMap) { Map responseBody = new LinkedHashMap<>(); rawDataMap.forEach((k, v) -> { @@ -118,9 +128,20 @@ public class VatCheckDao { } - public VatCheckResponseBean checkVatNumber(String vatNumber) { + public VatCheckResponseBean checkVatNumber(String vatNumber, Long hubId) { try { + CompanyEntity company = companyRepository.findByVatNumberAndHubId(vatNumber, hubId); + + if (company != null && Boolean.FALSE.equals(StringUtils.isEmpty(company.getJson()))) { + Map responseMap = Utils.convertJsonStringToMap(company.getJson()); + + VatCheckResponseBean jsonResponse = validateJsonFromDb(responseMap); + if (jsonResponse != null) { + return jsonResponse; + } + } + String vatApiVersion = getVatCheckVersion(); if(!isVatCheckApiV2(vatApiVersion)){ return checkVatNumberV1(vatNumber); @@ -134,6 +155,26 @@ public class VatCheckDao { return vatCheckResponseBean; } } + private VatCheckResponseBean validateJsonFromDb(Map responseMap) { + if (responseMap == null || !responseMap.containsKey("data")) return null; + + Object data = responseMap.get("data"); + + if (data instanceof Map dataMap && !dataMap.isEmpty()) { + VatCheckResponseBean response = new VatCheckResponseBean(); + processValidResponseV1(responseMap, response); + return response; + } + + if (data instanceof List dataList && !dataList.isEmpty()) { + VatCheckResponseBean response = new VatCheckResponseBean(); + processValidResponse(responseMap, response); + return response; + } + + return null; + } + public VatCheckResponseBean checkVatNumberV2(String vatNumber) { @@ -142,6 +183,7 @@ public class VatCheckDao { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); if (Boolean.TRUE.equals(Boolean.parseBoolean(isVatCheckGloballyDisabled))) { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V2); return vatCheckResponseBean; } try { @@ -175,6 +217,7 @@ public class VatCheckDao { public static void processValidResponse(Map responseMap, VatCheckResponseBean vatCheckResponseBean) { + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V2); if (responseMap == null || !responseMap.containsKey("data")) { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); return; diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java index 611925d3..00e6b93f 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java @@ -1,6 +1,8 @@ package net.gepafin.tendermanagement.model.response; import lombok.Getter; import lombok.Setter; +import net.gepafin.tendermanagement.enums.VatCheckVersionTypeEnum; + import java.util.Map; @Getter @@ -9,4 +11,5 @@ public class VatCheckResponseBean { private Boolean valid; private Map vatCheckResponse; private String message; + private VatCheckVersionTypeEnum version; } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java index 924f379c..f1d8f890 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java @@ -83,7 +83,9 @@ public class CompanyServiceImpl implements CompanyService { @Override @Transactional(readOnly = true) public VatCheckResponseBean checkVatNumber(HttpServletRequest request, String vatNumber) { - return vatCheckDao.checkVatNumber(vatNumber); + UserEntity userEntity = validator.validateUser(request); + Long hubId = userEntity.getHub().getId(); + return vatCheckDao.checkVatNumber(vatNumber, hubId); } @Override public CompanyEntity validateCompany(Long companyId) { From 2283e3169e67ff74004a807f056de102c7434cf6 Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 30 Apr 2025 20:30:24 +0530 Subject: [PATCH 26/63] Done ticket GEPAFINBE-215 --- .../gepafin/tendermanagement/dao/FormDao.java | 7 +-- .../tendermanagement/dao/VatCheckDao.java | 45 ++++++++++++++++++- .../model/response/VatCheckResponseBean.java | 3 ++ .../service/impl/CompanyServiceImpl.java | 4 +- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java b/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java index 598f6477..47859a3b 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java @@ -420,7 +420,8 @@ public class FormDao { .matchesPattern(value, fieldValidatorBean.getPattern(), fieldLabel) // Only applies if pattern is present .validateCustom(value, fieldValidatorBean.getCustom(), fieldLabel,contentResponseBean); // Add the custom validation here if (fieldValidatorBean.getCustom() != null && fieldValidatorBean.getCustom().equals(GepafinConstant.IS_PIVA)) { - String error = validateVatNumber(value, fieldValidatorBean.getCustom(), fieldLabel); + Long hubId = applicationEntity.getHubId(); + String error = validateVatNumber(value, fieldLabel,hubId); if(error != null) { validator.addError(error); } @@ -504,14 +505,14 @@ public class FormDao { }).filter(value -> !value.isEmpty()).findFirst().orElse(contentResponseBean.getId()); } - public String validateVatNumber(String value,String customRule,String fieldId){ + public String validateVatNumber(String value,String fieldId, Long hubId){ String error=null; if (value!=null && value.matches("^\\d{1,11}$")) { // Map customData=null; try { // Map vatCheckResponse = vatCheckDao.checkVatNumberApi(value); - vatCheckDao.checkVatNumber(value); + vatCheckDao.checkVatNumber(value, hubId); // if (Boolean.FALSE.equals(CollectionUtils.isEmpty(vatCheckResponse))) { // customData = vatCheckResponse; // } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java b/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java index 1c6869ad..342a853e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java @@ -3,12 +3,17 @@ package net.gepafin.tendermanagement.dao; import feign.FeignException; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.entities.CompanyEntity; +import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.VatCheckVersionTypeEnum; import net.gepafin.tendermanagement.model.response.VatCheckResponseBean; +import net.gepafin.tendermanagement.repositories.CompanyRepository; import net.gepafin.tendermanagement.repositories.GlobalConfigRepository; import net.gepafin.tendermanagement.service.feignClient.VatCheckV1Service; import net.gepafin.tendermanagement.service.feignClient.VatCheckV2Service; import net.gepafin.tendermanagement.util.Utils; +import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; +import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,6 +53,9 @@ public class VatCheckDao { @Autowired private GlobalConfigRepository globalConfigRepository; + @Autowired + private CompanyRepository companyRepository; + public final Logger log = LoggerFactory.getLogger(VatCheckDao.class); public VatCheckResponseBean checkVatNumberV1(String vatNumber) { @@ -56,6 +64,7 @@ public class VatCheckDao { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); if (Boolean.TRUE.equals(Boolean.parseBoolean(isVatCheckGloballyDisabled))) { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V1); return vatCheckResponseBean; } try { @@ -96,6 +105,7 @@ public class VatCheckDao { public static void processValidResponseV1(Map responseMap, VatCheckResponseBean vatCheckResponseBean) { Object dataObj = responseMap.get("data"); + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V1); if (dataObj instanceof Map rawDataMap) { Map responseBody = new LinkedHashMap<>(); rawDataMap.forEach((k, v) -> { @@ -118,9 +128,20 @@ public class VatCheckDao { } - public VatCheckResponseBean checkVatNumber(String vatNumber) { + public VatCheckResponseBean checkVatNumber(String vatNumber, Long hubId) { try { + CompanyEntity company = companyRepository.findByVatNumberAndHubId(vatNumber, hubId); + + if (company != null && Boolean.FALSE.equals(StringUtils.isEmpty(company.getJson()))) { + Map responseMap = Utils.convertJsonStringToMap(company.getJson()); + + VatCheckResponseBean jsonResponse = validateJsonFromDb(responseMap); + if (jsonResponse != null) { + return jsonResponse; + } + } + String vatApiVersion = getVatCheckVersion(); if(!isVatCheckApiV2(vatApiVersion)){ return checkVatNumberV1(vatNumber); @@ -134,6 +155,26 @@ public class VatCheckDao { return vatCheckResponseBean; } } + private VatCheckResponseBean validateJsonFromDb(Map responseMap) { + if (responseMap == null || !responseMap.containsKey("data")) return null; + + Object data = responseMap.get("data"); + + if (data instanceof Map dataMap && !dataMap.isEmpty()) { + VatCheckResponseBean response = new VatCheckResponseBean(); + processValidResponseV1(responseMap, response); + return response; + } + + if (data instanceof List dataList && !dataList.isEmpty()) { + VatCheckResponseBean response = new VatCheckResponseBean(); + processValidResponse(responseMap, response); + return response; + } + + return null; + } + public VatCheckResponseBean checkVatNumberV2(String vatNumber) { @@ -142,6 +183,7 @@ public class VatCheckDao { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); if (Boolean.TRUE.equals(Boolean.parseBoolean(isVatCheckGloballyDisabled))) { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V2); return vatCheckResponseBean; } try { @@ -175,6 +217,7 @@ public class VatCheckDao { public static void processValidResponse(Map responseMap, VatCheckResponseBean vatCheckResponseBean) { + vatCheckResponseBean.setVersion(VatCheckVersionTypeEnum.V2); if (responseMap == null || !responseMap.containsKey("data")) { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); return; diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java index 611925d3..00e6b93f 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/VatCheckResponseBean.java @@ -1,6 +1,8 @@ package net.gepafin.tendermanagement.model.response; import lombok.Getter; import lombok.Setter; +import net.gepafin.tendermanagement.enums.VatCheckVersionTypeEnum; + import java.util.Map; @Getter @@ -9,4 +11,5 @@ public class VatCheckResponseBean { private Boolean valid; private Map vatCheckResponse; private String message; + private VatCheckVersionTypeEnum version; } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java index 924f379c..f1d8f890 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java @@ -83,7 +83,9 @@ public class CompanyServiceImpl implements CompanyService { @Override @Transactional(readOnly = true) public VatCheckResponseBean checkVatNumber(HttpServletRequest request, String vatNumber) { - return vatCheckDao.checkVatNumber(vatNumber); + UserEntity userEntity = validator.validateUser(request); + Long hubId = userEntity.getHub().getId(); + return vatCheckDao.checkVatNumber(vatNumber, hubId); } @Override public CompanyEntity validateCompany(Long companyId) { From 23ed5df46485bef8276716a4b5a514b3b5e10131 Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 2 May 2025 18:26:22 +0530 Subject: [PATCH 27/63] Done ticket GEPAFINBE-210 --- .../constants/GepafinConstant.java | 8 ++ .../dao/ApplicationAmendmentRequestDao.java | 14 ++- .../tendermanagement/dao/ApplicationDao.java | 40 +++++++- .../dao/ApplicationEvaluationDao.java | 12 ++- .../tendermanagement/dao/EmailDao.java | 91 +++++++++++++++++++ .../tendermanagement/dao/EmailLogDao.java | 12 ++- .../dao/EmailNotificationDao.java | 7 +- .../gepafin/tendermanagement/dao/UserDao.java | 35 ++++++- .../entities/EmailLogEntity.java | 4 + .../entities/SystemEmailTemplatesEntity.java | 3 +- .../enums/EmailScenarioTypeEnum.java | 3 +- .../enums/NotificationTypeEnum.java | 3 +- .../enums/UserActionContextEnum.java | 4 +- .../enums/UserActionLogsEnum.java | 3 +- .../model/request/EmailLogRequest.java | 2 + .../ApplicationAmendmentRequestResponse.java | 1 + .../ApplicationEvaluationResponse.java | 1 + .../model/response/EmailReminderResponse.java | 16 ++++ .../response/EmailResendResponseBean.java | 12 +++ .../model/response/EmailSendResponse.java | 9 ++ .../InitiatePasswordResetResponse.java | 13 +++ .../tendermanagement/model/util/JWTToken.java | 11 +++ .../repositories/EmailLogRepository.java | 7 ++ .../ApplicationAmendmentRequestService.java | 7 +- .../service/ResendEmailService.java | 9 ++ .../tendermanagement/service/UserService.java | 6 +- ...pplicationAmendmentRequestServiceImpl.java | 12 +-- .../service/impl/AuthenticationService.java | 13 +-- .../service/impl/PecEmailService.java | 90 ++++++++++++++++-- .../service/impl/ResendEmailServiceImpl.java | 25 +++++ .../service/impl/SystemEmailService.java | 2 +- .../service/impl/UserServiceImpl.java | 8 +- .../gepafin/tendermanagement/util/Utils.java | 10 ++ .../api/ApplicationAmendmentRequestApi.java | 2 +- .../web/rest/api/EmailApi.java | 40 ++++++++ .../web/rest/api/UserApi.java | 9 +- ...ApplicationAmendmentRequestController.java | 21 +++-- .../web/rest/api/impl/EmailApiController.java | 52 +++++++++++ .../web/rest/api/impl/UserApiController.java | 10 +- .../db/changelog/db.changelog-1.0.0.xml | 19 ++++ ...lication_submission_failure_30_04_2025.sql | 46 ++++++++++ ...n_template_for_notification_22_04_2025.sql | 9 ++ src/main/resources/message_en.properties | 4 + src/main/resources/message_it.properties | 6 +- 44 files changed, 636 insertions(+), 75 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/EmailResendResponseBean.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java create mode 100644 src/main/java/net/gepafin/tendermanagement/service/ResendEmailService.java create mode 100644 src/main/java/net/gepafin/tendermanagement/service/impl/ResendEmailServiceImpl.java create mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/EmailApi.java create mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/EmailApiController.java create mode 100644 src/main/resources/db/dump/insert_system_email_template_for_application_submission_failure_30_04_2025.sql create mode 100644 src/main/resources/db/dump/update_json_template_for_notification_22_04_2025.sql diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 5c849a47..d0fb0136 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -537,6 +537,14 @@ public class GepafinConstant { public static final String APPLICATION_STATUS="applicationStatus"; 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"; + + + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index daa4391b..29935a03 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -140,6 +140,12 @@ public class ApplicationAmendmentRequestDao { @Autowired private ApplicationDao applicationDao; + @Autowired + private EmailLogRepository emailLogRepository; + + @Autowired + private EmailDao emailDao; + public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(Long applicationEvaluationId) { log.info("Fetching the application data for the Amendment process {}", applicationEvaluationId); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(applicationEvaluationId); @@ -300,6 +306,8 @@ public class ApplicationAmendmentRequestDao { log.info("Application submitted successfully for amendment", applicationAmendmentRequestResponse); if (Boolean.TRUE.equals(applicationAmendmentRequestResponse.getIsSendEmail())) { emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(applicationAmendmentRequestEntity); + EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); + applicationAmendmentRequestResponse.setEmailSendResponse(emailSendResponse); } return applicationAmendmentRequestResponse; } @@ -1168,12 +1176,13 @@ public class ApplicationAmendmentRequestDao { return response; } - public void sendReminderEmail(Long amendmentId) { + public EmailReminderResponse sendReminderEmail(Long amendmentId) { ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); Optional entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId()); + EmailReminderResponse emailReminderResponse = new EmailReminderResponse(); if (entityOptional.isPresent()) { ApplicationEntity applicationEntity = applicationService.validateApplication(entityOptional.get().getApplicationId()); UserEntity beneficiaryUser = userService.validateUser(applicationEntity.getUserId()); @@ -1186,10 +1195,13 @@ public class ApplicationAmendmentRequestDao { EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(emailTemplate.getEmailScenario(), RecipientTypeEnum.USER, beneficiaryUser.getId(), email, beneficiaryUser.getId(), applicationEntity.getId(), amendment.getId(), applicationEntity.getCall().getId()); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email), emailLogRequest); + EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); + emailReminderResponse.setEmailSendResponse(emailSendResponse); } else { 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) { diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index e95e1c8b..2492e8b0 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -1109,7 +1109,7 @@ public class ApplicationDao { if (userEntity.getBeneficiary() != null) { emailLogRequest.setRecipientType(RecipientTypeEnum.BENEFICIARY); email = userEntity.getBeneficiary().getEmail(); - emailLogRequest.setUserId(userEntity.getBeneficiary().getId()); + emailLogRequest.setRecipientId(userEntity.getBeneficiary().getId()); } emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email),emailLogRequest); List recipientEmails = new ArrayList<>(); @@ -2134,4 +2134,42 @@ 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 subjectPlaceholders = new HashMap<>(); + subjectPlaceholders.put("{{call_name}}", call.getName()); + + Map 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); + } + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 7052aad0..3adddf88 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -143,6 +143,9 @@ public class ApplicationEvaluationDao { @Autowired private ObjectMapper objectMapper; + @Autowired + private EmailDao emailDao; + private ApplicationEvaluationEntity convertToEntity(UserEntity user, ApplicationEvaluationRequest req, Long assignedApplciationId) { @@ -1876,7 +1879,7 @@ public class ApplicationEvaluationDao { assignedApplicationsEntity.getId()); ApplicationEvaluationEntity entity; - + EmailSendResponse emailSendResponse = new EmailSendResponse(); if (existingEntityOptional.isPresent()) { ApplicationEvaluationEntity existingEntity = existingEntityOptional.get(); // UserEntity userEntity = userService.validateUser(application.getUserId()); @@ -1888,6 +1891,8 @@ public class ApplicationEvaluationDao { application.setStatus(newStatus.getValue()); log.info("Status updated to ADMISSIBLE for applicationId: " + application.getId()); emailNotificationDao.sendAdmissibilityNotificationEmailForAdmissibleApplication(application); + emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); + } if(newStatus.equals(ApplicationStatusForEvaluation.TECHNICAL_EVALUATION) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))){ @@ -1944,13 +1949,16 @@ public class ApplicationEvaluationDao { application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application = applicationRepository.save(application); emailNotificationDao.sendInadmissibilityEmailForRejectedApplication(application,existingEntity); + emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); } Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.EVALUATION_RESULT); notificationDao.sendNotificationToInstructor(placeHolders,existingEntity,NotificationTypeEnum.EVALUATION_RESULT); - return convertToResponse(entity); + ApplicationEvaluationResponse response = convertToResponse(entity); + response.setEmailSendResponse(emailSendResponse); + return response; } return null; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java new file mode 100644 index 00000000..cfde04c1 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java @@ -0,0 +1,91 @@ +package net.gepafin.tendermanagement.dao; + + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.log4j.Log4j2; +import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.entities.CallEntity; +import net.gepafin.tendermanagement.entities.EmailLogEntity; +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.EmailLogRepository; +import net.gepafin.tendermanagement.service.CallService; +import net.gepafin.tendermanagement.util.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +@Component +@Log4j2 +public class EmailDao { + + @Autowired + EmailLogRepository emailLogRepository; + + @Autowired + EmailNotificationDao emailNotificationDao; + + @Autowired + private CallService callService; + + public EmailResendResponseBean resendEmail(HttpServletRequest request , Long userActionId){ + List emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceType(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue()); + if (emailLogs.isEmpty()) { + log.info("No emails found for given userActionId."); + } + EmailResendResponseBean emailResendResponseBean = new EmailResendResponseBean(); + for (EmailLogEntity log : emailLogs){ + EmailLogRequest emailLogRequest = new EmailLogRequest(); + emailLogRequest.setEmailType(EmailScenarioTypeEnum.valueOf(log.getEmailType())); + emailLogRequest.setRecipientType(RecipientTypeEnum.valueOf(log.getRecipientType())); + emailLogRequest.setRecipientId(log.getRecipientId()); + emailLogRequest.setUserId(log.getUserId()); + emailLogRequest.setApplicatioId(log.getApplicationId()); + emailLogRequest.setCallId(log.getCallId()); + emailLogRequest.setAmendmentId(log.getAmendmentId()); + + List 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); + return emailResendResponseBean; + } + + public EmailSendResponse buildEmailSendResponseFromRequest(HttpServletRequest request) { + Long userActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID); + boolean isEmailSendSuccess = isEmailSentSuccessfully(userActionId); + EmailSendResponse emailSendResponse = new EmailSendResponse(); + emailSendResponse.setIsEmailSend(isEmailSendSuccess); + emailSendResponse.setUserActionId(userActionId); + return emailSendResponse; + } + + public boolean isEmailSentSuccessfully(Long userActionId) { + List emailLogs = emailLogRepository.findByUserActionId(userActionId); + + for (EmailLogEntity log : emailLogs) { + if (EmailServiceTypeEnum.PEC_SERVICE.getValue().equals(log.getEmailServiceType()) && + StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus())) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailLogDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailLogDao.java index d74a6b3f..d95978fd 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailLogDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailLogDao.java @@ -1,6 +1,7 @@ package net.gepafin.tendermanagement.dao; import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.EmailLogEntity; import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; 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.VersionHistoryRequest; import net.gepafin.tendermanagement.repositories.EmailLogRepository; +import net.gepafin.tendermanagement.repositories.UserActionsRepository; import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.LoggingUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -22,6 +24,12 @@ public class EmailLogDao { @Autowired private EmailLogRepository emailLogRepository; + @Autowired + private HttpServletRequest request; + + @Autowired + private LoggingUtil loggingUtil; + public EmailLogEntity createEmailLog(EmailLogRequest emailLogRequest) { @@ -42,8 +50,8 @@ public class EmailLogDao { emailLogEntity.setApplicationId(emailLogRequest.getApplicatioId()); emailLogEntity.setAmendmentId(emailLogRequest.getAmendmentId()); emailLogEntity.setCallId(emailLogRequest.getCallId()); + emailLogEntity.setUserAction(loggingUtil.getUserActionLogById(emailLogRequest.getUserActionId())); emailLogEntity = saveEmailLogEntity(emailLogEntity); - return emailLogEntity; } public EmailLogEntity saveEmailLogEntity(EmailLogEntity emailLogEntity){ @@ -52,6 +60,7 @@ public class EmailLogDao { public EmailLogRequest createEmailLogRequest(EmailScenarioTypeEnum emailType, RecipientTypeEnum recipientType, Long recipientId, String recipientEmails, Long userId,Long applicationId,Long amendmentId,Long callId) { EmailLogRequest emailLogRequest = new EmailLogRequest(); + Long userActionId =(Long) request.getAttribute(GepafinConstant.USER_ACTION_ID); emailLogRequest.setEmailType(emailType); emailLogRequest.setRecipientType(recipientType); emailLogRequest.setRecipientId(recipientId); @@ -60,6 +69,7 @@ public class EmailLogDao { emailLogRequest.setApplicatioId(applicationId); emailLogRequest.setAmendmentId(amendmentId); emailLogRequest.setCallId(callId); + emailLogRequest.setUserActionId(userActionId); return emailLogRequest; } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java index 171ccbfa..3772ad71 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailNotificationDao.java @@ -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 , 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))) { emailConfig.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE.getValue()); EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType()); - emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); + emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); } else { emailConfig = retrieveEmailConfig(hubId); EmailService emailService = emailServiceFactory.getEmailService(emailConfig.getEmailServiceType()); - emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); - + emailService.sendEmail(subject, body, recipientEmails, emailConfig, emailLogRequest); } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java index 37ae9b44..b682b184 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java @@ -15,6 +15,7 @@ import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.SortBy; import net.gepafin.tendermanagement.repositories.BeneficiaryRepository; +import net.gepafin.tendermanagement.repositories.EmailLogRepository; import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.service.HubService; import net.gepafin.tendermanagement.service.RoleService; @@ -109,9 +110,15 @@ public class UserDao { @Autowired private EmailNotificationDao emailNotificationDao; + @Autowired + private EmailLogRepository emailLogRepository; + @Value("${fe.base.url}") private String feBaseUrl; + @Autowired + EmailDao emailDao; + public JWTToken createUser(HttpServletRequest request, String tempToken, UserReq userReq) { if (StringUtils.isEmpty(userReq.getHubUuid())) { @@ -134,7 +141,6 @@ public class UserDao { 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. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(beneficiary).build()); @@ -142,12 +148,30 @@ public class UserDao { /** This code is responsible for adding a version history log for the "Create user" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(userEntity).build()); + EmailSendResponse emailSendResponse = new EmailSendResponse(); if(Boolean.FALSE.equals(roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue()))){ sendEmailToOnboardingUser(userEntity, userReq ); + boolean isEmailSendSuccess = isEmailSentSuccessfully(userEntity.getId()); + emailSendResponse.setIsEmailSend(isEmailSendSuccess); + Long userActionId =(Long)request.getAttribute(GepafinConstant.USER_ACTION_ID); + emailSendResponse.setUserActionId(userActionId); } + JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId(),emailSendResponse); return token; } - public void sendEmailToOnboardingUser(UserEntity userEntity,UserReq userReq){ + + public boolean isEmailSentSuccessfully(Long userId) { + Optional 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; RoleStatusEnum roleStatus = RoleStatusEnum.valueOf(userEntity.getRoleEntity().getRoleType()); @@ -459,7 +483,7 @@ public class UserDao { return user; } - public void initiatePasswordReset(InitiatePasswordResetReq resetReq) { + public InitiatePasswordResetResponse initiatePasswordReset(InitiatePasswordResetReq resetReq) { UserEntity user = userRepository.findUserExcludingRoleType( resetReq.getEmail(), resetReq.getHubUuid(), @@ -478,8 +502,11 @@ public class UserDao { loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldUserEntity).newData(user).build()); log.info("Password reset token generated for user: {}", resetReq.getEmail()); - sendResetPasswordTokenEmail(user, token); + InitiatePasswordResetResponse initiatePasswordResetResponse = new InitiatePasswordResetResponse(); + EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); + initiatePasswordResetResponse.setEmailSendResponse(emailSendResponse); + return initiatePasswordResetResponse; } public void sendResetPasswordTokenEmail(UserEntity user, String token) { diff --git a/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java index 03ad4c2b..1a582a21 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/EmailLogEntity.java @@ -56,5 +56,9 @@ public class EmailLogEntity extends BaseEntity{ @Column(name = "is_deleted") private Boolean isDeleted; + + @ManyToOne + @JoinColumn(name = "user_action_id") + private UserActionEntity userAction; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java index b2c3cfb7..92d97e9f 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/SystemEmailTemplatesEntity.java @@ -55,7 +55,8 @@ public class SystemEmailTemplatesEntity extends BaseEntity { USER_ONBOARDING_CONFIDI("USER_ONBOARDING_CONFIDI"), USER_ONBOARDING_BANDI("USER_ONBOARDING_BANDI"), PASSWORD_RESET("PASSWORD_RESET"), - INADMISSIBILITY_TEMPLATE("INADMISSIBILITY_NOTIFICATION"); + INADMISSIBILITY_TEMPLATE("INADMISSIBILITY_NOTIFICATION"), + APPLICATION_SUBMISSION_FAILURE_NOTIFICATION("APPLICATION_SUBMISSION_FAILURE_NOTIFICATION"); private String value; SystemEmailTemplatesEntityTypeEnum(String value) { diff --git a/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java index 479912d7..908e554d 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/EmailScenarioTypeEnum.java @@ -11,7 +11,8 @@ public enum EmailScenarioTypeEnum { APPLICATION_ADMISSIBLE("APPLICATION_ADMISSIBLE"), USER_CREATION("USER_CREATION"), PASSWORD_RESET_REQUEST("PASSWORD_RESET_REQUEST"), - APPLICATION_REJECTED("APPLICATION_REJECTED"); + APPLICATION_REJECTED("APPLICATION_REJECTED"), + APPLICATION_SUBMISSION_FAILURE("APPLICATION_SUBMISSION_FAILURE"); private final String value; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java index 8957c03b..4430c2d6 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java @@ -14,7 +14,8 @@ public enum NotificationTypeEnum { EVALUATION_EXPIRED("EVALUATION_EXPIRED"), AMENDMENT_EXPIRATION_REMINDER("AMENDMENT_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; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index a1f7ee5c..9fae6ce7 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -215,7 +215,9 @@ public enum UserActionContextEnum { GET_ALL_USER_ACTION_BY_PAGINATION("GET_ALL_USER_ACTION_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_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; diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionLogsEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionLogsEnum.java index 555d3298..11aecdbc 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionLogsEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionLogsEnum.java @@ -12,7 +12,8 @@ public enum UserActionLogsEnum { DOWNLOAD("DOWNLOAD"), UPLOAD("UPLOAD"), SCHEDULER("SCHEDULER"), - SCRIPT("SCRIPT"); + SCRIPT("SCRIPT"), + EMAIL("EMAIL"); private final String value; diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/EmailLogRequest.java b/src/main/java/net/gepafin/tendermanagement/model/request/EmailLogRequest.java index b85f0e15..7cae845c 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/EmailLogRequest.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/EmailLogRequest.java @@ -37,4 +37,6 @@ public class EmailLogRequest { private Long callId; + private Long userActionId; + } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java index 8e8aeb83..ace60672 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java @@ -32,4 +32,5 @@ public class ApplicationAmendmentRequestResponse { private String internalNote; private ApplicationAmendmentRequestEnum status; private String emailTemplate; + private EmailSendResponse emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java index 47b018f9..187aa1dd 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java @@ -49,5 +49,6 @@ public class ApplicationEvaluationResponse { private EvaluationVersionEnum evaluationVersion; private String companyVatNumber; private String companyCodiceAteco; + private EmailSendResponse emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java new file mode 100644 index 00000000..d76b4fcd --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java @@ -0,0 +1,16 @@ +package net.gepafin.tendermanagement.model.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class EmailReminderResponse { + + @JsonProperty("emailSendResponse") + private EmailSendResponse emailSendResponse; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EmailResendResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/EmailResendResponseBean.java new file mode 100644 index 00000000..88f56e62 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/EmailResendResponseBean.java @@ -0,0 +1,12 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class EmailResendResponseBean { + + private EmailSendResponse emailSendResponse; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java new file mode 100644 index 00000000..c11d2c8d --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java @@ -0,0 +1,9 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; + +@Data +public class EmailSendResponse { + private Boolean isEmailSend; + private Long userActionId; +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java new file mode 100644 index 00000000..c14ef643 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java @@ -0,0 +1,13 @@ +package net.gepafin.tendermanagement.model.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class InitiatePasswordResetResponse { + private EmailSendResponse emailSendResponse; +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java index a57b7d59..a65f7d6e 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java +++ b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java @@ -3,6 +3,7 @@ package net.gepafin.tendermanagement.model.util; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import net.gepafin.tendermanagement.model.response.EmailSendResponse; import net.gepafin.tendermanagement.model.response.LoginResponse; /** @@ -15,10 +16,20 @@ public class JWTToken { @JsonProperty("user") private LoginResponse loginResponse; + + @JsonProperty("emailSendResponse") + private EmailSendResponse emailSendResponse; + public JWTToken(String token, LoginResponse loginResponse) { this.token = token; this.loginResponse = loginResponse; } + public JWTToken(String token, LoginResponse loginResponse, EmailSendResponse emailSendResponse) { + this.token = token; + this.loginResponse = loginResponse; + this.emailSendResponse = emailSendResponse; + } + } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java index 20475e0b..7ae53f22 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java @@ -1,11 +1,18 @@ package net.gepafin.tendermanagement.repositories; import net.gepafin.tendermanagement.entities.EmailLogEntity; +import net.gepafin.tendermanagement.entities.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +import java.util.Optional; public interface EmailLogRepository extends JpaRepository { List findByUserIdAndAmendmentIdAndIsDeletedFalse(Long userId,Long amendmentId); + List findByUserActionId(Long userActionId); + List findByUserActionIdAndEmailServiceType(Long userActionId, String emailServiceType); + + Optional findTopByUserIdAndEmailTypeAndIsDeletedFalseOrderByCreatedDateDesc(Long userId, String emailType); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java index d54d49d3..b19f77c4 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java @@ -8,10 +8,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationAmendmentPagination import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequest; import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequestBean; import net.gepafin.tendermanagement.model.request.CloseAmendmentRequest; -import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse; -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.response.*; import java.util.List; @@ -29,6 +26,6 @@ public interface ApplicationAmendmentRequestService { public List getAmendmentByApplicationId(HttpServletRequest request,Long applicationId,List statuses); public ApplicationAmendmentRequestResponse updateApplicationAmendmentStatus(HttpServletRequest request, Long applicationAmendmentId, ApplicationAmendmentRequestEnum status); - void sendReminderEmail(HttpServletRequest request,Long amendmentId); + EmailReminderResponse sendReminderEmail(HttpServletRequest request, Long amendmentId); PageableResponseBean> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/ResendEmailService.java b/src/main/java/net/gepafin/tendermanagement/service/ResendEmailService.java new file mode 100644 index 00000000..85275365 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/ResendEmailService.java @@ -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); +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/UserService.java b/src/main/java/net/gepafin/tendermanagement/service/UserService.java index bbe69e5f..c8224f0c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/UserService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/UserService.java @@ -8,9 +8,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.model.request.*; -import net.gepafin.tendermanagement.model.response.PageableResponseBean; -import net.gepafin.tendermanagement.model.response.UserSamlResponse; -import net.gepafin.tendermanagement.model.response.UserResponseBean; +import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.JWTToken; import java.util.List; @@ -28,7 +26,7 @@ public interface UserService { UserEntity validateUser(Long userId); - void initiatePasswordReset(InitiatePasswordResetReq resetReq); + InitiatePasswordResetResponse initiatePasswordReset(InitiatePasswordResetReq resetReq); Boolean resetPassword(ResetPasswordReq resetPasswordReq); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java index 1d7a38a9..a680ec1b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java @@ -12,10 +12,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationAmendmentPagination import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequest; import net.gepafin.tendermanagement.model.request.ApplicationAmendmentRequestBean; import net.gepafin.tendermanagement.model.request.CloseAmendmentRequest; -import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse; -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.response.*; import net.gepafin.tendermanagement.repositories.ApplicationAmendmentRequestRepository; import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository; import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService; @@ -145,17 +142,18 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm } @Override - public void sendReminderEmail(HttpServletRequest request,Long amendmentId) { + public EmailReminderResponse sendReminderEmail(HttpServletRequest request, Long amendmentId) { ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); + EmailReminderResponse response = new EmailReminderResponse(); Optional entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId()); if (entityOptional.isPresent()) { UserEntity user = validator.validatePreInstructor(request, entityOptional.get().getUserId()); - - applicationAmendmentRequestDao.sendReminderEmail(amendmentId); + response = applicationAmendmentRequestDao.sendReminderEmail(amendmentId); } + return response; } @Override diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java index 12ea0123..e112d40e 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java @@ -15,10 +15,7 @@ import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.*; import net.gepafin.tendermanagement.model.request.LoginReq; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; -import net.gepafin.tendermanagement.model.response.CompanyResponse; -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.response.*; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.repositories.LoginAttemptRepository; import net.gepafin.tendermanagement.repositories.SamlResponseRepository; @@ -122,7 +119,7 @@ public class AuthenticationService { createFailedLoginAttempt(loginAttemptEntity, e.getMessage()); throw e; } - return getJWTTokenBean(user, loginReq.getRememberMe(), loginAttemptEntity.getId()); + return getJWTTokenBean(user, loginReq.getRememberMe(), loginAttemptEntity.getId(),null); } public LoginAttemptEntity prepareLoginAttemptEntity(LoginReq loginUserReq, HttpServletRequest request) { @@ -145,7 +142,7 @@ public class AuthenticationService { loginAttemptEntity.setErrorMsg(errorMsg); loginAttemptDao.createLoginAttempt(loginAttemptEntity); } - public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId) { + public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId, EmailSendResponse emailSendResponse) { UserEntity oldUserEntity = Utils.getClonedEntityForData(user); user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); user = userRepository.save(user); @@ -156,7 +153,7 @@ public class AuthenticationService { 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. **/ 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.setUserId(userEntity.getId()); LoginAttemptEntity loginAttempt = createSuccessLoginAttempt(loginAttemptEntity); - return getJWTTokenBean(userEntity, Boolean.TRUE, loginAttempt.getId()); + return getJWTTokenBean(userEntity, Boolean.TRUE, loginAttempt.getId(),null); } catch (Exception e) { log.info("Authentication login failed for email: {}",e.getMessage()); loginAttemptEntity.setUserId(userId); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java index 8c44af9d..19742a8c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/PecEmailService.java @@ -1,25 +1,32 @@ 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.Unirest; import lombok.extern.slf4j.Slf4j; import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.dao.ApplicationDao; 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.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.StatusTypeEnum; import net.gepafin.tendermanagement.model.request.EmailConfig; 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.util.Utils; 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.Value; import org.springframework.stereotype.Service; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Slf4j @Service @@ -30,20 +37,26 @@ public class PecEmailService implements EmailService { @Value("${isPecServiceEnabled}") private String isPecServiceEnabled; - + @Autowired private Validator validator; @Autowired private EmailLogDao emailLogDao; + @Autowired + private NotificationDao notificationDao; + + @Autowired + private ApplicationDao applicationDao; + @Override public void sendEmail(String subject, String body, List recipientEmails, EmailConfig emailConfig, EmailLogRequest emailLogRequest) { if (Boolean.FALSE.equals(Boolean.parseBoolean(isEmailSendingEnabled))) { return; } - + PecEmailRequest emailRequest = new PecEmailRequest(); emailRequest.setSender(emailConfig.getSender()); emailRequest.setSubject(subject); @@ -67,13 +80,27 @@ public class PecEmailService implements EmailService { .header("Content-Type", "application/json") .body(Utils.convertObjectToJson(emailRequest)) // Serialize the emailRequest object to JSON .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) { emailLogRequest.setSendStatus(StatusTypeEnum.FAILED.getValue()); emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE); emailLogRequest.setErrorMessage(e.getMessage()); - emailLogDao.createEmailLog(emailLogRequest); - throw new RuntimeException("Failed to send email via PEC: " + response2.getStatus()); + sendNotificationOnFailure(emailLogRequest.getUserId(),emailLogRequest.getEmailType()); + if (EmailScenarioTypeEnum.APPLICATION_SUBMITTED.equals(emailLogRequest.getEmailType())) { + applicationDao.sendApplicationSubmissionFailureEmail(emailLogRequest); + } } if(response2 != null) { emailLogRequest.setEmailServiceResponse(response2.getBody()); @@ -82,6 +109,57 @@ public class PecEmailService implements EmailService { emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.PEC_SERVICE); emailLogDao.createEmailLog(emailLogRequest); } + + private void sendNotificationOnFailure(Long userId, EmailScenarioTypeEnum emailScenarioTypeEnum) { + if (userId == null) { + log.warn("Cannot send notification: userId is null."); + return; + } + + Map 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("")) { + 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; + } + } } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ResendEmailServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ResendEmailServiceImpl.java new file mode 100644 index 00000000..bfe199b3 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ResendEmailServiceImpl.java @@ -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); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java index fde6fd3e..95939082 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java @@ -55,7 +55,7 @@ public class SystemEmailService implements EmailService { emailLogRequest.setEmailBody(body); emailLogRequest.setSendStatus(StatusTypeEnum.SUCCESS.getValue()); emailLogRequest.setRecipientEmails(Utils.listToCommaSeparatedString(recipientEmails)); - + emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE); if (Boolean.FALSE.equals(validator.isTestProfileActivated())) { MessageResponse response = null; try { diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java index 0b13ef44..d2c2b032 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java @@ -11,9 +11,7 @@ import net.gepafin.tendermanagement.model.request.UpdateUserReq; import net.gepafin.tendermanagement.model.request.UserReq; import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.model.request.*; -import net.gepafin.tendermanagement.model.response.PageableResponseBean; -import net.gepafin.tendermanagement.model.response.UserSamlResponse; -import net.gepafin.tendermanagement.model.response.UserResponseBean; +import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.util.LoggingUtil; @@ -78,8 +76,8 @@ public class UserServiceImpl implements UserService { } @Override - public void initiatePasswordReset(InitiatePasswordResetReq resetReq) { - userDao.initiatePasswordReset(resetReq); + public InitiatePasswordResetResponse initiatePasswordReset(InitiatePasswordResetReq resetReq) { + return userDao.initiatePasswordReset(resetReq); } @Override diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 343e742a..31f3c81c 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -1011,5 +1011,15 @@ public class Utils { } } + public static List commaSeparatedStringToList(String emails) { + if (emails == null || emails.isEmpty()) { + return new ArrayList<>(); + } + return Arrays.stream(emails.split(",")) + .map(String::trim) + .collect(Collectors.toList()); + } + + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java index eb0c05f0..5d81ce7e 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java @@ -183,7 +183,7 @@ public interface ApplicationAmendmentRequestApi { @ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })) }) @PostMapping(value = "/{amendmentId}/reminder", produces = MediaType.APPLICATION_JSON_VALUE) - ResponseEntity> sendReminderEmail(HttpServletRequest request, + ResponseEntity> sendReminderEmail(HttpServletRequest request, @Parameter( required = true) @PathVariable(value = "amendmentId") Long amendmentId); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/EmailApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/EmailApi.java new file mode 100644 index 00000000..2bbeca34 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/EmailApi.java @@ -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> resendEmail( + HttpServletRequest request, + @Parameter(description = "The User Action ID", required = true) + @RequestParam("userActionId") Long userActionId); +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java index 6f7aaf8e..3f0d9410 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java @@ -10,10 +10,7 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.model.request.*; -import net.gepafin.tendermanagement.model.response.PageableResponseBean; -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.response.*; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; @@ -121,8 +118,8 @@ public interface UserApi { @RequestMapping(value = "/reset-password/initiate", produces = {"application/json"}, method = RequestMethod.POST) - ResponseEntity> initiatePasswordReset(HttpServletRequest request, - @Parameter(description = "Initiate password reset request object", required = true) @Valid @RequestBody InitiatePasswordResetReq initiatePasswordResetReq); + ResponseEntity> initiatePasswordReset(HttpServletRequest request, + @Parameter(description = "Initiate password reset request object", required = true) @Valid @RequestBody InitiatePasswordResetReq initiatePasswordResetReq); @Operation(summary = "Api to reset password", responses = { diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java index 585a6d1e..c92a060b 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java @@ -8,10 +8,7 @@ import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum; import net.gepafin.tendermanagement.enums.UserActionContextEnum; import net.gepafin.tendermanagement.enums.UserActionLogsEnum; import net.gepafin.tendermanagement.model.request.*; -import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse; -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.response.*; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService; import net.gepafin.tendermanagement.util.LoggingUtil; @@ -176,15 +173,25 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme .body(new Response<>(applicationResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_UPDATE_SUCCESSFULLY_MSG))); } @Override - public ResponseEntity> sendReminderEmail( + public ResponseEntity> sendReminderEmail( HttpServletRequest request, Long 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); + + if (!emailSendResponse.getEmailSendResponse().getIsEmailSend()) { + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(emailSendResponse, Status.EXCEPTION_ERROR, Translator.toLocale(GepafinConstant.REMINDER_EMAIL_FAILED_MSG))); + } return ResponseEntity.status(HttpStatus.OK) - .body(new Response<>(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 diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/EmailApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/EmailApiController.java new file mode 100644 index 00000000..59d55ac0 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/EmailApiController.java @@ -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> 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))); + + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java index 14945d65..3e262b77 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java @@ -11,9 +11,7 @@ import net.gepafin.tendermanagement.enums.UserActionContextEnum; import net.gepafin.tendermanagement.enums.UserActionLogsEnum; import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.model.request.*; -import net.gepafin.tendermanagement.model.response.PageableResponseBean; -import net.gepafin.tendermanagement.model.response.UserSamlResponse; -import net.gepafin.tendermanagement.model.response.UserResponseBean; +import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.Response; 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))); } @Override - public ResponseEntity> initiatePasswordReset(HttpServletRequest httpServletRequest,InitiatePasswordResetReq request) { + public ResponseEntity> initiatePasswordReset(HttpServletRequest httpServletRequest, InitiatePasswordResetReq request) { log.info("Initiating password reset for email: {}", request.getEmail()); /** This code is responsible for "Initiating Password Reset Request" operation. **/ loggingUtil.logUserAction(UserActionRequest.builder().request(httpServletRequest).actionType(UserActionLogsEnum.UPDATE) .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()); - 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 diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 38e13676..9d507532 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2746,4 +2746,23 @@ + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/dump/insert_system_email_template_for_application_submission_failure_30_04_2025.sql b/src/main/resources/db/dump/insert_system_email_template_for_application_submission_failure_30_04_2025.sql new file mode 100644 index 00000000..a1e0b030 --- /dev/null +++ b/src/main/resources/db/dump/insert_system_email_template_for_application_submission_failure_30_04_2025.sql @@ -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', + ' + +
+

Buongiorno,

+ +

+ Si prega di notare che si è verificato un errore durante linvio dell email "{{scenario}}" per la chiamata: {{call_name}}.

+

+ Dettagli:
+ - ID Applicazione: {{application_id}}
+ - Nome Azienda: {{company_name}}
+ - Numero Protocollo: {{protocol_number}}
+ - ID Azione Utente: {{user_action_id}} +

+ +

+ Si prega di effettuare i controlli appropriati e di adottare le misure correttive necessarie. +

+ +

Cordiali saluti,

+

Gepafin S.p.a.

+
+ + ', + 'ERRORE INVIO EMAIL - BANDO {{call_name}}', + NULL, + true, + false, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP, + 'APPLICATION_SUBMISSION_FAILURE' +); \ No newline at end of file diff --git a/src/main/resources/db/dump/update_json_template_for_notification_22_04_2025.sql b/src/main/resources/db/dump/update_json_template_for_notification_22_04_2025.sql new file mode 100644 index 00000000..9aefaedf --- /dev/null +++ b/src/main/resources/db/dump/update_json_template_for_notification_22_04_2025.sql @@ -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' +); diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index e67042ab..b09c8d62 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -400,3 +400,7 @@ insufficient.score.msg = Insufficient score to pass to the technical and economi password.expired.for.login.to.odessa = Odessa login password has been expired. invalid.user=Invalid user. + +reminder.email.sent.failed.msg = Failed to send reminder email +resend.email.sent.success.msg = Email resend successfully +resend.email.sent.failed.msg = Failed to resend the email. \ No newline at end of file diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index fd7f09e1..faafb940 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -390,4 +390,8 @@ insufficient.score.msg = Punteggio non sufficiente per passaggio alla valutazion validation.table.message=I dati per il campo {0} non sono presenti. password.expired.for.login.to.odessa = La password di accesso a Odessa è scaduta -invalid.user=Utente non valido. \ No newline at end of file +invalid.user=Utente non valido. + +reminder.email.sent.failed.msg = Impossibile inviare l'e-mail di promemoria +resend.email.sent.success.msg = Email reinviata con successo +resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail. \ No newline at end of file From d03b7d49c41f382c6f3c1f155e488098a8f266ac Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 5 May 2025 18:05:52 +0530 Subject: [PATCH 28/63] Fixed email log issue --- .../tendermanagement/service/impl/SystemEmailService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java index fde6fd3e..0cc64b89 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/SystemEmailService.java @@ -55,7 +55,7 @@ public class SystemEmailService implements EmailService { emailLogRequest.setEmailBody(body); emailLogRequest.setSendStatus(StatusTypeEnum.SUCCESS.getValue()); emailLogRequest.setRecipientEmails(Utils.listToCommaSeparatedString(recipientEmails)); - + emailLogRequest.setEmailServiceType(EmailServiceTypeEnum.SYSTEM_EMAIL_SERVICE); if (Boolean.FALSE.equals(validator.isTestProfileActivated())) { MessageResponse response = null; try { @@ -73,7 +73,10 @@ public class SystemEmailService implements EmailService { throw new RuntimeException("Failed to send email via Mailgun: " + (response != null ? response.getMessage() : "No response from Mailgun"), e); } - emailLogRequest.setEmailServiceResponse(response.toString()); + if(response != null) { + emailLogRequest.setEmailServiceResponse(response.toString()); + } + emailLogDao.createEmailLog(emailLogRequest); } } From 385ee2f755235b120a10b1d1f373dd30a10e5dac Mon Sep 17 00:00:00 2001 From: Piyush Date: Thu, 8 May 2025 19:21:59 +0530 Subject: [PATCH 29/63] Enhanced PEC error response saving --- .../dao/ApplicationAmendmentRequestDao.java | 9 +++ .../dao/ApplicationEvaluationDao.java | 11 +++- .../dao/AssignedApplicationsDao.java | 1 + .../tendermanagement/dao/EmailDao.java | 63 ++++++++++++------- .../gepafin/tendermanagement/dao/UserDao.java | 14 +++++ .../ApplicationAmendmentRequestEntity.java | 8 ++- .../ApplicationAmendmentRequestView.java | 26 +++++--- .../entities/ApplicationEvaluationEntity.java | 5 ++ .../entities/AssignedApplicationsView.java | 6 ++ .../entities/EmailSendResponseConverter.java | 40 ++++++++++++ .../tendermanagement/entities/UserEntity.java | 7 +++ ...plicationAmendmentRequestViewResponse.java | 3 + .../AssignedApplicationViewResponse.java | 3 + .../model/response/EmailSendResponse.java | 2 + .../model/response/UserResponseBean.java | 1 + .../repositories/EmailLogRepository.java | 4 +- .../gepafin/tendermanagement/util/Utils.java | 19 ++++++ .../db/changelog/db.changelog-1.0.0.xml | 30 +++++++++ ...ate_application_amendment_request_view.sql | 27 ++++++++ .../dump/update_assigned_application_view.sql | 53 ++++++++++++++++ 20 files changed, 296 insertions(+), 36 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java create mode 100644 src/main/resources/db/dump/update_application_amendment_request_view.sql create mode 100644 src/main/resources/db/dump/update_assigned_application_view.sql diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 29935a03..a0d0ff7f 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -1,5 +1,6 @@ package net.gepafin.tendermanagement.dao; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.criteria.CriteriaBuilder; @@ -308,6 +309,7 @@ public class ApplicationAmendmentRequestDao { emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(applicationAmendmentRequestEntity); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); applicationAmendmentRequestResponse.setEmailSendResponse(emailSendResponse); + saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity); } return applicationAmendmentRequestResponse; } @@ -1197,6 +1199,7 @@ public class ApplicationAmendmentRequestDao { emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email), emailLogRequest); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); emailReminderResponse.setEmailSendResponse(emailSendResponse); + saveEmailSendResponse(emailSendResponse, amendment); } else { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.BENEFICIARY_EMAIL_NOT_FOUND_MSG)); } @@ -1551,8 +1554,14 @@ public class ApplicationAmendmentRequestDao { applicationAmendmentRequestViewResponse.setExpirationDate(applicationAmendmentRequestView.getExpirationDate()); applicationAmendmentRequestViewResponse.setAssigendUserName(applicationAmendmentRequestView.getAssigendUserName()); applicationAmendmentRequestViewResponse.setStatus(applicationAmendmentRequestView.getStatus()); + applicationAmendmentRequestViewResponse.setEmailSendResponse(applicationAmendmentRequestView.getEmailSendResponse()); return applicationAmendmentRequestViewResponse; } + private void saveEmailSendResponse(EmailSendResponse newResponses, ApplicationAmendmentRequestEntity amendment) { + List mergedResponses = Utils.mergeEmailSendResponses(amendment.getEmailSendResponse(), newResponses); + amendment.setEmailSendResponse(mergedResponses); + applicationAmendmentRequestRepository.save(amendment); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 3adddf88..d7a03f62 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -1892,7 +1892,7 @@ public class ApplicationEvaluationDao { log.info("Status updated to ADMISSIBLE for applicationId: " + application.getId()); emailNotificationDao.sendAdmissibilityNotificationEmailForAdmissibleApplication(application); emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - + saveEmailSendResponseToEvaluation(emailSendResponse,existingEntity); } if(newStatus.equals(ApplicationStatusForEvaluation.TECHNICAL_EVALUATION) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))){ @@ -1950,6 +1950,7 @@ public class ApplicationEvaluationDao { application = applicationRepository.save(application); emailNotificationDao.sendInadmissibilityEmailForRejectedApplication(application,existingEntity); emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); + saveEmailSendResponseToEvaluation(emailSendResponse,existingEntity); } Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); @@ -1963,6 +1964,14 @@ public class ApplicationEvaluationDao { return null; } + private void saveEmailSendResponseToEvaluation(EmailSendResponse newResponse, ApplicationEvaluationEntity evaluationEntity) { + List mergedResponses = Utils.mergeEmailSendResponses( + evaluationEntity.getEmailSendResponse(), newResponse + ); + evaluationEntity.setEmailSendResponse(mergedResponses); + applicationEvaluationRepository.save(evaluationEntity); + } + public ApplicationEvaluationEntity validateApplicationEvaluationByApplicationId(Long applicationId) { return applicationEvaluationRepository .findByApplicationIdAndIsDeletedFalse(applicationId) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java index 17f18c9c..c7263313 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java @@ -470,6 +470,7 @@ public class AssignedApplicationsDao { response.setCompanyName(view.getCompanyName()); response.setCreatedDate(view.getCreatedDate()); response.setUpdatedDate(view.getUpdatedDate()); + response.setEmailSendResponse(view.getEmailSendResponse()); return response; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java index cfde04c1..66b20b77 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java @@ -20,8 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.Set; +import java.util.*; @Component @Log4j2 @@ -36,21 +35,25 @@ public class EmailDao { @Autowired private CallService callService; + @Autowired + private EmailLogDao emailLogDao; + public EmailResendResponseBean resendEmail(HttpServletRequest request , Long userActionId){ - List emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceType(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue()); + List emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceTypeAndSendStatus(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue(),StatusTypeEnum.FAILED.getValue()); if (emailLogs.isEmpty()) { log.info("No emails found for given userActionId."); } EmailResendResponseBean emailResendResponseBean = new EmailResendResponseBean(); for (EmailLogEntity log : emailLogs){ - EmailLogRequest emailLogRequest = new EmailLogRequest(); - emailLogRequest.setEmailType(EmailScenarioTypeEnum.valueOf(log.getEmailType())); - emailLogRequest.setRecipientType(RecipientTypeEnum.valueOf(log.getRecipientType())); - emailLogRequest.setRecipientId(log.getRecipientId()); - emailLogRequest.setUserId(log.getUserId()); - emailLogRequest.setApplicatioId(log.getApplicationId()); - emailLogRequest.setCallId(log.getCallId()); - emailLogRequest.setAmendmentId(log.getAmendmentId()); + 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 recipients = Utils.commaSeparatedStringToList(log.getRecipientEmails()); CallEntity call = callService.validateCall(log.getCallId()); @@ -69,23 +72,37 @@ public class EmailDao { public EmailSendResponse buildEmailSendResponseFromRequest(HttpServletRequest request) { Long userActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID); - boolean isEmailSendSuccess = isEmailSentSuccessfully(userActionId); - EmailSendResponse emailSendResponse = new EmailSendResponse(); - emailSendResponse.setIsEmailSend(isEmailSendSuccess); - emailSendResponse.setUserActionId(userActionId); - return emailSendResponse; - } - - public boolean isEmailSentSuccessfully(Long userActionId) { List emailLogs = emailLogRepository.findByUserActionId(userActionId); + boolean allSuccess = true; + String emailScenario = null; + for (EmailLogEntity log : emailLogs) { - if (EmailServiceTypeEnum.PEC_SERVICE.getValue().equals(log.getEmailServiceType()) && - StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus())) { - return true; + if (emailScenario == null) { + emailScenario = log.getEmailType(); + } + boolean isSuccess = EmailServiceTypeEnum.PEC_SERVICE.getValue().equals(log.getEmailServiceType()) && + StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus()); + if (!isSuccess) { + allSuccess = false; + break; } } - return false; + + 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; + } + + + + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java index b682b184..234ffa1d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java @@ -43,6 +43,7 @@ import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; @@ -155,6 +156,8 @@ public class UserDao { emailSendResponse.setIsEmailSend(isEmailSendSuccess); Long userActionId =(Long)request.getAttribute(GepafinConstant.USER_ACTION_ID); emailSendResponse.setUserActionId(userActionId); + emailSendResponse.setEmailScenario(EmailScenarioTypeEnum.USER_CREATION); + saveEmailSendResponseToUser(emailSendResponse,userEntity); } JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId(),emailSendResponse); return token; @@ -406,6 +409,7 @@ public class UserDao { RoleResponseBean roleResponseBean = roleDao.convertRoleEntityToRoleResponse(userEntity.getRoleEntity()); userResponseBean.setRole(roleResponseBean); userResponseBean.setLastLogin(userEntity.getLastLogin()); + userResponseBean.setEmailSendResponse(userEntity.getEmailSendResponse()); List companyResponseBeans = companyDao.getCompanyByUserId(userEntity.getId()); userResponseBean.setCompanies(companyResponseBeans); if (userEntity.getBeneficiary() == null) { @@ -506,8 +510,18 @@ public class UserDao { InitiatePasswordResetResponse initiatePasswordResetResponse = new InitiatePasswordResetResponse(); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); initiatePasswordResetResponse.setEmailSendResponse(emailSendResponse); + saveEmailSendResponseToUser(emailSendResponse,user); return initiatePasswordResetResponse; } + + private void saveEmailSendResponseToUser(EmailSendResponse newResponse, UserEntity user) { + List mergedResponses = Utils.mergeEmailSendResponses( + user.getEmailSendResponse(), newResponse + ); + user.setEmailSendResponse(mergedResponses); + userRepository.save(user); + } + public void sendResetPasswordTokenEmail(UserEntity user, String token) { SystemEmailTemplateResponse emailTemplate = systemEmailTemplatesService.retrieveTemplateByTypeAndCall( diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java index 840ad050..eb71f5c1 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java @@ -2,7 +2,10 @@ package net.gepafin.tendermanagement.entities; import jakarta.persistence.*; import lombok.Data; +import net.gepafin.tendermanagement.model.response.EmailSendResponse; + import java.time.LocalDateTime; +import java.util.List; @Entity @Table(name="application_amendment_request") @@ -53,7 +56,10 @@ public class ApplicationAmendmentRequestEntity extends BaseEntity { @Column(name = "amendment_document") private String amendmentDocument; - @Column(name = "CLOSING_DATE") private LocalDateTime closingDate; + + @Convert(converter = EmailSendResponseConverter.class) + @Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT") + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java index b5ee0ecc..c458af08 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java @@ -3,9 +3,12 @@ package net.gepafin.tendermanagement.entities; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; +import net.gepafin.tendermanagement.model.BaseBean; +import net.gepafin.tendermanagement.model.response.EmailSendResponse; import org.hibernate.annotations.Immutable; import java.time.LocalDateTime; +import java.util.List; @Entity @Immutable @@ -13,12 +16,12 @@ import java.time.LocalDateTime; @Getter @Setter @IdClass(ApplicationAmendmentRequestViewId.class) -public class ApplicationAmendmentRequestView { +public class ApplicationAmendmentRequestView extends BaseEntity { - @Id - @Column(name = "ID") - private Long id; +// @Id +// @Column(name = "ID") +// private Long id; @Column(name = "APPLICATION_ID") private Long applicationId; @@ -56,12 +59,17 @@ public class ApplicationAmendmentRequestView { @Column(name = "APPLICATION_USER_ID") private Long applicationUserId; - @Column(name = "CREATED_DATE") - private String createdDate; - - @Column(name = "UPDATED_DATE") - private String updatedDate; +// @Column(name = "CREATED_DATE") +// private String createdDate; +// +// @Column(name = "UPDATED_DATE") +// private String updatedDate; @Column(name = "IS_DELETED") private Boolean isDeleted; + + @Convert(converter = EmailSendResponseConverter.class) + @Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT") + private List emailSendResponse; + } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java index 045a1bdb..b8b00d3b 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationEvaluationEntity.java @@ -2,8 +2,10 @@ package net.gepafin.tendermanagement.entities; import jakarta.persistence.*; import lombok.Data; +import net.gepafin.tendermanagement.model.response.EmailSendResponse; import java.time.LocalDateTime; +import java.util.List; @Data @Entity @@ -71,4 +73,7 @@ public class ApplicationEvaluationEntity extends BaseEntity{ @Column(name = "evaluationVersion") private String evaluationVersion; + @Convert(converter = EmailSendResponseConverter.class) + @Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT") + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java index a446daff..71cd1075 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java @@ -2,9 +2,11 @@ package net.gepafin.tendermanagement.entities; import jakarta.persistence.*; import lombok.Data; +import net.gepafin.tendermanagement.model.response.EmailSendResponse; import org.hibernate.annotations.Immutable; import java.time.LocalDateTime; +import java.util.List; @Entity @Immutable @@ -58,4 +60,8 @@ public class AssignedApplicationsView{ @Column(name = "IS_DELETED") private Boolean isDeleted; + + @Convert(converter = EmailSendResponseConverter.class) + @Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT") + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java b/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java new file mode 100644 index 00000000..d02a842d --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java @@ -0,0 +1,40 @@ +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, String> { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public String convertToDatabaseColumn(List attribute) { + try { + return objectMapper.writeValueAsString(attribute); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Error converting list to JSON", e); + } + } + + @Override + public List convertToEntityAttribute(String dbData) { + if (dbData == null || dbData.isBlank()) { + return List.of(); // or null if you prefer + } + try { + return objectMapper.readValue(dbData, new TypeReference>() {}); + } catch (IOException e) { + throw new IllegalArgumentException("Error reading JSON from database", e); + } + } + +} + diff --git a/src/main/java/net/gepafin/tendermanagement/entities/UserEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/UserEntity.java index 606f52d9..86147cdf 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/UserEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/UserEntity.java @@ -7,8 +7,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; +import net.gepafin.tendermanagement.model.response.EmailSendResponse; import java.time.LocalDateTime; +import java.util.List; @Entity @Table(name = "GEPAFIN_USER") @@ -69,4 +71,9 @@ public class UserEntity extends BaseEntity { @ManyToOne @JoinColumn(name = "HUB_ID") private HubEntity hub; + + @Convert(converter = EmailSendResponseConverter.class) + @Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT") + private List emailSendResponse; + } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java index e4139131..9c73d4d9 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java @@ -3,6 +3,7 @@ package net.gepafin.tendermanagement.model.response; import lombok.Data; import java.time.LocalDateTime; +import java.util.List; @Data public class ApplicationAmendmentRequestViewResponse { @@ -24,4 +25,6 @@ public class ApplicationAmendmentRequestViewResponse { private String assigendUserName; private String status; + + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java index 94c2335a..e9a1f9f5 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/AssignedApplicationViewResponse.java @@ -6,6 +6,7 @@ import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.model.BaseBean; import java.time.LocalDateTime; +import java.util.List; @Data public class AssignedApplicationViewResponse extends BaseBean { @@ -20,5 +21,7 @@ public class AssignedApplicationViewResponse extends BaseBean { private Long protocolNumber; private String callName; private String companyName; + private List emailSendResponse; + } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java index c11d2c8d..4cc303f7 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/EmailSendResponse.java @@ -1,9 +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; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java index c8724d43..4b76be85 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java @@ -48,4 +48,5 @@ public class UserResponseBean extends BaseBean { private Boolean thirdParty; private String emailPec; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java index 7ae53f22..f12d0e3b 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java @@ -11,8 +11,8 @@ public interface EmailLogRepository extends JpaRepository { List findByUserIdAndAmendmentIdAndIsDeletedFalse(Long userId,Long amendmentId); List findByUserActionId(Long userActionId); - List findByUserActionIdAndEmailServiceType(Long userActionId, String emailServiceType); - + List findByUserActionIdAndEmailServiceTypeAndSendStatus( + Long userActionId, String emailServiceType, String sendStatus); Optional findTopByUserIdAndEmailTypeAndIsDeletedFalseOrderByCreatedDateDesc(Long userId, String emailType); } diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 31f3c81c..a5f1fed6 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -15,6 +15,7 @@ import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -36,9 +37,11 @@ import jakarta.persistence.criteria.Root; import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.MatchModeEnum; import net.gepafin.tendermanagement.model.request.FilterCriteria; import net.gepafin.tendermanagement.model.request.GlobalFilters; +import net.gepafin.tendermanagement.model.response.EmailSendResponse; import net.gepafin.tendermanagement.web.rest.api.errors.*; import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; @@ -1021,5 +1024,21 @@ public class Utils { } + public static List mergeEmailSendResponses(List existingResponses, EmailSendResponse newResponse) { + Map 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()); + } + } diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 9d507532..12d7a374 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2765,4 +2765,34 @@ path="db/dump/insert_system_email_template_for_application_submission_failure_30_04_2025.sql"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/dump/update_application_amendment_request_view.sql b/src/main/resources/db/dump/update_application_amendment_request_view.sql new file mode 100644 index 00000000..9224de74 --- /dev/null +++ b/src/main/resources/db/dump/update_application_amendment_request_view.sql @@ -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; \ No newline at end of file diff --git a/src/main/resources/db/dump/update_assigned_application_view.sql b/src/main/resources/db/dump/update_assigned_application_view.sql new file mode 100644 index 00000000..36d8a3ec --- /dev/null +++ b/src/main/resources/db/dump/update_assigned_application_view.sql @@ -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; From 6145232330d2384ef8fed037a19953a1f30336b3 Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 9 May 2025 12:17:09 +0530 Subject: [PATCH 30/63] updated code --- .../db/changelog/db.changelog-1.0.0.xml | 6 ++++ ...lication_submission_failure_08_05_2025.sql | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/main/resources/db/dump/update_system_email_template_for_application_submission_failure_08_05_2025.sql diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 12d7a374..bff80f3f 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2795,4 +2795,10 @@ path="db/dump/update_assigned_application_view.sql"/> + + + + + diff --git a/src/main/resources/db/dump/update_system_email_template_for_application_submission_failure_08_05_2025.sql b/src/main/resources/db/dump/update_system_email_template_for_application_submission_failure_08_05_2025.sql new file mode 100644 index 00000000..bc3a43b3 --- /dev/null +++ b/src/main/resources/db/dump/update_system_email_template_for_application_submission_failure_08_05_2025.sql @@ -0,0 +1,29 @@ +UPDATE gepafin_schema.system_email_template +SET html_content = ' + +
+

Buongiorno,

+ +

+

+ Si prega di notare che si è verificato un errore durante linvio dell e-mail nello scenario "{{scenario}}" per la chiamata: {{call_name}}. +

+ +

+ +

+ Dettagli:
+ - ID Applicazione: {{application_id}}
+ - Nome Azienda: {{company_name}}
+ - Numero Protocollo: {{protocol_number}}
+ - ID Azione Utente: {{user_action_id}} +

+ +

Si prega di effettuare i controlli appropriati e di adottare le misure correttive necessarie.

+ +

Cordiali saluti,

+

Gepafin S.p.a.

+
+ +' +WHERE template_name = 'Application submission failure notification'; From 2c20c55e732b75059b69c9dd422852d294de07e2 Mon Sep 17 00:00:00 2001 From: nisha Date: Fri, 9 May 2025 12:29:32 +0530 Subject: [PATCH 31/63] Done ticket GEPAFINBE-218 --- .../java/net/gepafin/tendermanagement/util/Utils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 31f3c81c..2d99d8b0 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -291,11 +291,14 @@ public class Utils { return pattern.matcher(email).matches(); } +// public static String randomKey(Integer range) { +// String data = String.valueOf(System.currentTimeMillis()); +// return data.substring(data.length() - range); +// +// } public static String randomKey(Integer range) { - String data = String.valueOf(System.currentTimeMillis()); - return data.substring(data.length() - range); + return UUID.randomUUID().toString().replace("-", "").substring(0, range); } - public static String convertObjectToJsonString(Object object) { try { // Check if the object is a string From 315e6965f632a548b6edc086934f74eb23da5899 Mon Sep 17 00:00:00 2001 From: nisha Date: Fri, 9 May 2025 12:29:32 +0530 Subject: [PATCH 32/63] Done ticket GEPAFINBE-218 --- .../java/net/gepafin/tendermanagement/util/Utils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 343e742a..6347119a 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -291,11 +291,14 @@ public class Utils { return pattern.matcher(email).matches(); } +// public static String randomKey(Integer range) { +// String data = String.valueOf(System.currentTimeMillis()); +// return data.substring(data.length() - range); +// +// } public static String randomKey(Integer range) { - String data = String.valueOf(System.currentTimeMillis()); - return data.substring(data.length() - range); + return UUID.randomUUID().toString().replace("-", "").substring(0, range); } - public static String convertObjectToJsonString(Object object) { try { // Check if the object is a string From aefe8fb38b8ad066ae74c6dc17c73ea26550d290 Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 9 May 2025 18:27:17 +0530 Subject: [PATCH 33/63] updated code --- .../java/net/gepafin/tendermanagement/dao/EmailDao.java | 8 ++++---- .../tendermanagement/repositories/EmailLogRepository.java | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java index 66b20b77..df5566e0 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java @@ -72,18 +72,18 @@ public class EmailDao { public EmailSendResponse buildEmailSendResponseFromRequest(HttpServletRequest request) { Long userActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID); - List emailLogs = emailLogRepository.findByUserActionId(userActionId); + List 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 = EmailServiceTypeEnum.PEC_SERVICE.getValue().equals(log.getEmailServiceType()) && - StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus()); - if (!isSuccess) { + boolean isSuccess = StatusTypeEnum.SUCCESS.getValue().equals(log.getSendStatus()); + if (Boolean.FALSE.equals(isSuccess)) { allSuccess = false; break; } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java index f12d0e3b..669c4b69 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/EmailLogRepository.java @@ -14,5 +14,8 @@ public interface EmailLogRepository extends JpaRepository { List findByUserActionIdAndEmailServiceTypeAndSendStatus( Long userActionId, String emailServiceType, String sendStatus); Optional findTopByUserIdAndEmailTypeAndIsDeletedFalseOrderByCreatedDateDesc(Long userId, String emailType); + List findByUserActionIdAndEmailServiceType( + Long userActionId, String emailServiceType); + } From 43da0472813ff38873e6b1fd0e6782ca7b9acc07 Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 9 May 2025 19:12:32 +0530 Subject: [PATCH 34/63] Updated code --- .../constants/GepafinConstant.java | 2 ++ .../gepafin/tendermanagement/dao/EmailDao.java | 17 ++++++++++++++++- src/main/resources/message_en.properties | 4 +++- src/main/resources/message_it.properties | 4 +++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index d0fb0136..7e165dc3 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -541,6 +541,8 @@ public class GepafinConstant { public static final String RESEND_EMAIL_SENT_FAILED_MSG = "resend.email.sent.failed.msg"; public static final String REMINDER_EMAIL_FAILED_MSG = "reminder.email.sent.failed.msg"; + public static final String NO_EMAIL_LOG_FOUND = "no.email.log.msg"; + public static final String USER_ACTION_ID_NOT_FOUND = "user.action.id.not.found"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java index df5566e0..6e46d475 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java @@ -3,9 +3,11 @@ 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.CallEntity; import net.gepafin.tendermanagement.entities.EmailLogEntity; +import net.gepafin.tendermanagement.entities.UserActionEntity; import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.RecipientTypeEnum; @@ -14,8 +16,12 @@ import net.gepafin.tendermanagement.model.request.EmailLogRequest; import net.gepafin.tendermanagement.model.response.EmailResendResponseBean; import net.gepafin.tendermanagement.model.response.EmailSendResponse; import net.gepafin.tendermanagement.repositories.EmailLogRepository; +import net.gepafin.tendermanagement.repositories.UserActionsRepository; import net.gepafin.tendermanagement.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; @@ -38,10 +44,19 @@ public class EmailDao { @Autowired private EmailLogDao emailLogDao; + @Autowired + private UserActionsRepository userActionsRepository; + 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 emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceTypeAndSendStatus(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue(),StatusTypeEnum.FAILED.getValue()); + if (emailLogs.isEmpty()) { - log.info("No emails found for given userActionId."); + 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){ diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index b09c8d62..ddd71c3e 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -403,4 +403,6 @@ invalid.user=Invalid user. reminder.email.sent.failed.msg = Failed to send reminder email resend.email.sent.success.msg = Email resend successfully -resend.email.sent.failed.msg = Failed to resend the email. \ No newline at end of file +resend.email.sent.failed.msg = Failed to resend the email. +no.email.log.msg = No failed emails found for given userActionId. +user.action.id.not.found = User Action id not found. \ No newline at end of file diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index faafb940..09ec0e49 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -394,4 +394,6 @@ invalid.user=Utente non valido. reminder.email.sent.failed.msg = Impossibile inviare l'e-mail di promemoria resend.email.sent.success.msg = Email reinviata con successo -resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail. \ No newline at end of file +resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail. +no.email.log.msg = Nessuna email trovata per userActionId specificato. +user.action.id.not.found = ID azione utente non trovato. \ No newline at end of file From d1dcc5cf7bf9d65aec96cc34840cbb7e194c6aea Mon Sep 17 00:00:00 2001 From: Piyush Date: Mon, 12 May 2025 15:55:22 +0530 Subject: [PATCH 35/63] Added emailSendResponse in get Amendment Api --- .../dao/ApplicationAmendmentRequestDao.java | 15 +++++--- ...plicationAmendmentRequestResponseBean.java | 36 +++++++++++++++++++ .../ApplicationAmendmentRequestService.java | 2 +- ...pplicationAmendmentRequestServiceImpl.java | 2 +- .../api/ApplicationAmendmentRequestApi.java | 2 +- ...ApplicationAmendmentRequestController.java | 4 +-- 6 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponseBean.java diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index a0d0ff7f..59004619 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -654,12 +654,19 @@ public class ApplicationAmendmentRequestDao { log.info(" Application amendment deleted with ID: {}", id); } - public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(Long id) { + public ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(Long id) { log.info("Fetching application amendment with ID: {}", id); ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); - ApplicationAmendmentRequestResponse response = convertEntityToResponse(applicationAmendmentRequestEntity,true); - log.info("Application Amendment fetched successfully by ID: {}", response); - return response; + ApplicationAmendmentRequestResponse sourceResponse = convertEntityToResponse(applicationAmendmentRequestEntity,true); + ApplicationAmendmentRequestResponseBean targetResponse = Utils.convertSourceObjectToDestinationObject( + sourceResponse, ApplicationAmendmentRequestResponseBean.class + ); + + if (targetResponse != null) { + targetResponse.setEmailSendResponse(applicationAmendmentRequestEntity.getEmailSendResponse()); + } + log.info("Application Amendment fetched successfully by ID: {}", targetResponse); + return targetResponse; } public List getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId) { diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponseBean.java new file mode 100644 index 00000000..9bbddfeb --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponseBean.java @@ -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 formFields; + private List applicationFormFields; + private List amendmentDocuments; + private String amendmentNotes; + private Boolean valid; + private Long applicationId; + private Long applicationEvaluationId; + private LocalDateTime evaluationEndDate; + private LocalDateTime expirationDate; + private List commentsList; + private String internalNote; + private ApplicationAmendmentRequestEnum status; + private String emailTemplate; + private List emailSendResponse; +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java index b19f77c4..9b4b63ed 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java @@ -16,7 +16,7 @@ public interface ApplicationAmendmentRequestService { public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(HttpServletRequest request,Long applicationEvaluationId); public ApplicationAmendmentRequestResponse createApplicationAmendmentRequest(HttpServletRequest request, Long applicationEvaluationId , ApplicationAmendmentRequest applicationAmendmentRequest); void deleteApplicationAmendmentRequest(HttpServletRequest request, Long id); - ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(HttpServletRequest request,Long id); + ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(HttpServletRequest request,Long id); List getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId); ApplicationAmendmentRequestResponse updateApplicationAmendment(HttpServletRequest request, Long id, ApplicationAmendmentRequestBean applicationAmendmentRequestBean); ApplicationAmendmentRequestEntity validateApplicationAmendmentRequest(Long applicationAmendmentId); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java index a680ec1b..20a1e455 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java @@ -75,7 +75,7 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm } @Override - public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { + public ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(id) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java index 5d81ce7e..25b53b3c 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java @@ -72,7 +72,7 @@ public interface ApplicationAmendmentRequestApi { @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) @GetMapping(value = "", produces = "application/json") - ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,@Parameter(description = "The application amendment id", required = true) @RequestParam(value = "id", required = true) Long id); + ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,@Parameter(description = "The application amendment id", required = true) @RequestParam(value = "id", required = true) Long id); @Operation(summary = "Api to get all applications amendment request by preInstructor user Id (deprecated)", responses = { diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java index c92a060b..739c2802 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java @@ -69,14 +69,14 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme } @Override - public ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { + public ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { log.info("Get Application Amendment Request By Id"); /** This code is responsible for creating user action logs for the "get application amendment by id" operation. **/ loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW) .actionContext(UserActionContextEnum.GET_AMENDMENT).build()); - ApplicationAmendmentRequestResponse applicationAmendmentRequestResponse = applicationAmendmentRequestService.getApplicationAmendmentRequestById(request,id); + ApplicationAmendmentRequestResponseBean applicationAmendmentRequestResponse = applicationAmendmentRequestService.getApplicationAmendmentRequestById(request,id); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(applicationAmendmentRequestResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_APPLICATION_AMENDMENT_SUCCESS_MSG))); } From 5e3b0025d9c9b1c93d9d103683d268276c13d64a Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 18:02:43 +0530 Subject: [PATCH 36/63] Done ticket GEPAFINBE-216 Handled error for appointment creation failed, now returning the error description getting from third party API. --- .../constants/GepafinConstant.java | 4 ++- .../tendermanagement/dao/AppointmentDao.java | 29 +++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 7e165dc3..5ecfa9b5 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -544,7 +544,9 @@ public class GepafinConstant { public static final String NO_EMAIL_LOG_FOUND = "no.email.log.msg"; public static final String USER_ACTION_ID_NOT_FOUND = "user.action.id.not.found"; - + public static final String CAUSE_STRING = "cause" ; + public static final String ERROR_DESCRIPTION_STRING = "errorDescription" ; + public static final String ERROR_STRING = "errors"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index cb83406e..43c8cfdc 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -758,12 +758,31 @@ public class AppointmentDao { if (appointmentResponse.getBody() != null) { log.info("Appointment API Response : {}", appointmentResponse.getBody()); - Map responseBody = (Map) appointmentResponse.getBody(); - if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { - Map data = (Map) responseBody.get(GepafinConstant.DATA_STRING); - if (data != null && data.containsKey(GepafinConstant.ID_STRING)) { - return data.get(GepafinConstant.ID_STRING).toString(); + try { + Map responseBody = (Map) appointmentResponse.getBody(); + // 1. Try to get appointment ID from data.id + if (responseBody.containsKey(GepafinConstant.DATA_STRING)) { + Map data = (Map) responseBody.get(GepafinConstant.DATA_STRING); + if (data != null && data.containsKey(GepafinConstant.ID_STRING)) { + return data.get(GepafinConstant.ID_STRING).toString(); + } } + // 2. If ID not present, check errors[0].cause.errorDescription + if (responseBody.containsKey(GepafinConstant.ERROR_STRING)) { + List> errors = (List>) responseBody.get(GepafinConstant.ERROR_STRING); + if (errors != null && !errors.isEmpty()) { + Map firstError = errors.get(0); + if (firstError.containsKey(GepafinConstant.CAUSE_STRING)) { + Map cause = (Map) firstError.get(GepafinConstant.CAUSE_STRING); + if (cause != null && cause.containsKey(GepafinConstant.ERROR_DESCRIPTION_STRING)) { + String errorDescription = cause.get(GepafinConstant.ERROR_DESCRIPTION_STRING).toString(); + log.warn("Appointment creation failed: {}", errorDescription); + } + } + } + } + } catch (Exception e) { + log.error("Error while extracting appointment ID or parsing error message", e); } } return null; From 5a055923300906f33410adf8dcdf14e0ecdc05d5 Mon Sep 17 00:00:00 2001 From: Piyush Date: Tue, 13 May 2025 18:18:46 +0530 Subject: [PATCH 37/63] Fixed Issue with Resend Email API --- .../tendermanagement/dao/EmailDao.java | 97 ++++++++++++++++++- .../ApplicationEvaluationRepository.java | 5 + .../repositories/EmailLogRepository.java | 7 ++ 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java index 6e46d475..9b99facb 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java @@ -5,9 +5,7 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.extern.log4j.Log4j2; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; -import net.gepafin.tendermanagement.entities.CallEntity; -import net.gepafin.tendermanagement.entities.EmailLogEntity; -import net.gepafin.tendermanagement.entities.UserActionEntity; +import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.EmailScenarioTypeEnum; import net.gepafin.tendermanagement.enums.EmailServiceTypeEnum; import net.gepafin.tendermanagement.enums.RecipientTypeEnum; @@ -15,8 +13,7 @@ import net.gepafin.tendermanagement.enums.StatusTypeEnum; import net.gepafin.tendermanagement.model.request.EmailLogRequest; import net.gepafin.tendermanagement.model.response.EmailResendResponseBean; import net.gepafin.tendermanagement.model.response.EmailSendResponse; -import net.gepafin.tendermanagement.repositories.EmailLogRepository; -import net.gepafin.tendermanagement.repositories.UserActionsRepository; +import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; @@ -47,6 +44,15 @@ public class EmailDao { @Autowired private UserActionsRepository userActionsRepository; + @Autowired + private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private ApplicationEvaluationRepository applicationEvaluationRepository; + public EmailResendResponseBean resendEmail(HttpServletRequest request , Long userActionId){ UserActionEntity userActionEntity = userActionsRepository.findUserActionByIdAndIsDeletedFalse(userActionId); if(userActionEntity == null){ @@ -82,9 +88,90 @@ public class EmailDao { } EmailSendResponse emailSendResponse = buildEmailSendResponseFromRequest(request); emailResendResponseBean.setEmailSendResponse(emailSendResponse); + + if (Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + updateEmailSendStatusIfSuccessful(emailSendResponse); + } return emailResendResponseBean; } + private void updateEmailSendStatusIfSuccessful(EmailSendResponse emailSendResponse){ + Long actionId = emailSendResponse.getUserActionId(); + + EmailLogEntity emailLog = emailLogRepository.findTopByUserActionIdAndEmailServiceTypeAndSendStatusOrderByIdDesc( + actionId, + EmailServiceTypeEnum.PEC_SERVICE.getValue(), + StatusTypeEnum.SUCCESS.getValue() + ); + if (emailLog != null) { + switch (emailSendResponse.getEmailScenario()) { + case APPLICATION_AMENDMENT_REQUESTED: + case APPLICATION_AMENDMENT_REMINDER: + updateApplicationAmendmentStatus(emailLog, emailSendResponse.getEmailScenario().getValue()); + break; + + case USER_CREATION: + case PASSWORD_RESET_REQUEST: + updateUserEmailStatus(emailLog, emailSendResponse.getEmailScenario().getValue()); + break; + + case APPLICATION_ADMISSIBLE: + case APPLICATION_REJECTED: + updateApplicationEvaluationStatus(emailLog, emailSendResponse.getEmailScenario().getValue()); + break; + + default: + log.warn("Unhandled email scenario: {}", emailSendResponse.getEmailScenario()); + } + } + } + + private void updateApplicationAmendmentStatus(EmailLogEntity log, String scenario) { + if (log.getAmendmentId() != null) { + applicationAmendmentRequestRepository.findById(log.getAmendmentId()).ifPresent(amendment -> { + if (updateEmailSendResponse(amendment.getEmailSendResponse(), scenario)) { + applicationAmendmentRequestRepository.save(amendment); + } + }); + } + } + + private void updateApplicationEvaluationStatus(EmailLogEntity log, String scenario) { + if (log.getApplicationId() != null) { + ApplicationEvaluationEntity evaluation = applicationEvaluationRepository.findByApplicationId(log.getApplicationId()); + if (evaluation != null && updateEmailSendResponse(evaluation.getEmailSendResponse(), scenario)) { + applicationEvaluationRepository.save(evaluation); + } + } + } + + private void updateUserEmailStatus(EmailLogEntity log, String scenario) { + if (log.getUserId() != null) { + userRepository.findById(log.getUserId()).ifPresent(user -> { + if (updateEmailSendResponse(user.getEmailSendResponse(), scenario)) { + userRepository.save(user); + } + }); + } + } + + + + + private boolean updateEmailSendResponse(List responses, String scenario) { + if (responses == null || responses.isEmpty()) return false; + + for (EmailSendResponse response : responses) { + if (scenario.equals(response.getEmailScenario().getValue())) { + response.setIsEmailSend(true); + return true; + } + } + return false; + } + + + public EmailSendResponse buildEmailSendResponseFromRequest(HttpServletRequest request) { Long userActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID); List emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceType(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue()); diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java index 9019aad4..a231d3c6 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java @@ -76,5 +76,10 @@ public interface ApplicationEvaluationRepository extends JpaRepository { List findByUserActionIdAndEmailServiceType( Long userActionId, String emailServiceType); + EmailLogEntity findTopByUserActionIdAndEmailServiceTypeAndSendStatusOrderByIdDesc( + Long userActionId, + String emailServiceType, + String sendStatus + ); + + } From 43ff10e7b685c53d3b00b05f0849e1a2c540e3fd Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 19:39:11 +0530 Subject: [PATCH 38/63] Updated code for maximum retries on login to odessa. --- .../tendermanagement/dao/AppointmentDao.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 43c8cfdc..23f9784d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -176,6 +176,11 @@ public class AppointmentDao { } private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { + + int maxRetries = 3; + int attempt = 0; + boolean success = false; + while (attempt < maxRetries && !success) { try { //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); @@ -195,15 +200,16 @@ public class AppointmentDao { hub.setAreaCode(parsedResponse.getAreaCode()); hubRepository.save(hub); log.info("Saved new authToken and areaCode for Hub."); + success = true; return hub; } else { throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); } } throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); - } - catch (FeignException.Forbidden forbiddenException) { - logForbiddenError(); + } catch (FeignException.Forbidden forbiddenException) { + attempt++; + log.error("Failed to login to odessa due to some error"); // Extract raw response body String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response @@ -239,15 +245,17 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - - // Regenerate the token and retry - loginToOdessa(hub, application); - } - catch (Exception e) { + if (attempt >= maxRetries) { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); + } else { + loginToOdessa(hub, application); + } + } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); } - return null; + } + return null; } private void startAsyncNdgProcessing(Long applicationId) { From b137c9b3ec0946166955517dc482238ee674a375 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 19:48:48 +0530 Subject: [PATCH 39/63] Updated code for retry authentication for login to odessa. --- .../tendermanagement/dao/AppointmentDao.java | 132 ++++++++++-------- 1 file changed, 70 insertions(+), 62 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 23f9784d..079addee 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -430,77 +430,85 @@ public class AppointmentDao { } private HubEntity authenticateAndSaveToken(HubEntity hub) { - - try { - //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call - String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); - log.info("Got the auth for login to odessa {}", authJwtToken); - hub.setAuthToken(authJwtToken); - hubRepository.save(hub); - // Prepare the request body (adjust if necessary for login API) - Map body = Collections.emptyMap(); - // Perform login API call - ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); - - // Handle successful login - if (responseLogin.getStatusCode() == HttpStatus.OK) { - log.info("Login successful to odessa. Parsing response."); - String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); - AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); - - // Validate and save token - if (parsedResponse.getTokenId() != null) { - hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); - hub.setAreaCode(parsedResponse.getAreaCode()); - hubRepository.save(hub); - - log.info("Saved new authToken and areaCode for Hub."); - return hub; - } else { - throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); - } - } - // Handle non-OK response - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); - } catch (FeignException.Forbidden forbiddenException) { - logForbiddenError(); - - // Extract raw response body - String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response - - // Parse JSON to check for "PasswordExpired" + int maxRetries = 3; + int attempt = 0; + boolean success = false; + while (attempt < maxRetries && !success) { try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(responseBody); - JsonNode errorsNode = rootNode.path("errors"); + //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call + String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); + log.info("Got the auth for login to odessa {}", authJwtToken); + hub.setAuthToken(authJwtToken); + hubRepository.save(hub); + // Prepare the request body (adjust if necessary for login API) + Map body = Collections.emptyMap(); + // Perform login API call + ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); - if (errorsNode.isArray()) { - for (JsonNode error : errorsNode) { - // Check the main errorCode - if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } + // Handle successful login + if (responseLogin.getStatusCode() == HttpStatus.OK) { + log.info("Login successful to odessa. Parsing response."); + String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); + AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); - // Check inside "subErrors" - JsonNode subErrorsNode = error.path("subErrors"); - if (subErrorsNode.isArray()) { - for (JsonNode subError : subErrorsNode) { - if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // Validate and save token + if (parsedResponse.getTokenId() != null) { + hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); + hub.setAreaCode(parsedResponse.getAreaCode()); + hubRepository.save(hub); + + log.info("Saved new authToken and areaCode for Hub."); + success = true; + return hub; + } else { + throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); + } + } + // Handle non-OK response + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); + } catch (FeignException.Forbidden forbiddenException) { + attempt++; + log.error("Failed to login to odessa due to some error occurred."); + + // Extract raw response body + String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + + // Parse JSON to check for "PasswordExpired" + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(responseBody); + JsonNode errorsNode = rootNode.path("errors"); + + if (errorsNode.isArray()) { + for (JsonNode error : errorsNode) { + // Check the main errorCode + if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + } + + // Check inside "subErrors" + JsonNode subErrorsNode = error.path("subErrors"); + if (subErrorsNode.isArray()) { + for (JsonNode subError : subErrorsNode) { + if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { + throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + } } } } } + } catch (IOException e) { + log.error("Error parsing JSON response: {}", e.getMessage()); } - } catch (IOException e) { - log.error("Error parsing JSON response: {}", e.getMessage()); + if (attempt >= maxRetries) { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); + } else { + regenerateTokenAndSave(hub); + } + } catch (Exception e) { + log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); + throw new RuntimeException("Authentication failed on Odessa. try again", e); } - - // Regenerate the token and retry - regenerateTokenAndSave(hub); - } catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); - throw new RuntimeException("Authentication failed on Odessa. try again", e); } return null; } From 42fd20adc7758b285126786aa0e0963488974a8a Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 20:09:12 +0530 Subject: [PATCH 40/63] Updated code fix. --- .../tendermanagement/dao/AppointmentDao.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 079addee..5cfa0fe3 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -208,7 +208,6 @@ public class AppointmentDao { } throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); } catch (FeignException.Forbidden forbiddenException) { - attempt++; log.error("Failed to login to odessa due to some error"); // Extract raw response body @@ -245,14 +244,16 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt >= maxRetries) { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); + if (attempt + 1 < maxRetries) { + regenerateTokenAndSave(hub); } else { - loginToOdessa(hub, application); + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); + } finally { + attempt++; } } return null; @@ -430,6 +431,7 @@ public class AppointmentDao { } private HubEntity authenticateAndSaveToken(HubEntity hub) { + int maxRetries = 3; int attempt = 0; boolean success = false; @@ -467,7 +469,6 @@ public class AppointmentDao { // Handle non-OK response throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); } catch (FeignException.Forbidden forbiddenException) { - attempt++; log.error("Failed to login to odessa due to some error occurred."); // Extract raw response body @@ -500,14 +501,16 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt >= maxRetries) { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); - } else { + if (attempt + 1 < maxRetries) { regenerateTokenAndSave(hub); + } else { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); + } finally { + attempt++; } } return null; From a836864faceaa34e95e0d6338703797dbf192d9e Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 13 May 2025 20:19:43 +0530 Subject: [PATCH 41/63] Code Fix. --- .../tendermanagement/dao/AppointmentDao.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 5cfa0fe3..609ab87d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -181,6 +181,7 @@ public class AppointmentDao { int attempt = 0; boolean success = false; while (attempt < maxRetries && !success) { + attempt++; try { //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); @@ -244,16 +245,9 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt + 1 < maxRetries) { - regenerateTokenAndSave(hub); - } else { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); - } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); - } finally { - attempt++; } } return null; @@ -436,6 +430,7 @@ public class AppointmentDao { int attempt = 0; boolean success = false; while (attempt < maxRetries && !success) { + attempt++; try { //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); @@ -501,16 +496,9 @@ public class AppointmentDao { } catch (IOException e) { log.error("Error parsing JSON response: {}", e.getMessage()); } - if (attempt + 1 < maxRetries) { - regenerateTokenAndSave(hub); - } else { - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale("Maximum retry attempts reached while trying to login to Odessa.")); - } } catch (Exception e) { log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); - } finally { - attempt++; } } return null; From 637aec5211a49ee73399260d6e30ad1b133b797f Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 14 May 2025 11:36:35 +0530 Subject: [PATCH 42/63] Done ticket GEPAFINBE-217 --- .../constants/GepafinConstant.java | 2 +- .../dao/ApplicationAmendmentRequestDao.java | 4 +- .../tendermanagement/dao/ApplicationDao.java | 82 +++++++++++++++++++ .../enums/UserActionContextEnum.java | 1 + .../ApplicationEvaluationRepository.java | 5 ++ .../repositories/ApplicationRepository.java | 3 + .../AssignedApplicationsRepository.java | 4 + .../service/ApplicationService.java | 2 + .../service/impl/ApplicationServiceImpl.java | 7 +- .../web/rest/api/ApplicationApi.java | 14 ++++ .../api/impl/ApplicationApiController.java | 11 +++ src/main/resources/message_en.properties | 4 +- src/main/resources/message_it.properties | 8 +- 13 files changed, 139 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index d0fb0136..d26d3927 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -541,7 +541,7 @@ public class GepafinConstant { public static final String RESEND_EMAIL_SENT_FAILED_MSG = "resend.email.sent.failed.msg"; public static final String REMINDER_EMAIL_FAILED_MSG = "reminder.email.sent.failed.msg"; - + public static final String READMIT_APPLICATION_SUCCESS = "application.readmit.success"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index a0d0ff7f..cd482625 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -1082,12 +1082,12 @@ public class ApplicationAmendmentRequestDao { application.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); applicationRepository.save(application); - existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().setStatus(AssignedApplicationEnum.OPEN.getValue()); - AssignedApplicationsEntity assignedApplicationsEntity = assignedApplicationsDao.validateAssignedApplication( existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().getId()); AssignedApplicationsEntity oldAssignedApplicationData = Utils.getClonedEntityForData(assignedApplicationsEntity); + existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().setStatus(AssignedApplicationEnum.OPEN.getValue()); + assignedApplicationsEntity = assignedApplicationsRepository.save(existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 2492e8b0..9dfba4b0 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2170,6 +2170,88 @@ public class ApplicationDao { emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(GepafinConstant.RINALDO_EMAIL),emailLogRequest); } + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId) { + log.info("Re-admiting the Application with id : {}", applicationId); + + ApplicationEntity applicationEntity = fetchRejectedApplication(applicationId); + if(applicationEntity == null){ + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG)); + } + validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); + validateCallEndDate(applicationEntity); + + assignedApplicationsRepository.findByApplicationIdAndStatusAndIsDeletedFalse(applicationEntity.getId(), AssignedApplicationEnum.CLOSE.getValue()) + .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); + + return getApplicationResponse(applicationEntity); + } + private ApplicationEntity fetchRejectedApplication(Long applicationId) { + return applicationRepository.findByIdAndStatusAndIsDeletedFalse(applicationId, ApplicationStatusTypeEnum.REJECTED.getValue()); + } + private void validateCallEndDate(ApplicationEntity applicationEntity) { + checkCallEndDate(applicationEntity.getCall()); + log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); + } + + private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { + applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse(assignedApp.getId(), ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()) + .ifPresent(eval -> reopenApplication(request, applicationEntity, assignedApp, eval)); + } + + + private void reopenApplication(HttpServletRequest request, ApplicationEntity applicationEntity, + AssignedApplicationsEntity assignedApp, ApplicationEvaluationEntity evaluationEntity) { + + ApplicationEntity oldApplication = Utils.getClonedEntityForData(applicationEntity); + AssignedApplicationsEntity oldAssignedApp = Utils.getClonedEntityForData(assignedApp); + ApplicationEvaluationEntity oldEvaluation = Utils.getClonedEntityForData(evaluationEntity); + + updateApplicationStatus(applicationEntity); + updateAssignedApplicationStatus(assignedApp); + updateEvaluationEntity(applicationEntity.getHubId(), evaluationEntity); + + saveEntities(applicationEntity, assignedApp, evaluationEntity); + + /** This code is responsible for adding a version history log for the "Update Application" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplication).newData(applicationEntity).build()); + + /** This code is responsible for adding a version history log for the "Update Application Evaluation" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldEvaluation).newData(evaluationEntity).build()); + + /** This code is responsible for adding a version history log for the "Update Assigned Application" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldAssignedApp).newData(assignedApp).build()); + } + + private void updateApplicationStatus(ApplicationEntity applicationEntity) { + applicationEntity.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); + applicationEntity.setDateRejected(null); + } + + private void updateAssignedApplicationStatus(AssignedApplicationsEntity assignedApp) { + assignedApp.setStatus(AssignedApplicationEnum.OPEN.getValue()); + } + + private void updateEvaluationEntity(Long hubId, ApplicationEvaluationEntity evaluationEntity) { + HubEntity hub = hubService.valdateHub(hubId); + Long evaluationDays = (hub != null) ? hub.getEvaluationExpirationDays() : 30L; + + LocalDateTime now = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); + evaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.OPEN.getValue()); + evaluationEntity.setClosingDate(null); + evaluationEntity.setActiveDays(null); + evaluationEntity.setEndDate(now.plusDays(evaluationDays)); + evaluationEntity.setStartDate(now); + evaluationEntity.setRemainingDays(evaluationDays); + evaluationEntity.setSuspendedDays(0L); + evaluationEntity.setStopDateTime(null); + } + + private void saveEntities(ApplicationEntity app, AssignedApplicationsEntity assignedApp, ApplicationEvaluationEntity eval) { + applicationRepository.save(app); + assignedApplicationsRepository.save(assignedApp); + applicationEvaluationRepository.save(eval); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index 9fae6ce7..fe2e4cd1 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -46,6 +46,7 @@ public enum UserActionContextEnum { GET_SIGNED_DOCUMENT("GET_SIGNED_DOCUMENT"), GET_NEXT_PREVIOUS_FORM("GET_NEXT_PREVIOUS_FORM"), DOWNLOAD_APPLICATION_DOC_ZIP("DOWNLOAD_APPLICATION_DOC_ZIP"), + READMIT_APPLICATION("READMIT_APPLICATION"), /** FAQ action context **/ CREATE_FAQ("CREATE_FAQ"), diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java index 9019aad4..306ad3a5 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java @@ -76,5 +76,10 @@ public interface ApplicationEvaluationRepository extends JpaRepository findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse( + Long assignedApplicationId, + String status + ); + } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java index b5cf7fb9..c760689a 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java @@ -178,4 +178,7 @@ public interface ApplicationRepository extends JpaRepository findByApplicationIdAndStatusAndIsDeletedFalse( Long applicationId, String status); + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index 24fde801..c7af4f88 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -50,4 +50,6 @@ public interface ApplicationService { public byte[] exportCsv(HttpServletRequest request, Long callId); + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index 879c72cf..357661d1 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -170,5 +170,10 @@ public class ApplicationServiceImpl implements ApplicationService { return csvBytes; } - + @Override + @Transactional(rollbackFor = Exception.class) + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId) { + UserEntity userEntity = validator.validateUser(request); + return applicationDao.readmitApplication(request, applicationId); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index 00609f68..a18e6852 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -238,6 +238,20 @@ public interface ApplicationApi { public ResponseEntity exportCsv( HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable(value = "callId", required = true) Long callId); + @Operation(summary = "Api to re-admit an application", + responses = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) + @PutMapping(value = "/{applicationId}/readmit", produces = { "application/json" }) + @PreAuthorize("hasRole('ROLE_SUPER_ADMIN')|| hasRole('ROLE_INSTRUCTOR_MANAGER')|| hasRole('ROLE_PRE_INSTRUCTOR')") + ResponseEntity> readmitApplication(HttpServletRequest request, + @Parameter(description = "The application id", required = true) @PathVariable("applicationId") Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index a06f5dc4..840711ae 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -242,5 +242,16 @@ public class ApplicationApiController implements ApplicationApi { .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(csvBytes); } + @Override + public ResponseEntity> readmitApplication(HttpServletRequest request, Long applicationId) { + /** This code is responsible for creating user action logs for the "re-admit application" operation. **/ + loggingUtil.logUserAction( + UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.READMIT_APPLICATION).build()); + + ApplicationResponse applicationResponse = applicationService.readmitApplication(request, applicationId); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(applicationResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.READMIT_APPLICATION_SUCCESS))); + } } diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index b09c8d62..aa8d0ad4 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -403,4 +403,6 @@ invalid.user=Invalid user. reminder.email.sent.failed.msg = Failed to send reminder email resend.email.sent.success.msg = Email resend successfully -resend.email.sent.failed.msg = Failed to resend the email. \ No newline at end of file +resend.email.sent.failed.msg = Failed to resend the email. + +application.readmit.success=Application has been readmitted successfully. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index faafb940..b9a8e2db 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -53,7 +53,7 @@ call.update.successfully=Chiamata aggiornata con successo. call.fetch.success=Dettagli della chiamata recuperati con successo. call.not.found=Chiamata non trovata. score.not.null=Il punteggio non pu? essere nullo o zero. -field.not.null={0} non può essere vuoto. +field.not.null={0} non pu� essere vuoto. field.not.empty=la {0} non pu? essere vuota. update_call_status_success_msg=Lo stato della chiamata ? stato aggiornato con successo. status.same.error=Lo stato ? gi? impostato. @@ -389,9 +389,11 @@ error.invalid.limit=Il limite dovrebbe essere compreso tra 1 e 3000. insufficient.score.msg = Punteggio non sufficiente per passaggio alla valutazione tecnica ed economico finanziaria validation.table.message=I dati per il campo {0} non sono presenti. -password.expired.for.login.to.odessa = La password di accesso a Odessa è scaduta +password.expired.for.login.to.odessa = La password di accesso a Odessa � scaduta invalid.user=Utente non valido. reminder.email.sent.failed.msg = Impossibile inviare l'e-mail di promemoria resend.email.sent.success.msg = Email reinviata con successo -resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail. \ No newline at end of file +resend.email.sent.failed.msg = Impossibile inviare nuovamente l'e-mail. + +application.readmit.success=L'applicazione è stata riammessa con successo. From 1de7d672d0bfe22cdeb97256564482512353d81b Mon Sep 17 00:00:00 2001 From: rajesh Date: Wed, 14 May 2025 13:06:14 +0530 Subject: [PATCH 43/63] Appointment error handling check. --- .../tendermanagement/dao/AppointmentDao.java | 428 ++++++++++++------ 1 file changed, 277 insertions(+), 151 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 609ab87d..617c9dff 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -1,7 +1,6 @@ package net.gepafin.tendermanagement.dao; import com.amazonaws.services.s3.AmazonS3Client; -import com.amazonaws.services.s3.model.GetObjectRequest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -13,12 +12,14 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.config.jwt.TokenProvider; import net.gepafin.tendermanagement.constants.AppointmentApiConstant; import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestEntity; import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity; import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.DocumentEntity; import net.gepafin.tendermanagement.entities.HubEntity; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.enums.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.model.request.AppointmentCreationRequest; @@ -63,7 +64,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -145,6 +145,15 @@ public class AppointmentDao { @Autowired private AmazonS3Service amazonS3Service; + @Autowired + private ApplicationDao applicationDao; + + @Autowired + private ApplicationAmendmentRequestDao applicationAmendmentRequestDao; + + @Autowired + private ApplicationEvaluationDao applicationEvaluationDao; + private final Map executorMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap threadForDocumentMap = new ConcurrentHashMap<>(); @@ -175,15 +184,182 @@ public class AppointmentDao { return ndgResponse; } - private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { + // private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { + // + // int maxRetries = 3; + // int attempt = 0; + // boolean success = false; + // while (attempt < maxRetries && !success) { + // attempt++; + // try { + // //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call + // String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); + // log.info("Got the auth for login to odessa {}", authJwtToken); + // hub.setAuthToken(authJwtToken); + // hubRepository.save(hub); + // Map body = Collections.emptyMap(); + // ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); + // if (responseLogin.getStatusCode() == HttpStatus.OK) { + // log.info("Login successful to odessa. Parsing response."); + // String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); + // AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); + // + // // Validate and save token + // if (parsedResponse.getTokenId() != null) { + // hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); + // hub.setAreaCode(parsedResponse.getAreaCode()); + // hubRepository.save(hub); + // log.info("Saved new authToken and areaCode for Hub."); + // success = true; + // return hub; + // } else { + // throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); + // } + // } + // throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); + // } catch (FeignException.Forbidden forbiddenException) { + // log.error("Failed to login to odessa due to some error"); + // + // // Extract raw response body + // String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + // + // // Parse JSON to check for "PasswordExpired" + // try { + // ObjectMapper objectMapper = new ObjectMapper(); + // JsonNode rootNode = objectMapper.readTree(responseBody); + // JsonNode errorsNode = rootNode.path("errors"); + // + // if (errorsNode.isArray()) { + // for (JsonNode error : errorsNode) { + // // Check the main errorCode + // if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + // application.setNdgStatus(GepafinConstant.NDG_FAILED); + // applicationRepository.save(application); + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // + // // Check inside "subErrors" + // JsonNode subErrorsNode = error.path("subErrors"); + // if (subErrorsNode.isArray()) { + // for (JsonNode subError : subErrorsNode) { + // if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { + // application.setNdgStatus(GepafinConstant.NDG_FAILED); + // applicationRepository.save(application); + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // } + // } + // } + // } + // } catch (IOException e) { + // log.error("Error parsing JSON response: {}", e.getMessage()); + // } + // } catch (Exception e) { + // log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); + // throw new RuntimeException("Authentication failed on Odessa. try again", e); + // } + // } + // return null; + // } + // + // + // private HubEntity authenticateAndSaveToken(HubEntity hub) { + // + // int maxRetries = 3; + // int attempt = 0; + // boolean success = false; + // while (attempt < maxRetries && !success) { + // attempt++; + // try { + // //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call + // String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); + // log.info("Got the auth for login to odessa {}", authJwtToken); + // hub.setAuthToken(authJwtToken); + // hubRepository.save(hub); + // // Prepare the request body (adjust if necessary for login API) + // Map body = Collections.emptyMap(); + // // Perform login API call + // ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); + // + // // Handle successful login + // if (responseLogin.getStatusCode() == HttpStatus.OK) { + // log.info("Login successful to odessa. Parsing response."); + // String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); + // AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); + // + // // Validate and save token + // if (parsedResponse.getTokenId() != null) { + // hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); + // hub.setAreaCode(parsedResponse.getAreaCode()); + // hubRepository.save(hub); + // + // log.info("Saved new authToken and areaCode for Hub."); + // success = true; + // return hub; + // } else { + // throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); + // } + // } + // // Handle non-OK response + // throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); + // } catch (FeignException.Forbidden forbiddenException) { + // log.error("Failed to login to odessa due to some error occurred."); + // + // // Extract raw response body + // String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + // + // // Parse JSON to check for "PasswordExpired" + // try { + // ObjectMapper objectMapper = new ObjectMapper(); + // JsonNode rootNode = objectMapper.readTree(responseBody); + // JsonNode errorsNode = rootNode.path("errors"); + // + // if (errorsNode.isArray()) { + // for (JsonNode error : errorsNode) { + // // Check the main errorCode + // if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // + // // Check inside "subErrors" + // JsonNode subErrorsNode = error.path("subErrors"); + // if (subErrorsNode.isArray()) { + // for (JsonNode subError : subErrorsNode) { + // if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { + // throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + // } + // } + // } + // } + // } + // } catch (IOException e) { + // log.error("Error parsing JSON response: {}", e.getMessage()); + // } + // } catch (Exception e) { + // log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); + // throw new RuntimeException("Authentication failed on Odessa. try again", e); + // } + // } + // return null; + // } + + private void loginToOdessa(HubEntity hub, ApplicationEntity application) { + + performOdessaLogin(hub, application); + } + + private HubEntity authenticateAndSaveToken(HubEntity hub, ApplicationEntity application) { + + return performOdessaLogin(hub, application); + } + + private HubEntity performOdessaLogin(HubEntity hub, ApplicationEntity application) { int maxRetries = 3; int attempt = 0; - boolean success = false; - while (attempt < maxRetries && !success) { + while (attempt < maxRetries) { attempt++; try { - //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); log.info("Got the auth for login to odessa {}", authJwtToken); hub.setAuthToken(authJwtToken); @@ -195,13 +371,11 @@ public class AppointmentDao { String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); - // Validate and save token if (parsedResponse.getTokenId() != null) { hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); hub.setAreaCode(parsedResponse.getAreaCode()); hubRepository.save(hub); log.info("Saved new authToken and areaCode for Hub."); - success = true; return hub; } else { throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); @@ -209,48 +383,51 @@ public class AppointmentDao { } throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); } catch (FeignException.Forbidden forbiddenException) { - log.error("Failed to login to odessa due to some error"); + log.error("Failed to login to odessa due to forbidden error."); - // Extract raw response body - String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response + CheckPasswordExpiredOrErrorInResponse(application, forbiddenException); + } catch (Exception e) { + log.error("Failed to authenticate user on Odessa (Attempt {}): {}", attempt, e.getMessage(), e); + } + } + throw new RuntimeException("Max retries exceeded. Failed to login to Odessa."); + } + private void CheckPasswordExpiredOrErrorInResponse(ApplicationEntity application, FeignException.Forbidden forbiddenException) { - // Parse JSON to check for "PasswordExpired" - try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(responseBody); - JsonNode errorsNode = rootNode.path("errors"); + String responseBody = forbiddenException.contentUTF8(); - if (errorsNode.isArray()) { - for (JsonNode error : errorsNode) { - // Check the main errorCode - if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { - application.setNdgStatus(GepafinConstant.NDG_FAILED); - applicationRepository.save(application); - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(responseBody); + JsonNode errorsNode = rootNode.path("errors"); - // Check inside "subErrors" - JsonNode subErrorsNode = error.path("subErrors"); - if (subErrorsNode.isArray()) { - for (JsonNode subError : subErrorsNode) { - if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { - application.setNdgStatus(GepafinConstant.NDG_FAILED); - applicationRepository.save(application); - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } + if (errorsNode.isArray()) { + for (JsonNode error : errorsNode) { + if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + if (application != null) { + application.setNdgStatus(GepafinConstant.NDG_FAILED); + applicationRepository.save(application); + } + throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); + } + + JsonNode subErrorsNode = error.path("subErrors"); + if (subErrorsNode.isArray()) { + for (JsonNode subError : subErrorsNode) { + if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { + if (application != null) { + application.setNdgStatus(GepafinConstant.NDG_FAILED); + applicationRepository.save(application); } + throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); } } } - } catch (IOException e) { - log.error("Error parsing JSON response: {}", e.getMessage()); } - } catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); - throw new RuntimeException("Authentication failed on Odessa. try again", e); } + } catch (IOException e) { + log.error("Error parsing JSON response: {}", e.getMessage()); } - return null; } private void startAsyncNdgProcessing(Long applicationId) { @@ -299,7 +476,7 @@ public class AppointmentDao { try { // Authenticate and fetch token if required if (hub.getAppointmentAuthTokenId() == null || hub.getAreaCode() == null) { - authenticateAndSaveToken(hub); + authenticateAndSaveToken(hub, application); } String authorizationToken = getBearerToken(hub); @@ -345,10 +522,11 @@ public class AppointmentDao { application.setStatus(ApplicationStatusTypeEnum.NDG.getValue()); applicationRepository.save(application); companyRepository.save(company); - ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); + ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation( + application.getApplicationEvaluationId()); Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); notificationDao.sendNotificationToInstructor(placeHolders, applicationEvaluationEntity, NotificationTypeEnum.NDG_GENERATION); - notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.NDG_GENERATION); + notificationDao.sendNotificationToSuperUser(application, placeHolders, NotificationTypeEnum.NDG_GENERATION); log.info("NDG saved successfully for applicationId: {}", application.getId()); break; } @@ -398,7 +576,7 @@ public class AppointmentDao { ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); notificationDao.sendNotificationToInstructor(placeHolders, applicationEvaluationEntity, NotificationTypeEnum.NDG_GENERATION); - notificationDao.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.NDG_GENERATION); + notificationDao.sendNotificationToSuperUser(application, placeHolders, NotificationTypeEnum.NDG_GENERATION); log.info("NDG saved for applicationId: {}, {}", application.getId(), application.getNdg()); } @@ -416,7 +594,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { log.error("403 Forbidden received while getting visuraList for Ndg code. Regenerating token..."); // Regenerate the token and retry - String newAuthorizationToken = regenerateTokenAndSave(hub); + String newAuthorizationToken = regenerateTokenAndSave(hub, application); return getVisuraList(idVisura, newAuthorizationToken, application, hub); } catch (Exception e) { log.error("Failed to fetch Ndg code: {}", e.getMessage(), e); @@ -424,86 +602,6 @@ public class AppointmentDao { } } - private HubEntity authenticateAndSaveToken(HubEntity hub) { - - int maxRetries = 3; - int attempt = 0; - boolean success = false; - while (attempt < maxRetries && !success) { - attempt++; - try { - //code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call - String authJwtToken = Utils.generateAuthTokenForLoginToOdessa(); - log.info("Got the auth for login to odessa {}", authJwtToken); - hub.setAuthToken(authJwtToken); - hubRepository.save(hub); - // Prepare the request body (adjust if necessary for login API) - Map body = Collections.emptyMap(); - // Perform login API call - ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); - - // Handle successful login - if (responseLogin.getStatusCode() == HttpStatus.OK) { - log.info("Login successful to odessa. Parsing response."); - String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); - AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); - - // Validate and save token - if (parsedResponse.getTokenId() != null) { - hub.setAppointmentAuthTokenId(parsedResponse.getTokenId()); - hub.setAreaCode(parsedResponse.getAreaCode()); - hubRepository.save(hub); - - log.info("Saved new authToken and areaCode for Hub."); - success = true; - return hub; - } else { - throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again."); - } - } - // Handle non-OK response - throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN)); - } catch (FeignException.Forbidden forbiddenException) { - log.error("Failed to login to odessa due to some error occurred."); - - // Extract raw response body - String responseBody = forbiddenException.contentUTF8(); // Extract raw JSON response - - // Parse JSON to check for "PasswordExpired" - try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode = objectMapper.readTree(responseBody); - JsonNode errorsNode = rootNode.path("errors"); - - if (errorsNode.isArray()) { - for (JsonNode error : errorsNode) { - // Check the main errorCode - if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } - - // Check inside "subErrors" - JsonNode subErrorsNode = error.path("subErrors"); - if (subErrorsNode.isArray()) { - for (JsonNode subError : subErrorsNode) { - if (GepafinConstant.PASSWORD_EXPIRED.equals(subError.path("errorCode").asText())) { - throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); - } - } - } - } - } - } catch (IOException e) { - log.error("Error parsing JSON response: {}", e.getMessage()); - } - } catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); - throw new RuntimeException("Authentication failed on Odessa. try again", e); - } - } - return null; - } - private AppointmentLoginResponse retrieveNdgByVatNumber(String vatNumber, String authorizationToken, HubEntity hub, ApplicationEntity application) { try { @@ -517,7 +615,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { logForbiddenError(); // Regenerate the token and retry - String newAuthorizationToken = regenerateTokenAndSave(hub); + String newAuthorizationToken = regenerateTokenAndSave(hub, application); return retrieveNdgByVatNumber(vatNumber, newAuthorizationToken, hub, application); } catch (Exception e) { log.error("Failed to retrieve NDG by VAT number: {}", e.getMessage(), e); @@ -525,9 +623,10 @@ public class AppointmentDao { } } - private String regenerateTokenAndSave(HubEntity hub) { - hub = authenticateAndSaveToken(hub); - return "Bearer " + hub.getAppointmentAuthTokenId(); + private String regenerateTokenAndSave(HubEntity hub, ApplicationEntity application) { + + hub = authenticateAndSaveToken(hub, application); + return "Bearer " + hub.getAppointmentAuthTokenId(); } private AppointmentLoginResponse createVisura(CompanyEntity company, String authorizationToken, HubEntity hub) { @@ -540,7 +639,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { logForbiddenError(); // Regenerate the token and retry - String newAuthorizationToken = regenerateTokenAndSave(hub); + String newAuthorizationToken = regenerateTokenAndSave(hub, null); return createVisura(company, newAuthorizationToken, hub); } catch (Exception e) { log.error("Failed to create Visura for Ndg : {}", e.getMessage()); @@ -710,9 +809,8 @@ public class AppointmentDao { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_NOT_FOUND_FOR_APPLICATION)); } - hub = authenticateAndSaveToken(hub); // Generate authorization token and fetch template data - String authorizationToken = getBearerToken(hub); + String authorizationToken = regenerateTokenAndSave(hub, application); Long appointmentTemplateId = application.getCall().getAppointmentTemplateId(); if (appointmentTemplateId == null) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPOINTMENT_CANNOT_BE_CREATED)); @@ -756,7 +854,7 @@ public class AppointmentDao { } catch (FeignException.Forbidden forbiddenException) { log.error("403 Forbidden received while retrieving template. Regenerating token..."); - regenerateTokenAndSave(hub); + regenerateTokenAndSave(hub, application); return createAppointment(applicationId, createAppointmentRequest); } } @@ -819,20 +917,20 @@ public class AppointmentDao { JsonNode prodottoNode = richiestaNode.path(AppointmentApiConstant.PRODOTTO); String prodottoCode = prodottoNode.path(AppointmentApiConstant.PRODOTTO_CODE).asText(); - richiestaCliente.setCodProdotto(prodottoCode); - richiestaCliente.setIdMotivazione(getIntValue(richiestaNode)); - richiestaCliente.setCodAbi(getTextValue(richiestaNode, AppointmentApiConstant.COD_ABI)); - richiestaCliente.setCodCab(getTextValue(richiestaNode, AppointmentApiConstant.COD_CAB)); - richiestaCliente.setIdNota(getTextValue(richiestaNode, AppointmentApiConstant.ID_NOTA)); - richiestaCliente.setImportoAgevolato(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_AGEVOLATO)); - richiestaCliente.setImportoMedioLungoTermine(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_MEDIOLUNGO_TERMINE)); - richiestaCliente.setCodTipoProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_TIPO_PRODOTTO)); - richiestaCliente.setCodCategoriaProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_CATEGORIA_PRODOTTO)); - richiestaCliente.setCodFormaTecnica(getTextValue(richiestaNode, AppointmentApiConstant.COD_FORMATECNICA)); - richiestaCliente.setCodOperazione(getTextValue(richiestaNode, AppointmentApiConstant.COD_OPERAZIONE)); + richiestaCliente.setCodProdotto(prodottoCode); + richiestaCliente.setIdMotivazione(getIntValue(richiestaNode)); + richiestaCliente.setCodAbi(getTextValue(richiestaNode, AppointmentApiConstant.COD_ABI)); + richiestaCliente.setCodCab(getTextValue(richiestaNode, AppointmentApiConstant.COD_CAB)); + richiestaCliente.setIdNota(getTextValue(richiestaNode, AppointmentApiConstant.ID_NOTA)); + richiestaCliente.setImportoAgevolato(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_AGEVOLATO)); + richiestaCliente.setImportoMedioLungoTermine(getTextValue(richiestaNode, AppointmentApiConstant.IMPORTO_MEDIOLUNGO_TERMINE)); + richiestaCliente.setCodTipoProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_TIPO_PRODOTTO)); + richiestaCliente.setCodCategoriaProdotto(getTextValue(richiestaNode, AppointmentApiConstant.COD_CATEGORIA_PRODOTTO)); + richiestaCliente.setCodFormaTecnica(getTextValue(richiestaNode, AppointmentApiConstant.COD_FORMATECNICA)); + richiestaCliente.setCodOperazione(getTextValue(richiestaNode, AppointmentApiConstant.COD_OPERAZIONE)); - richiestaClienteList.add(richiestaCliente); - } + richiestaClienteList.add(richiestaCliente); + } input.setRichiestaCliente(richiestaClienteList); appointmentCreationRequest.setInput(input); @@ -893,13 +991,40 @@ public class AppointmentDao { // Check if the document is already being processed DocumentEntity systemDoc = documentDao.validateDocument(documentId); + ApplicationEntity application = null; + + if (systemDoc != null) { + DocumentSourceTypeEnum sourceType = DocumentSourceTypeEnum.valueOf(systemDoc.getSource()); + + switch (sourceType) { + case APPLICATION: + application = applicationDao.validateApplication(systemDoc.getSourceId()); + break; + case AMENDMENT: + ApplicationAmendmentRequestEntity applicationAmendmentEntity = applicationAmendmentRequestDao.validateApplicationAmendmentRequest(systemDoc.getSourceId()); + application = applicationDao.validateApplication(applicationAmendmentEntity.getApplicationId()); + break; + case EVALUATION: + ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationDao.validateApplicationEvaluation(systemDoc.getSourceId()); + application = applicationDao.validateApplication(applicationEvaluationEntity.getApplicationId()); + break; + + case CALL: + break; + + default: + log.warn("Unhandled document source type: {}", sourceType); + break; + } + } + Claims claims = tokenProvider.getClaimsFromToken(tokenProvider.extractTokenFromRequest(request)); Long hubId = Utils.extractHubIdFromPayload(claims.getSubject()); // Authenticate the hub before proceeding HubEntity hub = hubRepository.findByHubId(hubId); - authenticateAndSaveToken(hub); - if (systemDoc.getDocumentAttachmentId() != null) { + authenticateAndSaveToken(hub, application); + if (systemDoc != null && systemDoc.getDocumentAttachmentId() != null) { // If the documentAttachmentId is already set, return the response log.info("Document already uploaded with documentAttachmentId: {}", systemDoc.getDocumentAttachmentId()); DocumentUploadResponse response = new DocumentUploadResponse(); @@ -919,11 +1044,12 @@ public class AppointmentDao { }); threadForDocumentMap.put(documentId, executor); + ApplicationEntity finalApplication = application; executor.submit(() -> { threadLocalHubId.set(hubId); try { log.info("Starting async document upload for documentId: {}", documentId); - uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest); + uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest, finalApplication); } catch (Exception e) { log.error("Error in async document upload for documentId: {}", documentId, e); } finally { @@ -939,7 +1065,7 @@ public class AppointmentDao { return null; } - private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest) { + private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest, ApplicationEntity application) { // Synchronous upload logic DocumentEntity systemDoc = documentDao.validateDocument(documentId); @@ -980,8 +1106,8 @@ public class AppointmentDao { log.info("Document uploaded successfully to external system: {}", parsedResponse); } catch (FeignException.Forbidden forbiddenException) { log.error("403 Forbidden received while uploading document. Regenerating token..."); - regenerateTokenAndSave(hub); - uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest); + regenerateTokenAndSave(hub, application); + uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest, application); } catch (Exception e) { log.error("Exception during document upload: {}", e.getMessage(), e); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.EXTERNAL_DOCUMENT_UPLOAD_FAILURE_MSG)); From 16f1b553567d8908e9784757143da7a42b5a5a70 Mon Sep 17 00:00:00 2001 From: Piyush Date: Wed, 14 May 2025 14:52:27 +0530 Subject: [PATCH 44/63] Added value of emailSendResponse in get Evaluation API --- .../dao/ApplicationEvaluationDao.java | 18 ++++--- .../ApplicationEvaluationResponseBean.java | 52 +++++++++++++++++++ .../service/ApplicationEvaluationService.java | 2 +- .../ApplicationEvaluationServiceImpl.java | 3 +- .../rest/api/ApplicationEvaluationApi.java | 2 +- .../ApplicationEvaluationApiController.java | 4 +- 6 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponseBean.java diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index d7a03f62..069bbd40 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -314,7 +314,6 @@ public class ApplicationEvaluationDao { response.setUpdatedDate(entity.getUpdatedDate()); response.setNumberOfCheck(entity.getAssignedApplicationsEntity().getApplication().getCall().getNumberOfCheck()); response.setAppointmentTemplateId(entity.getAssignedApplicationsEntity().getApplication().getCall().getAppointmentTemplateId()); - } @@ -1093,7 +1092,7 @@ public class ApplicationEvaluationDao { } validator.validatePreInstructor(request, assignedApplications.getUserId()); } - public ApplicationEvaluationResponse getApplicationEvaluationByApplicationId(HttpServletRequest request, UserEntity user, Long applicationID, Long assignedApplicationID) { + public ApplicationEvaluationResponseBean getApplicationEvaluationByApplicationId(HttpServletRequest request, UserEntity user, Long applicationID, Long assignedApplicationID) { Long applicationId; Long assignedApplicationId; validatePreinstructor(request, applicationID, assignedApplicationID); @@ -1127,10 +1126,17 @@ public class ApplicationEvaluationDao { } else { entityOptional = applicationEvaluationRepository.findFirstByIsDeletedFalseOrderByCreatedDateDesc(); } - return entityOptional.map(this::convertToResponse) - .orElseGet(() -> { - return getEvaluationResponseByApplicationid(user, applicationId, assignedApplicationId); - }); + + if (entityOptional.isEmpty()) { + return null; + } + ApplicationEvaluationEntity entity = entityOptional.get(); + ApplicationEvaluationResponse response = convertToResponse(entity); + ApplicationEvaluationResponseBean targetResponse = Utils.convertSourceObjectToDestinationObject(response, ApplicationEvaluationResponseBean.class); + if (targetResponse != null && entity.getEmailSendResponse() != null) { + targetResponse.setEmailSendResponse(entity.getEmailSendResponse()); + } + return targetResponse; } private List prepareEvaluationDocumentBeanList(ApplicationEvaluationEntity entity) { List docRequest = new ArrayList<>(); diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponseBean.java new file mode 100644 index 00000000..4cda0fca --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponseBean.java @@ -0,0 +1,52 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; +import net.gepafin.tendermanagement.enums.ApplicationEvaluationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; +import net.gepafin.tendermanagement.enums.EvaluationVersionEnum; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class ApplicationEvaluationResponseBean { + + private Long id; + private Long applicationId; + private ApplicationStatusTypeEnum applicationStatus; + private Long assignedApplicationId; + private String note; + private ApplicationEvaluationStatusTypeEnum status; + private Long minScore; + private List criteria; + private List checklist; + private List files; + private List evaluationDocument; + private List amendmentDetails; + private LocalDateTime createdDate; + private LocalDateTime updatedDate; + private String beneficiary; + private Long assignedUserId; + private String assignedUserName; + private Long protocolNumber; + private String callName; + private String motivation; + private LocalDateTime submissionDate; + private LocalDateTime evaluationEndDate; + private LocalDateTime callEndDate; + private String companyName; + private LocalDateTime assignedAt; + private String ndg; + private String appointmentId; + private BigDecimal amountRequested; + private BigDecimal amountAccepted; + private LocalDateTime dateAccepted; + private LocalDateTime dateRejected; + private Long numberOfCheck; + private Long appointmentTemplateId; + private EvaluationVersionEnum evaluationVersion; + private String companyVatNumber; + private String companyCodiceAteco; + private List emailSendResponse; +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java index 86140ac6..67258e9c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java @@ -19,7 +19,7 @@ public interface ApplicationEvaluationService { void deleteApplicationEvaluation(HttpServletRequest request,Long id); - ApplicationEvaluationResponse getApplicationEvaluationByApplicationId(HttpServletRequest request,Long applicationId,Long assignedApplicationId); + ApplicationEvaluationResponseBean getApplicationEvaluationByApplicationId(HttpServletRequest request,Long applicationId,Long assignedApplicationId); ApplicationEvaluationEntity validateApplicationEvaluation(Long applicationEvaluationId); ApplicationEvaluationEntity validateApplicationEvaluationByApplicationId(Long applicationId); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java index 044c0902..570487a8 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java @@ -11,6 +11,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationEvaluationFormReque import net.gepafin.tendermanagement.model.request.ApplicationEvaluationRequest; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationFormResponse; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationResponse; +import net.gepafin.tendermanagement.model.response.ApplicationEvaluationResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationEvaluationVersionResponse; import net.gepafin.tendermanagement.repositories.AssignedApplicationsRepository; import net.gepafin.tendermanagement.service.ApplicationEvaluationService; @@ -56,7 +57,7 @@ public class ApplicationEvaluationServiceImpl implements ApplicationEvaluationSe @Override @Transactional(readOnly = true) - public ApplicationEvaluationResponse getApplicationEvaluationByApplicationId( + public ApplicationEvaluationResponseBean getApplicationEvaluationByApplicationId( HttpServletRequest request, Long applicationId, Long assignedApplicationId) { UserEntity preInstructor = validator.validateUser(request); return applicationEvaluationDao.getApplicationEvaluationByApplicationId( diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java index 4798e078..1b60e9d7 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java @@ -44,7 +44,7 @@ public interface ApplicationEvaluationApi { @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })) }) @GetMapping(value = "/application", produces = MediaType.APPLICATION_JSON_VALUE) - ResponseEntity> getApplicationEvaluationByApplicationId( + ResponseEntity> getApplicationEvaluationByApplicationId( HttpServletRequest request, @Parameter(required = false) @RequestParam(value = "applicationId", required = false) Long applicationId, @Parameter( required = false) @RequestParam(value = "assignedApplicationId", required = false) Long assignedApplicationId); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java index 50eadb36..85486435 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java @@ -51,7 +51,7 @@ public class ApplicationEvaluationApiController implements ApplicationEvaluation @Override - public ResponseEntity> getApplicationEvaluationByApplicationId( + public ResponseEntity> getApplicationEvaluationByApplicationId( HttpServletRequest request, Long applicationId, Long assignedApplicationId) { @@ -59,7 +59,7 @@ public class ApplicationEvaluationApiController implements ApplicationEvaluation loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_APPLICATION_EVALUATION).build()); - ApplicationEvaluationResponse response = null; + ApplicationEvaluationResponseBean response = null; response = applicationEvaluationService.getApplicationEvaluationByApplicationId(request, applicationId,assignedApplicationId); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(response, Status.SUCCESS, Translator.toLocale(GepafinConstant.EVALUATION_FETCHED_SUCCESSFULLY))); From 34e01cd64c6a747bc4c499eff6e211821e93906e Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 14 May 2025 16:02:06 +0530 Subject: [PATCH 45/63] Updated code --- .../net/gepafin/tendermanagement/dao/ApplicationDao.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 9dfba4b0..9648b749 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2179,7 +2179,6 @@ public class ApplicationDao { Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG)); } validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); - validateCallEndDate(applicationEntity); assignedApplicationsRepository.findByApplicationIdAndStatusAndIsDeletedFalse(applicationEntity.getId(), AssignedApplicationEnum.CLOSE.getValue()) .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); @@ -2189,10 +2188,6 @@ public class ApplicationDao { private ApplicationEntity fetchRejectedApplication(Long applicationId) { return applicationRepository.findByIdAndStatusAndIsDeletedFalse(applicationId, ApplicationStatusTypeEnum.REJECTED.getValue()); } - private void validateCallEndDate(ApplicationEntity applicationEntity) { - checkCallEndDate(applicationEntity.getCall()); - log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); - } private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse(assignedApp.getId(), ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()) From dbf7a8d5640e00edd5cabadbdf6e6d3f710f934f Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 14 May 2025 16:57:03 +0530 Subject: [PATCH 46/63] Fixed issue hub assigned application pagination --- .../dao/AssignedApplicationsDao.java | 11 ++-- .../entities/AssignedApplicationsView.java | 3 + .../db/changelog/db.changelog-1.0.0.xml | 4 ++ ...te_assigned_application_view_14_5_2025.sql | 57 +++++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java index c7263313..7339a7c5 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java @@ -315,7 +315,8 @@ public class AssignedApplicationsDao { if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } - Specification spec = searchByPagination( assignedApplicationPageableRequestBean, user,userId); + Long hubId=user.getHub().getId(); + Specification spec = searchByPagination( assignedApplicationPageableRequestBean,hubId,userId); Page entityPage = assignedApplicationsViewRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response @@ -333,10 +334,10 @@ public class AssignedApplicationsDao { return pageableResponseBean; } - public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, UserEntity userEntity,Long userId) { + public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, Long hubId,Long userId) { return (root, query, criteriaBuilder) -> { - List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, userEntity,userId); + List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, hubId,userId); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (assignedApplicationPageableRequestBean.getGlobalFilters() != null @@ -377,7 +378,7 @@ public class AssignedApplicationsDao { private List getPredicates(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, - CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity,Long userId) { + CriteriaBuilder criteriaBuilder, Root root,Long hubId,Long userId) { Integer year = null; String search = null; @@ -448,6 +449,8 @@ public class AssignedApplicationsDao { } predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); + predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.HUB_ID), hubId)); + Utils.applyFiltersByPagination(root, criteriaBuilder, predicates, filters); return predicates; diff --git a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java index 71cd1075..46bf004b 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java @@ -64,4 +64,7 @@ public class AssignedApplicationsView{ @Convert(converter = EmailSendResponseConverter.class) @Column(name = "EMAIL_SEND_RESPONSE", columnDefinition = "TEXT") private List emailSendResponse; + + @Column(name = "HUB_ID") + private Long hubId; } diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index bff80f3f..0b4e6cc7 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2801,4 +2801,8 @@ path="db/dump/update_system_email_template_for_application_submission_failure_08_05_2025.sql"/> + + + diff --git a/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql b/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql new file mode 100644 index 00000000..ec2ba975 --- /dev/null +++ b/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql @@ -0,0 +1,57 @@ + +DROP VIEW IF EXISTS gepafin_schema.assigned_applications_view ; + +CREATE OR REPLACE VIEW gepafin_schema.assigned_applications_view AS +SELECT + -- From assigned_applications + aa.id AS id, + aa.user_id AS user_id, + aa.status AS status, + aa.created_date AS created_date, + aa.updated_date AS updated_date, + aa.is_deleted AS is_deleted, + + -- From application + a.id AS application_id, + a.hub_id as hub_id, + a.status AS application_status, + a.submission_date AS submission_date, + ae.end_date AS evaluation_end_date, + a.ndg AS ndg, + a.appointment_id AS appointment_id, + + -- From protocol (OneToOne) + p.protocol_number AS protocol_number, + + -- From call (ManyToOne) + cl.name AS call_name, + + -- From company (ManyToOne) + c.company_name AS company_name, + ae.email_send_response AS email_send_response + +FROM gepafin_schema.assigned_applications aa + +-- Join application (ManyToOne from assigned_applications) +LEFT JOIN gepafin_schema.application a + ON aa.application_id = a.id + AND (a.is_deleted IS FALSE OR a.is_deleted IS NULL) + +-- Join application_evaluation (application_id matches + not deleted) +LEFT JOIN gepafin_schema.application_evaluation ae + ON ae.application_id = a.id + AND (ae.is_deleted IS FALSE OR ae.is_deleted IS NULL) + +-- Join protocol (OneToOne from application) +LEFT JOIN gepafin_schema.protocol p + ON a.protocol_number = p.id + +-- Join call (ManyToOne from application) +LEFT JOIN gepafin_schema.call cl + ON a.call_id = cl.id + +-- Join company (ManyToOne from application) +LEFT JOIN gepafin_schema.company c + ON a.company_id = c.id + +WHERE aa.is_deleted IS FALSE OR aa.is_deleted IS NULL; From 9db2aad0313cb5cdaa0aaeb8254e79733c51859a Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 14 May 2025 16:57:03 +0530 Subject: [PATCH 47/63] Resolved conflicts --- .../dao/AssignedApplicationsDao.java | 11 ++-- .../entities/AssignedApplicationsView.java | 3 + .../db/changelog/db.changelog-1.0.0.xml | 5 ++ ...te_assigned_application_view_14_5_2025.sql | 57 +++++++++++++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java index 17f18c9c..30ebb149 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java @@ -315,7 +315,8 @@ public class AssignedApplicationsDao { if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } - Specification spec = searchByPagination( assignedApplicationPageableRequestBean, user,userId); + Long hubId=user.getHub().getId(); + Specification spec = searchByPagination( assignedApplicationPageableRequestBean,hubId,userId); Page entityPage = assignedApplicationsViewRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response @@ -333,10 +334,10 @@ public class AssignedApplicationsDao { return pageableResponseBean; } - public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, UserEntity userEntity,Long userId) { + public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, Long hubId,Long userId) { return (root, query, criteriaBuilder) -> { - List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, userEntity,userId); + List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, hubId,userId); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (assignedApplicationPageableRequestBean.getGlobalFilters() != null @@ -377,7 +378,7 @@ public class AssignedApplicationsDao { private List getPredicates(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, - CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity,Long userId) { + CriteriaBuilder criteriaBuilder, Root root,Long hubId,Long userId) { Integer year = null; String search = null; @@ -448,6 +449,8 @@ public class AssignedApplicationsDao { } predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); + predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.HUB_ID), hubId)); + Utils.applyFiltersByPagination(root, criteriaBuilder, predicates, filters); return predicates; diff --git a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java index a446daff..75d396a9 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/AssignedApplicationsView.java @@ -58,4 +58,7 @@ public class AssignedApplicationsView{ @Column(name = "IS_DELETED") private Boolean isDeleted; + + @Column(name = "HUB_ID") + private Long hubId; } diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 38e13676..e10adc93 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2746,4 +2746,9 @@ + + + + diff --git a/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql b/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql new file mode 100644 index 00000000..ec2ba975 --- /dev/null +++ b/src/main/resources/db/dump/update_assigned_application_view_14_5_2025.sql @@ -0,0 +1,57 @@ + +DROP VIEW IF EXISTS gepafin_schema.assigned_applications_view ; + +CREATE OR REPLACE VIEW gepafin_schema.assigned_applications_view AS +SELECT + -- From assigned_applications + aa.id AS id, + aa.user_id AS user_id, + aa.status AS status, + aa.created_date AS created_date, + aa.updated_date AS updated_date, + aa.is_deleted AS is_deleted, + + -- From application + a.id AS application_id, + a.hub_id as hub_id, + a.status AS application_status, + a.submission_date AS submission_date, + ae.end_date AS evaluation_end_date, + a.ndg AS ndg, + a.appointment_id AS appointment_id, + + -- From protocol (OneToOne) + p.protocol_number AS protocol_number, + + -- From call (ManyToOne) + cl.name AS call_name, + + -- From company (ManyToOne) + c.company_name AS company_name, + ae.email_send_response AS email_send_response + +FROM gepafin_schema.assigned_applications aa + +-- Join application (ManyToOne from assigned_applications) +LEFT JOIN gepafin_schema.application a + ON aa.application_id = a.id + AND (a.is_deleted IS FALSE OR a.is_deleted IS NULL) + +-- Join application_evaluation (application_id matches + not deleted) +LEFT JOIN gepafin_schema.application_evaluation ae + ON ae.application_id = a.id + AND (ae.is_deleted IS FALSE OR ae.is_deleted IS NULL) + +-- Join protocol (OneToOne from application) +LEFT JOIN gepafin_schema.protocol p + ON a.protocol_number = p.id + +-- Join call (ManyToOne from application) +LEFT JOIN gepafin_schema.call cl + ON a.call_id = cl.id + +-- Join company (ManyToOne from application) +LEFT JOIN gepafin_schema.company c + ON a.company_id = c.id + +WHERE aa.is_deleted IS FALSE OR aa.is_deleted IS NULL; From ce2880304765d1012065b9a4cfed6ecca5ec32c4 Mon Sep 17 00:00:00 2001 From: nisha Date: Thu, 15 May 2025 13:50:31 +0530 Subject: [PATCH 48/63] Updated code --- .../java/net/gepafin/tendermanagement/dao/ApplicationDao.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 9648b749..d8877015 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2180,7 +2180,7 @@ public class ApplicationDao { } validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); - assignedApplicationsRepository.findByApplicationIdAndStatusAndIsDeletedFalse(applicationEntity.getId(), AssignedApplicationEnum.CLOSE.getValue()) + assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationEntity.getId()) .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); return getApplicationResponse(applicationEntity); @@ -2190,7 +2190,7 @@ public class ApplicationDao { } private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { - applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse(assignedApp.getId(), ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()) + applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse(assignedApp.getId()) .ifPresent(eval -> reopenApplication(request, applicationEntity, assignedApp, eval)); } From e5c8d27f91960c891373fee82af182bf564bdf71 Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 14 May 2025 11:36:35 +0530 Subject: [PATCH 49/63] Resolved conflicts --- .../constants/GepafinConstant.java | 1 + .../dao/ApplicationAmendmentRequestDao.java | 4 +- .../tendermanagement/dao/ApplicationDao.java | 82 +++++++++++++++++++ .../enums/UserActionContextEnum.java | 1 + .../ApplicationEvaluationRepository.java | 5 ++ .../repositories/ApplicationRepository.java | 3 + .../AssignedApplicationsRepository.java | 4 + .../service/ApplicationService.java | 2 + .../service/impl/ApplicationServiceImpl.java | 7 +- .../web/rest/api/ApplicationApi.java | 14 ++++ .../api/impl/ApplicationApiController.java | 11 +++ src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 7 +- 13 files changed, 136 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 5c849a47..8b3e8b54 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -537,6 +537,7 @@ public class GepafinConstant { public static final String APPLICATION_STATUS="applicationStatus"; public static final String RINALDO_EMAIL = "rinaldo.bonazzo@bflows.net"; + public static final String READMIT_APPLICATION_SUCCESS = "application.readmit.success"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index daa4391b..b1ac989b 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -1072,12 +1072,12 @@ public class ApplicationAmendmentRequestDao { application.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); applicationRepository.save(application); - existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().setStatus(AssignedApplicationEnum.OPEN.getValue()); - AssignedApplicationsEntity assignedApplicationsEntity = assignedApplicationsDao.validateAssignedApplication( existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().getId()); AssignedApplicationsEntity oldAssignedApplicationData = Utils.getClonedEntityForData(assignedApplicationsEntity); + existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().setStatus(AssignedApplicationEnum.OPEN.getValue()); + assignedApplicationsEntity = assignedApplicationsRepository.save(existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index e95e1c8b..71a9b515 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2132,6 +2132,88 @@ public class ApplicationDao { tableDataByApp.put(appId, flattenedAll); } } + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId) { + log.info("Re-admiting the Application with id : {}", applicationId); + + ApplicationEntity applicationEntity = fetchRejectedApplication(applicationId); + if(applicationEntity == null){ + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG)); + } + validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); + validateCallEndDate(applicationEntity); + + assignedApplicationsRepository.findByApplicationIdAndStatusAndIsDeletedFalse(applicationEntity.getId(), AssignedApplicationEnum.CLOSE.getValue()) + .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); + + return getApplicationResponse(applicationEntity); + } + private ApplicationEntity fetchRejectedApplication(Long applicationId) { + return applicationRepository.findByIdAndStatusAndIsDeletedFalse(applicationId, ApplicationStatusTypeEnum.REJECTED.getValue()); + } + private void validateCallEndDate(ApplicationEntity applicationEntity) { + checkCallEndDate(applicationEntity.getCall()); + log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); + } + + private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { + applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse(assignedApp.getId(), ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()) + .ifPresent(eval -> reopenApplication(request, applicationEntity, assignedApp, eval)); + } + + + private void reopenApplication(HttpServletRequest request, ApplicationEntity applicationEntity, + AssignedApplicationsEntity assignedApp, ApplicationEvaluationEntity evaluationEntity) { + + ApplicationEntity oldApplication = Utils.getClonedEntityForData(applicationEntity); + AssignedApplicationsEntity oldAssignedApp = Utils.getClonedEntityForData(assignedApp); + ApplicationEvaluationEntity oldEvaluation = Utils.getClonedEntityForData(evaluationEntity); + + updateApplicationStatus(applicationEntity); + updateAssignedApplicationStatus(assignedApp); + updateEvaluationEntity(applicationEntity.getHubId(), evaluationEntity); + + saveEntities(applicationEntity, assignedApp, evaluationEntity); + + /** This code is responsible for adding a version history log for the "Update Application" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplication).newData(applicationEntity).build()); + + /** This code is responsible for adding a version history log for the "Update Application Evaluation" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldEvaluation).newData(evaluationEntity).build()); + + /** This code is responsible for adding a version history log for the "Update Assigned Application" operation. **/ + loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldAssignedApp).newData(assignedApp).build()); + } + + private void updateApplicationStatus(ApplicationEntity applicationEntity) { + applicationEntity.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); + applicationEntity.setDateRejected(null); + } + + private void updateAssignedApplicationStatus(AssignedApplicationsEntity assignedApp) { + assignedApp.setStatus(AssignedApplicationEnum.OPEN.getValue()); + } + + private void updateEvaluationEntity(Long hubId, ApplicationEvaluationEntity evaluationEntity) { + HubEntity hub = hubService.valdateHub(hubId); + Long evaluationDays = (hub != null) ? hub.getEvaluationExpirationDays() : 30L; + + LocalDateTime now = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); + evaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.OPEN.getValue()); + evaluationEntity.setClosingDate(null); + evaluationEntity.setActiveDays(null); + evaluationEntity.setEndDate(now.plusDays(evaluationDays)); + evaluationEntity.setStartDate(now); + evaluationEntity.setRemainingDays(evaluationDays); + evaluationEntity.setSuspendedDays(0L); + evaluationEntity.setStopDateTime(null); + } + + private void saveEntities(ApplicationEntity app, AssignedApplicationsEntity assignedApp, ApplicationEvaluationEntity eval) { + applicationRepository.save(app); + assignedApplicationsRepository.save(assignedApp); + applicationEvaluationRepository.save(eval); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index a1f7ee5c..7ee87e08 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -46,6 +46,7 @@ public enum UserActionContextEnum { GET_SIGNED_DOCUMENT("GET_SIGNED_DOCUMENT"), GET_NEXT_PREVIOUS_FORM("GET_NEXT_PREVIOUS_FORM"), DOWNLOAD_APPLICATION_DOC_ZIP("DOWNLOAD_APPLICATION_DOC_ZIP"), + READMIT_APPLICATION("READMIT_APPLICATION"), /** FAQ action context **/ CREATE_FAQ("CREATE_FAQ"), diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java index 9019aad4..306ad3a5 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationEvaluationRepository.java @@ -76,5 +76,10 @@ public interface ApplicationEvaluationRepository extends JpaRepository findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse( + Long assignedApplicationId, + String status + ); + } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java index b5cf7fb9..c760689a 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java @@ -178,4 +178,7 @@ public interface ApplicationRepository extends JpaRepository findByApplicationIdAndStatusAndIsDeletedFalse( Long applicationId, String status); + + + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index 24fde801..c7af4f88 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -50,4 +50,6 @@ public interface ApplicationService { public byte[] exportCsv(HttpServletRequest request, Long callId); + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index 879c72cf..357661d1 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -170,5 +170,10 @@ public class ApplicationServiceImpl implements ApplicationService { return csvBytes; } - + @Override + @Transactional(rollbackFor = Exception.class) + public ApplicationResponse readmitApplication(HttpServletRequest request, Long applicationId) { + UserEntity userEntity = validator.validateUser(request); + return applicationDao.readmitApplication(request, applicationId); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index 00609f68..a18e6852 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -238,6 +238,20 @@ public interface ApplicationApi { public ResponseEntity exportCsv( HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable(value = "callId", required = true) Long callId); + @Operation(summary = "Api to re-admit an application", + responses = { + @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { + @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) + @PutMapping(value = "/{applicationId}/readmit", produces = { "application/json" }) + @PreAuthorize("hasRole('ROLE_SUPER_ADMIN')|| hasRole('ROLE_INSTRUCTOR_MANAGER')|| hasRole('ROLE_PRE_INSTRUCTOR')") + ResponseEntity> readmitApplication(HttpServletRequest request, + @Parameter(description = "The application id", required = true) @PathVariable("applicationId") Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index a06f5dc4..840711ae 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -242,5 +242,16 @@ public class ApplicationApiController implements ApplicationApi { .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(csvBytes); } + @Override + public ResponseEntity> readmitApplication(HttpServletRequest request, Long applicationId) { + /** This code is responsible for creating user action logs for the "re-admit application" operation. **/ + loggingUtil.logUserAction( + UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE).actionContext(UserActionContextEnum.READMIT_APPLICATION).build()); + + ApplicationResponse applicationResponse = applicationService.readmitApplication(request, applicationId); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(applicationResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.READMIT_APPLICATION_SUCCESS))); + } } diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index e67042ab..237e6e53 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -400,3 +400,4 @@ insufficient.score.msg = Insufficient score to pass to the technical and economi password.expired.for.login.to.odessa = Odessa login password has been expired. invalid.user=Invalid user. +application.readmit.success=Application has been readmitted successfully. \ No newline at end of file diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index fd7f09e1..35247fe3 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -53,7 +53,7 @@ call.update.successfully=Chiamata aggiornata con successo. call.fetch.success=Dettagli della chiamata recuperati con successo. call.not.found=Chiamata non trovata. score.not.null=Il punteggio non pu? essere nullo o zero. -field.not.null={0} non può essere vuoto. +field.not.null={0} non pu� essere vuoto. field.not.empty=la {0} non pu? essere vuota. update_call_status_success_msg=Lo stato della chiamata ? stato aggiornato con successo. status.same.error=Lo stato ? gi? impostato. @@ -389,5 +389,6 @@ error.invalid.limit=Il limite dovrebbe essere compreso tra 1 e 3000. insufficient.score.msg = Punteggio non sufficiente per passaggio alla valutazione tecnica ed economico finanziaria validation.table.message=I dati per il campo {0} non sono presenti. -password.expired.for.login.to.odessa = La password di accesso a Odessa è scaduta -invalid.user=Utente non valido. \ No newline at end of file +password.expired.for.login.to.odessa = La password di accesso a Odessa � scaduta +invalid.user=Utente non valido. +application.readmit.success=L'applicazione è stata riammessa con successo. From 78b2ff40463bb9425944323a42d5d3b22f9efb10 Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 14 May 2025 16:02:06 +0530 Subject: [PATCH 50/63] Updated code --- .../net/gepafin/tendermanagement/dao/ApplicationDao.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 71a9b515..2d2fd4a5 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2141,7 +2141,6 @@ public class ApplicationDao { Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG)); } validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); - validateCallEndDate(applicationEntity); assignedApplicationsRepository.findByApplicationIdAndStatusAndIsDeletedFalse(applicationEntity.getId(), AssignedApplicationEnum.CLOSE.getValue()) .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); @@ -2151,10 +2150,6 @@ public class ApplicationDao { private ApplicationEntity fetchRejectedApplication(Long applicationId) { return applicationRepository.findByIdAndStatusAndIsDeletedFalse(applicationId, ApplicationStatusTypeEnum.REJECTED.getValue()); } - private void validateCallEndDate(ApplicationEntity applicationEntity) { - checkCallEndDate(applicationEntity.getCall()); - log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); - } private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse(assignedApp.getId(), ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()) From 8664f0096134c1f9743b82497f7bc0eaf52db03b Mon Sep 17 00:00:00 2001 From: nisha Date: Thu, 15 May 2025 13:50:31 +0530 Subject: [PATCH 51/63] Updated code --- .../java/net/gepafin/tendermanagement/dao/ApplicationDao.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 2d2fd4a5..89c8d1e9 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -2142,7 +2142,7 @@ public class ApplicationDao { } validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); - assignedApplicationsRepository.findByApplicationIdAndStatusAndIsDeletedFalse(applicationEntity.getId(), AssignedApplicationEnum.CLOSE.getValue()) + assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationEntity.getId()) .ifPresent(assignedApp -> processAssignedAppAndEvaluation(request, applicationEntity, assignedApp)); return getApplicationResponse(applicationEntity); @@ -2152,7 +2152,7 @@ public class ApplicationDao { } private void processAssignedAppAndEvaluation(HttpServletRequest request, ApplicationEntity applicationEntity, AssignedApplicationsEntity assignedApp) { - applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndStatusAndIsDeletedFalse(assignedApp.getId(), ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()) + applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse(assignedApp.getId()) .ifPresent(eval -> reopenApplication(request, applicationEntity, assignedApp, eval)); } From 6b67263c53c14456ea4717ed3f4620a6596aae05 Mon Sep 17 00:00:00 2001 From: nisha Date: Thu, 15 May 2025 18:34:05 +0530 Subject: [PATCH 52/63] Done ticket GEPAFINBE-213 --- .../dao/ApplicationAmendmentRequestDao.java | 152 ++++++++++++++---- ...ApplicationAmendmentRequestRepository.java | 2 + .../ApplicationAmendmentScheduler.java | 2 +- 3 files changed, 125 insertions(+), 31 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index daa4391b..3820d9da 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -26,6 +26,7 @@ import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundExceptio import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; @@ -1032,7 +1033,7 @@ public class ApplicationAmendmentRequestDao { public ApplicationAmendmentRequestResponse closeAmendmentRequest(Long id, CloseAmendmentRequest closeAmendmentRequest) { log.info("Closing application amendement with ID: {}", id); - ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); + ApplicationAmendmentRequestEntity existingApplicationAmendment = validatApplicationAmendmentRequestByStatus(id,ApplicationAmendmentRequestEnum.AWAITING.getValue()); //cloned entity for old data and versioning ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); List amendmentRequestList = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( @@ -1042,17 +1043,18 @@ public class ApplicationAmendmentRequestDao { // Check if this is the last amendment being closed boolean isLastRemaining = amendmentRequestList.stream() .filter(amendment -> !amendment.getId().equals(id)) // Exclude the current amendment - .allMatch(amendment -> amendment.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue())); + .allMatch(amendment -> amendment.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue()) || amendment.getStatus().equals(ApplicationAmendmentRequestEnum.EXPIRED.getValue())); + - if (isLastRemaining) { - log.info("The current amendment is the last remaining one to be closed."); - applicationAmendmentRequestDao.calculateEndDateAndSuspensionDays(existingApplicationAmendment.getApplicationEvaluationEntity()); - } setIfUpdated(existingApplicationAmendment::getInternalNote, existingApplicationAmendment::setInternalNote, closeAmendmentRequest.getInternalNote()); setIfUpdated(existingApplicationAmendment::getStatus, existingApplicationAmendment::setStatus, ApplicationAmendmentRequestEnum.CLOSE.getValue()); existingApplicationAmendment.setClosingDate(LocalDateTime.now()); ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment, oldApplicationAmendmentEntity, VersionActionTypeEnum.UPDATE); + if (isLastRemaining) { + log.info("The current amendment is the last remaining one to be closed."); + applicationAmendmentRequestDao.calculateEndDateAndSuspensionDaysOnExpirationOrClosing(existingApplicationAmendment.getApplicationEvaluationEntity()); + } ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false); List amendmentRequests = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( @@ -1104,15 +1106,17 @@ public class ApplicationAmendmentRequestDao { return response; } - public ApplicationAmendmentRequestResponse extendResponseDays(Long id, Long newResponseDays) { - ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); + ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validatApplicationAmendmentRequestByStatus(id,ApplicationAmendmentRequestEnum.EXPIRED.getValue()); if (newResponseDays != null && newResponseDays > 0) { - ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(applicationAmendmentRequestEntity); + ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(applicationAmendmentRequestEntity); Long currentResponseDays = applicationAmendmentRequestEntity.getResponseDays() != null ? applicationAmendmentRequestEntity.getResponseDays() : 0L; applicationAmendmentRequestEntity.setResponseDays(currentResponseDays + newResponseDays); - applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now().plusDays(applicationAmendmentRequestEntity.getResponseDays()))); + applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now().plusDays(newResponseDays))); + applicationAmendmentRequestEntity.setStatus(ApplicationAmendmentRequestEnum.AWAITING.getValue()); + applicationAmendmentRequestEntity.getApplicationEvaluationEntity().setStatus(ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue()); + applicationAmendmentRequestEntity.getApplicationEvaluationEntity().getAssignedApplicationsEntity().getApplication().setStatus(ApplicationStatusTypeEnum.SOCCORSO.getValue()); applicationAmendmentRequestRepository.save(applicationAmendmentRequestEntity); /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ @@ -1219,26 +1223,26 @@ public class ApplicationAmendmentRequestDao { return Utils.replacePlaceholders(template.getHtmlContent(), bodyPlaceholders); } - public ApplicationEvaluationEntity calculateEndDateAndSuspensionDays(ApplicationEvaluationEntity applicationEvaluationEntity){ - LocalDateTime currentDate=DateTimeUtil.DateServerToUTC(LocalDateTime.now()); - LocalDateTime endDate=currentDate.plusDays(applicationEvaluationEntity.getRemainingDays()); - Long suspendedDays = ChronoUnit.DAYS.between(applicationEvaluationEntity.getStopDateTime(), currentDate); - - ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); - applicationEvaluationEntity.setEndDate(endDate); - if(applicationEvaluationEntity.getSuspendedDays() == null) { - applicationEvaluationEntity.setSuspendedDays(0L); - } - applicationEvaluationEntity.setSuspendedDays(applicationEvaluationEntity.getSuspendedDays()+suspendedDays); - ApplicationEvaluationEntity applicationEvaluation = applicationEvaluationRepository.save(applicationEvaluationEntity); - - /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ - loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(applicationEvaluation).build()); - - return applicationEvaluation; - - - } +// public ApplicationEvaluationEntity calculateEndDateAndSuspensionDays(ApplicationEvaluationEntity applicationEvaluationEntity){ +// LocalDateTime currentDate=DateTimeUtil.DateServerToUTC(LocalDateTime.now()); +// LocalDateTime endDate=currentDate.plusDays(applicationEvaluationEntity.getRemainingDays()); +// Long suspendedDays = ChronoUnit.DAYS.between(applicationEvaluationEntity.getStopDateTime(), currentDate); +// +// ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); +// applicationEvaluationEntity.setEndDate(endDate); +// if(applicationEvaluationEntity.getSuspendedDays() == null) { +// applicationEvaluationEntity.setSuspendedDays(0L); +// } +// applicationEvaluationEntity.setSuspendedDays(applicationEvaluationEntity.getSuspendedDays()+suspendedDays); +// ApplicationEvaluationEntity applicationEvaluation = applicationEvaluationRepository.save(applicationEvaluationEntity); +// +// /** This code is responsible for adding a version history log for the "Update Application Amendment" operation. **/ +// loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(applicationEvaluation).build()); +// +// return applicationEvaluation; +// +// +// } private GetAllAmendmentResponseBean initializeGetAllBasicResponse(ApplicationAmendmentRequestEntity entity) { GetAllAmendmentResponseBean response = new GetAllAmendmentResponseBean(); @@ -1542,5 +1546,93 @@ public class ApplicationAmendmentRequestDao { return applicationAmendmentRequestViewResponse; } + public ApplicationEvaluationEntity calculateEndDateAndSuspensionDaysOnExpirationOrClosing + (ApplicationEvaluationEntity applicationEvaluationEntity) { + + // Fetch all linked amendments + List amendments = + applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(applicationEvaluationEntity.getId()); + + // Recalculate suspension + long suspendedDays = calculateSuspendedDays(amendments); + + // Update end date and save + + ApplicationEvaluationEntity oldEntity = Utils.getClonedEntityForData(applicationEvaluationEntity); + HubEntity hub = hubService.valdateHub(applicationEvaluationEntity.getAssignedApplicationsEntity().getApplication().getHubId()); + Long initialDays = (hub != null) ? hub.getEvaluationExpirationDays() : 30L; + LocalDateTime endDate = applicationEvaluationEntity.getStartDate().plusDays(suspendedDays+initialDays); + applicationEvaluationEntity.setEndDate(endDate); + applicationEvaluationEntity.setSuspendedDays(suspendedDays); + ApplicationEvaluationEntity updated = applicationEvaluationRepository.save(applicationEvaluationEntity); + + loggingUtil.addVersionHistory(VersionHistoryRequest.builder() + .request(request) + .actionType(VersionActionTypeEnum.UPDATE) + .oldData(oldEntity) + .newData(updated) + .build()); + + return updated; + } + + public long calculateSuspendedDays(List amendments) { + List> periods = amendments.stream() + .filter(amendmentRequest -> amendmentRequest.getStartDate() != null) + .map(amendmentRequest -> { + LocalDateTime start = amendmentRequest.getStartDate(); + LocalDateTime end; + + String status = amendmentRequest.getStatus(); + if (Boolean.TRUE.equals(ApplicationAmendmentRequestEnum.CLOSE.getValue().equals(status)) && amendmentRequest.getClosingDate() != null) { + end = amendmentRequest.getClosingDate(); + } else if (Boolean.TRUE.equals(ApplicationAmendmentRequestEnum.EXPIRED.getValue().equals(status)) && amendmentRequest.getEndDate() != null) { + end = amendmentRequest.getStartDate().plusDays(amendmentRequest.getResponseDays()); + }else { + end= amendmentRequest.getEndDate(); + } + + return Pair.of(start, end); + }) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(Pair::getLeft)) + .collect(Collectors.toList()); + + long totalDays = 0; + LocalDateTime currentStart = null; + LocalDateTime currentEnd = null; + + for (Pair period : periods) { + if (currentStart == null) { + currentStart = period.getLeft(); + currentEnd = period.getRight(); + } else if (!period.getLeft().isAfter(currentEnd)) { + // Merge overlapping/touching periods + currentEnd = currentEnd.isAfter(period.getRight()) ? currentEnd : period.getRight(); + } else { + // Non-overlapping: count previous period + totalDays += ChronoUnit.DAYS.between(currentStart.toLocalDate(), currentEnd.toLocalDate()); + currentStart = period.getLeft(); + currentEnd = period.getRight(); + } + } + + if (currentStart != null && currentEnd != null) { + totalDays += ChronoUnit.DAYS.between(currentStart.toLocalDate(), currentEnd.toLocalDate()); + } + + return totalDays; + } + + + + public ApplicationAmendmentRequestEntity validatApplicationAmendmentRequestByStatus(Long id,String status) { + ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity= applicationAmendmentRequestRepository.findByIdAndIsDeletedFalseAndStatus(id,status); + if(applicationAmendmentRequestEntity==null){ + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)); + } + return applicationAmendmentRequestEntity; + } } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java index fc492019..4cd6d413 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java @@ -150,4 +150,6 @@ public interface ApplicationAmendmentRequestRepository extends JpaRepository applicationIds, @Param("statuses") List statuses); + + ApplicationAmendmentRequestEntity findByIdAndIsDeletedFalseAndStatus(Long id,String status); } diff --git a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java index 6a4c7b81..050b4972 100644 --- a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java +++ b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationAmendmentScheduler.java @@ -122,7 +122,7 @@ public class ApplicationAmendmentScheduler { .findEvaluationsWithoutActiveAmendmentsByIds(applicationEvaluationIds); evaluationsWithoutActiveAmendmentList.forEach(evaluation -> { try { - applicationAmendmentRequestDao.calculateEndDateAndSuspensionDays(evaluation); + applicationAmendmentRequestDao.calculateEndDateAndSuspensionDaysOnExpirationOrClosing(evaluation); updateEvaluationStatus(evaluation); From 64f5bde4376b6f1c9f3778a3ad03ae2bc7e04529 Mon Sep 17 00:00:00 2001 From: Piyush Date: Mon, 19 May 2025 13:36:11 +0530 Subject: [PATCH 53/63] PEC success emails not saved or included in response --- .../dao/ApplicationAmendmentRequestDao.java | 36 +++++++++++-------- .../dao/ApplicationEvaluationDao.java | 36 ++++++++++++------- .../tendermanagement/dao/EmailDao.java | 6 ++-- .../gepafin/tendermanagement/dao/UserDao.java | 32 ++++++++++++----- .../entities/EmailSendResponseConverter.java | 3 ++ .../ApplicationAmendmentRequestResponse.java | 2 +- .../ApplicationEvaluationFormResponse.java | 1 + .../ApplicationEvaluationResponse.java | 2 +- .../model/response/EmailReminderResponse.java | 4 ++- .../InitiatePasswordResetResponse.java | 4 ++- .../tendermanagement/model/util/JWTToken.java | 6 ++-- .../ApplicationAmendmentRequestService.java | 2 +- .../service/ApplicationEvaluationService.java | 2 +- ...pplicationAmendmentRequestServiceImpl.java | 2 +- .../ApplicationEvaluationServiceImpl.java | 2 +- .../service/impl/AuthenticationService.java | 2 +- .../api/ApplicationAmendmentRequestApi.java | 2 +- .../rest/api/ApplicationEvaluationApi.java | 2 +- ...ApplicationAmendmentRequestController.java | 9 ++--- .../ApplicationEvaluationApiController.java | 4 +-- 20 files changed, 98 insertions(+), 61 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 156bab88..f25b5149 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -308,8 +308,14 @@ public class ApplicationAmendmentRequestDao { if (Boolean.TRUE.equals(applicationAmendmentRequestResponse.getIsSendEmail())) { emailNotificationDao.sendMailToNotifyBeneficiaryRegardingNewAmendment(applicationAmendmentRequestEntity); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - applicationAmendmentRequestResponse.setEmailSendResponse(emailSendResponse); - saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity); + List responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + saveEmailSendResponse(emailSendResponse, applicationAmendmentRequestEntity); + applicationAmendmentRequestResponse.setEmailSendResponse(responses); + } + else{ + applicationAmendmentRequestResponse.setEmailSendResponse(Collections.emptyList()); + } } return applicationAmendmentRequestResponse; } @@ -516,6 +522,7 @@ public class ApplicationAmendmentRequestDao { Long hubId = applicationEntity.getHubId(); HubEntity hubEntity = hubService.valdateHub(hubId); + response.setEmailSendResponse(entity.getEmailSendResponse()); response.setId(entity.getId()); response.setApplicationId(entity.getApplicationId()); response.setApplicationEvaluationId(entity.getApplicationEvaluationEntity().getId()); @@ -654,19 +661,12 @@ public class ApplicationAmendmentRequestDao { log.info(" Application amendment deleted with ID: {}", id); } - public ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(Long id) { + public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(Long id) { log.info("Fetching application amendment with ID: {}", id); ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); - ApplicationAmendmentRequestResponse sourceResponse = convertEntityToResponse(applicationAmendmentRequestEntity,true); - ApplicationAmendmentRequestResponseBean targetResponse = Utils.convertSourceObjectToDestinationObject( - sourceResponse, ApplicationAmendmentRequestResponseBean.class - ); - - if (targetResponse != null) { - targetResponse.setEmailSendResponse(applicationAmendmentRequestEntity.getEmailSendResponse()); - } - log.info("Application Amendment fetched successfully by ID: {}", targetResponse); - return targetResponse; + ApplicationAmendmentRequestResponse response = convertEntityToResponse(applicationAmendmentRequestEntity,true); + response.setEmailSendResponse(applicationAmendmentRequestEntity.getEmailSendResponse()); + return response; } public List getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId) { @@ -1205,8 +1205,14 @@ public class ApplicationAmendmentRequestDao { beneficiaryUser.getId(), applicationEntity.getId(), amendment.getId(), applicationEntity.getCall().getId()); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email), emailLogRequest); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - emailReminderResponse.setEmailSendResponse(emailSendResponse); - saveEmailSendResponse(emailSendResponse, amendment); + List responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + emailReminderResponse.setEmailSendResponse(responses); + saveEmailSendResponse(emailSendResponse, amendment); + } + else{ + emailReminderResponse.setEmailSendResponse(Collections.emptyList()); + } } else { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.BENEFICIARY_EMAIL_NOT_FOUND_MSG)); } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 069bbd40..d12ce836 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -1092,7 +1092,7 @@ public class ApplicationEvaluationDao { } validator.validatePreInstructor(request, assignedApplications.getUserId()); } - public ApplicationEvaluationResponseBean getApplicationEvaluationByApplicationId(HttpServletRequest request, UserEntity user, Long applicationID, Long assignedApplicationID) { + public ApplicationEvaluationResponse getApplicationEvaluationByApplicationId(HttpServletRequest request, UserEntity user, Long applicationID, Long assignedApplicationID) { Long applicationId; Long assignedApplicationId; validatePreinstructor(request, applicationID, assignedApplicationID); @@ -1131,12 +1131,9 @@ public class ApplicationEvaluationDao { return null; } ApplicationEvaluationEntity entity = entityOptional.get(); - ApplicationEvaluationResponse response = convertToResponse(entity); - ApplicationEvaluationResponseBean targetResponse = Utils.convertSourceObjectToDestinationObject(response, ApplicationEvaluationResponseBean.class); - if (targetResponse != null && entity.getEmailSendResponse() != null) { - targetResponse.setEmailSendResponse(entity.getEmailSendResponse()); - } - return targetResponse; + ApplicationEvaluationResponse applicationEvaluationResponse = convertToResponse(entity); + applicationEvaluationResponse.setEmailSendResponse(entity.getEmailSendResponse()); + return applicationEvaluationResponse; } private List prepareEvaluationDocumentBeanList(ApplicationEvaluationEntity entity) { List docRequest = new ArrayList<>(); @@ -1893,12 +1890,16 @@ public class ApplicationEvaluationDao { ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(application); + List responses = new ArrayList<>(); if(newStatus.equals(ApplicationStatusForEvaluation.ADMISSIBLE) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.APPOINTMENT.getValue()))){ application.setStatus(newStatus.getValue()); log.info("Status updated to ADMISSIBLE for applicationId: " + application.getId()); emailNotificationDao.sendAdmissibilityNotificationEmailForAdmissibleApplication(application); emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - saveEmailSendResponseToEvaluation(emailSendResponse,existingEntity); + responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) { + saveEmailSendResponseToEvaluation(emailSendResponse, existingEntity); + } } if(newStatus.equals(ApplicationStatusForEvaluation.TECHNICAL_EVALUATION) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))){ @@ -1945,8 +1946,8 @@ public class ApplicationEvaluationDao { if (Boolean.TRUE.equals(statusType.equals((ApplicationStatusTypeEnum.APPROVED.getValue())))) { - application.setDateAccepted(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); - application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); + application.setDateAccepted(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); + application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application = applicationRepository.save(application); // emailNotificationDao.sendAdmissibilityNotificationEmailForApprovedApplication(application); } @@ -1956,7 +1957,10 @@ public class ApplicationEvaluationDao { application = applicationRepository.save(application); emailNotificationDao.sendInadmissibilityEmailForRejectedApplication(application,existingEntity); emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - saveEmailSendResponseToEvaluation(emailSendResponse,existingEntity); + responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) { + saveEmailSendResponseToEvaluation(emailSendResponse, existingEntity); + } } Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); @@ -1964,7 +1968,9 @@ public class ApplicationEvaluationDao { notificationDao.sendNotificationToInstructor(placeHolders,existingEntity,NotificationTypeEnum.EVALUATION_RESULT); ApplicationEvaluationResponse response = convertToResponse(entity); - response.setEmailSendResponse(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())) { + response.setEmailSendResponse(responses); + } return response; } return null; @@ -2029,6 +2035,7 @@ public class ApplicationEvaluationDao { ApplicationEvaluationEntity entity = applicationEvaluationService.validateApplicationEvaluation(evaluationResponse.getId()); + //Handling Application Evaluation form EvaluationFormEntity evaluationFormEntity = evaluationFormService.validateEvaluationForm(evaluationFormId); validateFormFields(applicationEvaluationFormRequestBean,evaluationFormEntity); @@ -2037,7 +2044,9 @@ public class ApplicationEvaluationDao { validateFormFieldCustom(applicationEvaluationFormRequestBean.getFormFields(),entity,evaluationFormEntity); ApplicationEvaluationFormEntity applicationEvaluationFormEntity = getApplicationEvaluationFormOrCreate(evaluationFormEntity,entity); createOrUpdateMultipleFormFields(applicationEvaluationFormRequestBean.getFormFields(), applicationEvaluationFormEntity, evaluationFormEntity); - return processEvaluationForm(entity); + ApplicationEvaluationFormResponse response = processEvaluationForm(entity); + response.setEmailSendResponse(evaluationResponse.getEmailSendResponse()); + return response; } private ApplicationEvaluationFormEntity getApplicationEvaluationFormOrCreate(EvaluationFormEntity evaluationFormEntity, ApplicationEvaluationEntity applicationEvaluationEntity) { @@ -2282,6 +2291,7 @@ public class ApplicationEvaluationDao { } response.setCompanyVatNumber(company.getVatNumber()); response.setCompanyCodiceAteco(company.getCodiceAteco()); + response.setEmailSendResponse(evaluationEntity.getEmailSendResponse()); return response; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java index 9b99facb..244df6a4 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EmailDao.java @@ -161,9 +161,10 @@ public class EmailDao { private boolean updateEmailSendResponse(List responses, String scenario) { if (responses == null || responses.isEmpty()) return false; - for (EmailSendResponse response : responses) { + for (Iterator iterator = responses.iterator(); iterator.hasNext(); ) { + EmailSendResponse response = iterator.next(); if (scenario.equals(response.getEmailScenario().getValue())) { - response.setIsEmailSend(true); + iterator.remove(); // remove only the first match return true; } } @@ -172,6 +173,7 @@ public class EmailDao { + public EmailSendResponse buildEmailSendResponseFromRequest(HttpServletRequest request) { Long userActionId = (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID); List emailLogs = emailLogRepository.findByUserActionIdAndEmailServiceType(userActionId,EmailServiceTypeEnum.PEC_SERVICE.getValue()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java index 234ffa1d..0403fde3 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java @@ -149,17 +149,25 @@ public class UserDao { /** This code is responsible for adding a version history log for the "Create user" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).newData(userEntity).build()); - EmailSendResponse emailSendResponse = new EmailSendResponse(); + List responses = new ArrayList<>(); if(Boolean.FALSE.equals(roleEntity.getRoleType().equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue()))){ sendEmailToOnboardingUser(userEntity, userReq ); boolean isEmailSendSuccess = isEmailSentSuccessfully(userEntity.getId()); - emailSendResponse.setIsEmailSend(isEmailSendSuccess); - Long userActionId =(Long)request.getAttribute(GepafinConstant.USER_ACTION_ID); - emailSendResponse.setUserActionId(userActionId); - emailSendResponse.setEmailScenario(EmailScenarioTypeEnum.USER_CREATION); - saveEmailSendResponseToUser(emailSendResponse,userEntity); + EmailSendResponse emailSendResponse = new EmailSendResponse(); + if (Boolean.FALSE.equals(isEmailSendSuccess)){ + emailSendResponse.setIsEmailSend(false); + Long userActionId =(Long)request.getAttribute(GepafinConstant.USER_ACTION_ID); + emailSendResponse.setUserActionId(userActionId); + emailSendResponse.setEmailScenario(EmailScenarioTypeEnum.USER_CREATION); + + saveEmailSendResponseToUser(emailSendResponse,userEntity); + responses = List.of(emailSendResponse); + } + else{ + responses = Collections.emptyList(); + } } - JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId(),emailSendResponse); + JWTToken token = authService.getJWTTokenBean(userEntity, Boolean.TRUE, loginAttemptEntity.getId(),responses); return token; } @@ -509,8 +517,14 @@ public class UserDao { sendResetPasswordTokenEmail(user, token); InitiatePasswordResetResponse initiatePasswordResetResponse = new InitiatePasswordResetResponse(); EmailSendResponse emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); - initiatePasswordResetResponse.setEmailSendResponse(emailSendResponse); - saveEmailSendResponseToUser(emailSendResponse,user); + List responses = List.of(emailSendResponse); + if (!Boolean.TRUE.equals(emailSendResponse.getIsEmailSend())){ + initiatePasswordResetResponse.setEmailSendResponse(responses); + saveEmailSendResponseToUser(emailSendResponse,user); + } + else{ + initiatePasswordResetResponse.setEmailSendResponse(Collections.emptyList()); + } return initiatePasswordResetResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java b/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java index d02a842d..43409886 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/EmailSendResponseConverter.java @@ -18,6 +18,9 @@ public class EmailSendResponseConverter implements AttributeConverter attribute) { try { + if (attribute == null) { + attribute = List.of(); + } return objectMapper.writeValueAsString(attribute); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Error converting list to JSON", e); diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java index ace60672..c7f1a2eb 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestResponse.java @@ -32,5 +32,5 @@ public class ApplicationAmendmentRequestResponse { private String internalNote; private ApplicationAmendmentRequestEnum status; private String emailTemplate; - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java index 38530c8a..92f7933a 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationFormResponse.java @@ -48,5 +48,6 @@ public class ApplicationEvaluationFormResponse { private Long appointmentTemplateId; private String companyVatNumber; private String companyCodiceAteco; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java index 187aa1dd..49f07c6f 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationEvaluationResponse.java @@ -49,6 +49,6 @@ public class ApplicationEvaluationResponse { private EvaluationVersionEnum evaluationVersion; private String companyVatNumber; private String companyCodiceAteco; - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java index d76b4fcd..25b8a3b3 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/EmailReminderResponse.java @@ -5,12 +5,14 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor public class EmailReminderResponse { @JsonProperty("emailSendResponse") - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java index c14ef643..129a1744 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/InitiatePasswordResetResponse.java @@ -5,9 +5,11 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor public class InitiatePasswordResetResponse { - private EmailSendResponse emailSendResponse; + private List emailSendResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java index a65f7d6e..fdfb3e3a 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java +++ b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java @@ -6,6 +6,8 @@ import lombok.Data; import net.gepafin.tendermanagement.model.response.EmailSendResponse; import net.gepafin.tendermanagement.model.response.LoginResponse; +import java.util.List; + /** * JWTToken */ @@ -18,14 +20,14 @@ public class JWTToken { private LoginResponse loginResponse; @JsonProperty("emailSendResponse") - private EmailSendResponse emailSendResponse; + private List emailSendResponse; public JWTToken(String token, LoginResponse loginResponse) { this.token = token; this.loginResponse = loginResponse; } - public JWTToken(String token, LoginResponse loginResponse, EmailSendResponse emailSendResponse) { + public JWTToken(String token, LoginResponse loginResponse, List emailSendResponse) { this.token = token; this.loginResponse = loginResponse; this.emailSendResponse = emailSendResponse; diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java index 9b4b63ed..b19f77c4 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java @@ -16,7 +16,7 @@ public interface ApplicationAmendmentRequestService { public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(HttpServletRequest request,Long applicationEvaluationId); public ApplicationAmendmentRequestResponse createApplicationAmendmentRequest(HttpServletRequest request, Long applicationEvaluationId , ApplicationAmendmentRequest applicationAmendmentRequest); void deleteApplicationAmendmentRequest(HttpServletRequest request, Long id); - ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(HttpServletRequest request,Long id); + ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(HttpServletRequest request,Long id); List getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId); ApplicationAmendmentRequestResponse updateApplicationAmendment(HttpServletRequest request, Long id, ApplicationAmendmentRequestBean applicationAmendmentRequestBean); ApplicationAmendmentRequestEntity validateApplicationAmendmentRequest(Long applicationAmendmentId); diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java index 67258e9c..86140ac6 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationEvaluationService.java @@ -19,7 +19,7 @@ public interface ApplicationEvaluationService { void deleteApplicationEvaluation(HttpServletRequest request,Long id); - ApplicationEvaluationResponseBean getApplicationEvaluationByApplicationId(HttpServletRequest request,Long applicationId,Long assignedApplicationId); + ApplicationEvaluationResponse getApplicationEvaluationByApplicationId(HttpServletRequest request,Long applicationId,Long assignedApplicationId); ApplicationEvaluationEntity validateApplicationEvaluation(Long applicationEvaluationId); ApplicationEvaluationEntity validateApplicationEvaluationByApplicationId(Long applicationId); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java index 20a1e455..a680ec1b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java @@ -75,7 +75,7 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm } @Override - public ApplicationAmendmentRequestResponseBean getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { + public ApplicationAmendmentRequestResponse getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(id) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java index 570487a8..650acdc1 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationEvaluationServiceImpl.java @@ -57,7 +57,7 @@ public class ApplicationEvaluationServiceImpl implements ApplicationEvaluationSe @Override @Transactional(readOnly = true) - public ApplicationEvaluationResponseBean getApplicationEvaluationByApplicationId( + public ApplicationEvaluationResponse getApplicationEvaluationByApplicationId( HttpServletRequest request, Long applicationId, Long assignedApplicationId) { UserEntity preInstructor = validator.validateUser(request); return applicationEvaluationDao.getApplicationEvaluationByApplicationId( diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java index e112d40e..01ad155b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java @@ -142,7 +142,7 @@ public class AuthenticationService { loginAttemptEntity.setErrorMsg(errorMsg); loginAttemptDao.createLoginAttempt(loginAttemptEntity); } - public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId, EmailSendResponse emailSendResponse) { + public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe, Long loginAttemptId, List emailSendResponse) { UserEntity oldUserEntity = Utils.getClonedEntityForData(user); user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); user = userRepository.save(user); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java index 25b53b3c..5d81ce7e 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationAmendmentRequestApi.java @@ -72,7 +72,7 @@ public interface ApplicationAmendmentRequestApi { @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) @GetMapping(value = "", produces = "application/json") - ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,@Parameter(description = "The application amendment id", required = true) @RequestParam(value = "id", required = true) Long id); + ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,@Parameter(description = "The application amendment id", required = true) @RequestParam(value = "id", required = true) Long id); @Operation(summary = "Api to get all applications amendment request by preInstructor user Id (deprecated)", responses = { diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java index 1b60e9d7..4798e078 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationEvaluationApi.java @@ -44,7 +44,7 @@ public interface ApplicationEvaluationApi { @ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })) }) @GetMapping(value = "/application", produces = MediaType.APPLICATION_JSON_VALUE) - ResponseEntity> getApplicationEvaluationByApplicationId( + ResponseEntity> getApplicationEvaluationByApplicationId( HttpServletRequest request, @Parameter(required = false) @RequestParam(value = "applicationId", required = false) Long applicationId, @Parameter( required = false) @RequestParam(value = "assignedApplicationId", required = false) Long assignedApplicationId); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java index 739c2802..0c8ef489 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationAmendmentRequestController.java @@ -69,14 +69,14 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme } @Override - public ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { + public ResponseEntity> getApplicationAmendmentRequestById(HttpServletRequest request,Long id) { log.info("Get Application Amendment Request By Id"); /** This code is responsible for creating user action logs for the "get application amendment by id" operation. **/ loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW) .actionContext(UserActionContextEnum.GET_AMENDMENT).build()); - ApplicationAmendmentRequestResponseBean applicationAmendmentRequestResponse = applicationAmendmentRequestService.getApplicationAmendmentRequestById(request,id); + ApplicationAmendmentRequestResponse applicationAmendmentRequestResponse = applicationAmendmentRequestService.getApplicationAmendmentRequestById(request,id); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(applicationAmendmentRequestResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_APPLICATION_AMENDMENT_SUCCESS_MSG))); } @@ -185,11 +185,6 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme EmailReminderResponse emailSendResponse = applicationAmendmentRequestService.sendReminderEmail(request,amendmentId); - if (!emailSendResponse.getEmailSendResponse().getIsEmailSend()) { - return ResponseEntity.status(HttpStatus.OK) - .body(new Response<>(emailSendResponse, Status.EXCEPTION_ERROR, Translator.toLocale(GepafinConstant.REMINDER_EMAIL_FAILED_MSG))); - } - return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(emailSendResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.REMINDER_EMAIL_SENT_SUCCESS_MSG))); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java index 85486435..50eadb36 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationEvaluationApiController.java @@ -51,7 +51,7 @@ public class ApplicationEvaluationApiController implements ApplicationEvaluation @Override - public ResponseEntity> getApplicationEvaluationByApplicationId( + public ResponseEntity> getApplicationEvaluationByApplicationId( HttpServletRequest request, Long applicationId, Long assignedApplicationId) { @@ -59,7 +59,7 @@ public class ApplicationEvaluationApiController implements ApplicationEvaluation loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_APPLICATION_EVALUATION).build()); - ApplicationEvaluationResponseBean response = null; + ApplicationEvaluationResponse response = null; response = applicationEvaluationService.getApplicationEvaluationByApplicationId(request, applicationId,assignedApplicationId); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(response, Status.SUCCESS, Translator.toLocale(GepafinConstant.EVALUATION_FETCHED_SUCCESSFULLY))); From ad4e5483b44382d6634fb71a80a05f6d5863ec7d Mon Sep 17 00:00:00 2001 From: nisha Date: Tue, 20 May 2025 18:35:41 +0530 Subject: [PATCH 54/63] Add notification scenario check for Beneficiary role --- .../dao/ApplicationEvaluationDao.java | 12 ++++++++++-- .../gepafin/tendermanagement/dao/AppointmentDao.java | 11 +++++++++-- .../scheduler/ApplicationEvaluationScheduler.java | 6 +++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index d7a03f62..b26a8a2a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -704,7 +704,11 @@ public class ApplicationEvaluationDao { /** 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()); - Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_CREATION); +// Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_CREATION); + + Map 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.sendNotificationToInstructor(placeHolders,entity,NotificationTypeEnum.EVALUATION_CREATION); @@ -1943,6 +1947,7 @@ public class ApplicationEvaluationDao { application.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); application = applicationRepository.save(application); // emailNotificationDao.sendAdmissibilityNotificationEmailForApprovedApplication(application); + notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); } if (Boolean.TRUE.equals(statusType.equals((ApplicationStatusTypeEnum.REJECTED.getValue())))) { application.setDateRejected(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); @@ -1951,9 +1956,12 @@ public class ApplicationEvaluationDao { emailNotificationDao.sendInadmissibilityEmailForRejectedApplication(application,existingEntity); emailSendResponse = emailDao.buildEmailSendResponseFromRequest(request); saveEmailSendResponseToEvaluation(emailSendResponse,existingEntity); + notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); } - Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_RESULT); + Map 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.sendNotificationToInstructor(placeHolders,existingEntity,NotificationTypeEnum.EVALUATION_RESULT); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index cb83406e..d83cb36e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -343,7 +343,11 @@ public class AppointmentDao { applicationRepository.save(application); companyRepository.save(company); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); - Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); +// Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); + + Map 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.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.NDG_GENERATION); log.info("NDG saved successfully for applicationId: {}", application.getId()); @@ -393,7 +397,10 @@ public class AppointmentDao { companyRepository.save(company); applicationRepository.save(application); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); - Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); +// Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.NDG_GENERATION); + Map 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.sendNotificationToSuperUser(application,placeHolders,NotificationTypeEnum.NDG_GENERATION); log.info("NDG saved for applicationId: {}, {}", application.getId(), application.getNdg()); diff --git a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java index c43aca10..af4cb6be 100644 --- a/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java +++ b/src/main/java/net/gepafin/tendermanagement/scheduler/ApplicationEvaluationScheduler.java @@ -24,6 +24,7 @@ import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.LocalTime; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -87,7 +88,10 @@ public class ApplicationEvaluationScheduler { evaluation.setStatus(ApplicationEvaluationStatusTypeEnum.EXPIRED.getValue()); evaluation = applicationEvaluationRepository.save(evaluation); - Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_EXPIRED); +// Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.EVALUATION_EXPIRED); + Map 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.sendNotificationToInstructor(placeHolders,evaluation,NotificationTypeEnum.EVALUATION_EXPIRED); notificationDao.sendNotificationToInstructorManager(placeHolders,evaluation,NotificationTypeEnum.EVALUATION_EXPIRED); From 81ee85c6f536fef55e008df2f9ecbe3fd69b0490 Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 21 May 2025 14:21:16 +0530 Subject: [PATCH 55/63] updated code --- .../net/gepafin/tendermanagement/dao/AppointmentDao.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index ce99d828..b1166689 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -62,11 +62,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; From 6df1cf4ea2f1055db7ac572a6d79f84cab42a063 Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 21 May 2025 16:18:09 +0530 Subject: [PATCH 56/63] Added created date and updated date in changeset --- src/main/resources/db/changelog/db.changelog-1.0.0.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 0b4e6cc7..76bfc067 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2653,6 +2653,8 @@ + + @@ -2666,12 +2668,16 @@ + + + + From 62274dcbd35c423610ad19061ed9724c1eed2593 Mon Sep 17 00:00:00 2001 From: rajesh Date: Fri, 23 May 2025 15:17:07 +0530 Subject: [PATCH 57/63] Added APOINTMENT status to update application status API --- .../tendermanagement/dao/ApplicationDao.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index f4656197..3a80c27d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -208,6 +208,7 @@ public class ApplicationDao { @Autowired private ApplicationEvaluationDao applicationEvaluationDao; + public final Random random = new Random(); public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) { FormEntity formEntity = formService.validateForm(formId); @@ -934,12 +935,16 @@ public class ApplicationDao { } } + public String generateRandomFiveDigitNumber() { + int number = 10000 + random.nextInt(90000); // Generates a number from 10000 to 99999 + return String.valueOf(number); + } public ApplicationResponse updateApplicationStatus(HttpServletRequest request, Long applicationId, ApplicationStatusTypeEnum status) { log.info("Updating status for Application id : " + applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); - checkCallEndDate(applicationEntity.getCall()); + log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); //cloned entity for old application data ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(applicationEntity); @@ -953,8 +958,16 @@ public class ApplicationDao { if (Boolean.TRUE.equals(applicationEntity.getStatus().equals(status.getValue()))) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_IN_PREVIOUS_STATUS)); } + + if (status.equals(ApplicationStatusTypeEnum.APPOINTMENT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.NDG.getValue()))){ + String appointmentId = generateRandomFiveDigitNumber(); + applicationEntity.setAppointmentId(appointmentId); + applicationEntity.setStatus(ApplicationStatusTypeEnum.APPOINTMENT.getValue()); + } + if (status.equals(ApplicationStatusTypeEnum.SUBMIT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.READY.getValue()))) { // callService.validatePublishedCall(applicationEntity.getCall().getId(), userEntity.getHub().getId()); + checkCallEndDate(applicationEntity.getCall()); Long protocolNumber = protocolDao.getProtocolNumber(userEntity.getHub()); ProtocolEntity protocolEntity = protocolDao.createProtocolEntity(applicationEntity, protocolNumber, userEntity.getHub().getId(),true); applicationEntity.setProtocol(protocolEntity); @@ -974,10 +987,12 @@ public class ApplicationDao { log.info("Status updated to SUBMIT for applicationId: " + applicationId); } if (status.equals(ApplicationStatusTypeEnum.DRAFT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.AWAITING.getValue()))) { + checkCallEndDate(applicationEntity.getCall()); applicationEntity.setStatus(status.getValue()); log.info("Status updated to DRAFT for applicationId: " + applicationId); } if (status.equals(ApplicationStatusTypeEnum.AWAITING) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.READY.getValue()))) { + checkCallEndDate(applicationEntity.getCall()); ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository.findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); deleteSignedDocumentFromS3(applicationSignedDocument); From 4e34486581b2be825023f4590cd9eb3357525df1 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 26 May 2025 12:46:18 +0530 Subject: [PATCH 58/63] Fixed close amendment issue --- .../dao/ApplicationAmendmentRequestDao.java | 10 +++++++++- .../ApplicationAmendmentRequestRepository.java | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 76ce5d3d..02a92762 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -1050,7 +1050,7 @@ public class ApplicationAmendmentRequestDao { public ApplicationAmendmentRequestResponse closeAmendmentRequest(Long id, CloseAmendmentRequest closeAmendmentRequest) { log.info("Closing application amendement with ID: {}", id); - ApplicationAmendmentRequestEntity existingApplicationAmendment = validatApplicationAmendmentRequestByStatus(id,ApplicationAmendmentRequestEnum.AWAITING.getValue()); + ApplicationAmendmentRequestEntity existingApplicationAmendment = validatApplicationAmendmentRequestByListStatus(id,List.of(ApplicationAmendmentRequestEnum.AWAITING.getValue(),ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue())); //cloned entity for old data and versioning ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); List amendmentRequestList = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( @@ -1670,4 +1670,12 @@ public class ApplicationAmendmentRequestDao { amendment.setEmailSendResponse(mergedResponses); applicationAmendmentRequestRepository.save(amendment); } + public ApplicationAmendmentRequestEntity validatApplicationAmendmentRequestByListStatus(Long id,List status) { + ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalseAndStatusIn(id, status); + if (applicationAmendmentRequestEntity == null) { + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)); + } + return applicationAmendmentRequestEntity; + } } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java index 4cd6d413..d063eb37 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java @@ -152,4 +152,6 @@ public interface ApplicationAmendmentRequestRepository extends JpaRepository applicationIds, @Param("statuses") List statuses); ApplicationAmendmentRequestEntity findByIdAndIsDeletedFalseAndStatus(Long id,String status); + + ApplicationAmendmentRequestEntity findByIdAndIsDeletedFalseAndStatusIn(Long id, List statusList); } From 1123faa710f397b6eb210bb00ee867910ba2a8c4 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 26 May 2025 17:17:41 +0530 Subject: [PATCH 59/63] Done ticket GEPAFINBE-219 --- .../constants/GepafinConstant.java | 22 ++ .../dao/ApplicationAmendmentRequestDao.java | 1 + .../tendermanagement/dao/ApplicationDao.java | 25 +- .../tendermanagement/dao/CompanyDao.java | 71 +++++- .../tendermanagement/dao/ProtocolDao.java | 219 +++++++++++++++++- .../ApplicationSignedDocumentEntity.java | 2 + .../entities/CompanyEntity.java | 6 +- .../entities/ProtocolEntity.java | 11 + .../ApplicationSignedDocumentResponse.java | 1 + .../service/feignClient/ProtocolService.java | 32 +++ .../tendermanagement/util/DateTimeUtil.java | 16 +- .../tendermanagement/util/FileHashUtil.java | 40 ++++ .../gepafin/tendermanagement/util/Utils.java | 9 + src/main/resources/application.properties | 17 +- .../db/changelog/db.changelog-1.0.0.xml | 18 ++ 15 files changed, 467 insertions(+), 23 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java create mode 100644 src/main/java/net/gepafin/tendermanagement/util/FileHashUtil.java diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index f9fbe5d6..1fe74e81 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -549,6 +549,28 @@ public class GepafinConstant { public static final String CAUSE_STRING = "cause" ; public static final String ERROR_DESCRIPTION_STRING = "errorDescription" ; public static final String ERROR_STRING = "errors"; + public static final String PROTOCOL_SERVICE_URL="http://65.108.55.96:8080"; + public static final String PROTOCOL_SERVICE_BEARER_TOKEN="/auth/login"; + public static final String PROTOCOL_SERVICE_CREATE_PROTOCOL="/documenti/protocollaUD"; + public static final String PROTOCOL_CALL_NAME="BANDO"; + public static final String PROTOCOL_DOC_URL="DOC_URL"; + public static final String PROTOCOL_COMPANY_NAME_VAT_NUMBER="OGGETTO_PG"; + public static final String PROTOCOL_DOC_HASH="URL_CONTENT_HASH"; + public static final String PROTOCOL_TIPO_PROTOCOLLAZIONE="TIPO_PROTOCOLLAZIONE"; + public static final String PROTOCOL_TIPO_CORRISPONDENTE_COMPANY="tipoCorrispondente"; + public static final String PROTOCOL_COMPANY_NAME="denominazione"; + public static final String PROTOCOL_MEZZO="mezzo"; + public static final String PROTOCOL_INDIRIZZO_PEC="indirizzoPec"; + public static final String PROTOCOL_COMPANY_VAT_NUMBER="identificativo"; + public static final String PROTOCOL_CODICE_UO="codiceUo"; + public static final String PROTOCOL_COMPETENTE="competente"; + public static final String PROTOCOL_TIPO_CORRISPONDENTE="tipoCorrispondente"; + public static final String PROTOCOL_MITTENTE="mittente"; + public static final String PROTOCOL_DESTINATARI="destinatari"; + public static final String PROTOCOL_EXTERNAL_YEAR="ANNO_PG"; + public static final String PROTOCOL_EXTERNAL_NUMBER=""; + public static final String PROTOCOL_EXTERNAL_DATE=""; + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 156bab88..04e6f17b 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -369,6 +369,7 @@ public class ApplicationAmendmentRequestDao { ProtocolEntity protocolEntity = protocolDao.createProtocolEntity( applicationEvaluationEntity.getAssignedApplicationsEntity().getApplication(), protocolNumber, userEntity.getHub().getId(),false); + protocolDao.saveProtocolEntity(protocolEntity); applicationAmendmentRequestEntity.setProtocol(protocolEntity); ApplicationAmendmentRequestEntity applicationAmendment = saveApplicationAmendmentRequestEntity(applicationAmendmentRequestEntity, null, VersionActionTypeEnum.INSERT); String evaluationStatusType = applicationEvaluationEntity.getStatus(); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 9648b749..296d42d1 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -136,6 +136,9 @@ public class ApplicationDao { @Value("${call.id}") private String callId; + @Value("${sviluppumbriaUuid}") + private String sviluppumbriaUuid; + @Autowired private AmazonS3Service amazonS3Service; @@ -943,7 +946,7 @@ public class ApplicationDao { log.info("Call end date verified successfully | callId: {}", applicationEntity.getCall().getId()); //cloned entity for old application data ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(applicationEntity); - + HubEntity hub=hubService.valdateHub(applicationEntity.getHubId()); UserEntity userEntity = userService.validateUser(applicationEntity.getUserId()); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); if (ApplicationStatusTypeEnum.SUBMIT.getValue().equals(applicationEntity.getStatus())) { @@ -954,10 +957,15 @@ public class ApplicationDao { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_IN_PREVIOUS_STATUS)); } if (status.equals(ApplicationStatusTypeEnum.SUBMIT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.READY.getValue()))) { -// callService.validatePublishedCall(applicationEntity.getCall().getId(), userEntity.getHub().getId()); + CompanyEntity company=companyService.validateCompany(applicationEntity.getCompanyId()); + Long protocolNumber = protocolDao.getProtocolNumber(userEntity.getHub()); ProtocolEntity protocolEntity = protocolDao.createProtocolEntity(applicationEntity, protocolNumber, userEntity.getHub().getId(),true); + protocolDao.saveProtocolEntity(protocolEntity); applicationEntity.setProtocol(protocolEntity); + if(Boolean.TRUE.equals(hub.getUniqueUuid().equals(sviluppumbriaUuid))) { + protocolEntity = protocolDao.createExternalProtocol(applicationEntity, company, protocolEntity); + } applicationEntity.setStatus(ApplicationStatusTypeEnum.SUBMIT.getValue()); applicationEntity.setSubmissionDate(protocolEntity.getCreatedDate()); applicationEntity = applicationRepository.save(applicationEntity); @@ -968,7 +976,7 @@ public class ApplicationDao { loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEntity).newData(applicationEntity).build()); - sendMailToUserAndCompany(userEntity, applicationEntity); + sendMailToUserAndCompany(userEntity, applicationEntity,company); sendMailTodefaultSystemAndGepafin(userEntity, applicationEntity); applicationEntity.setStatus(status.getValue()); log.info("Status updated to SUBMIT for applicationId: " + applicationId); @@ -1079,9 +1087,8 @@ public class ApplicationDao { } } - private void sendMailToUserAndCompany(UserEntity userEntity, ApplicationEntity applicationEntity) { + private void sendMailToUserAndCompany(UserEntity userEntity, ApplicationEntity applicationEntity,CompanyEntity company) { CallEntity call =applicationEntity.getCall(); - CompanyEntity company=companyService.validateCompany(applicationEntity.getCompanyId()); UserWithCompanyEntity userWithCompany=companyService.getUserWithCompany(userEntity.getId(),company.getId()); ProtocolEntity protocol= applicationEntity.getProtocol(); HubEntity hub = hubService.valdateHub(applicationEntity.getHubId()); @@ -1184,12 +1191,19 @@ public class ApplicationDao { if (applicationSignedDocument != null) { deleteSignedDocumentFromS3(applicationSignedDocument); } + String hash =""; + try { + hash = FileHashUtil.calculateSHA256(file.getInputStream()); + } catch (IOException e) { + throw new RuntimeException(e); + } UploadFileOnAmazonS3Response uploadFileOnAmazonS3 = uploadFileOnAmazonS3ForUserSignedDocument(file, applicationEntity.getCall().getId(), applicationId); applicationSignedDocument = new ApplicationSignedDocumentEntity(); applicationSignedDocument.setApplication(applicationEntity); applicationSignedDocument.setFileName(uploadFileOnAmazonS3.getFileName()); applicationSignedDocument.setFilePath(uploadFileOnAmazonS3.getFilePath()); applicationSignedDocument.setStatus(ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); + applicationSignedDocument.setFileHash(hash); applicationSignedDocument = applicationSignedDocumentRepository.save(applicationSignedDocument); /** This code is responsible for adding a version history log for the "assign application document" operation. **/ @@ -1255,6 +1269,7 @@ public class ApplicationDao { .setStatus(ApplicationSignedDocumentStatusEnum.valueOf(applicationSignedDocument.getStatus())); applicationSignedDocumentResponse.setCreatedDate(applicationSignedDocument.getCreatedDate()); applicationSignedDocumentResponse.setUpdatedDate(applicationSignedDocument.getUpdatedDate()); + applicationSignedDocumentResponse.setFileHash(applicationSignedDocument.getFileHash()); return applicationSignedDocumentResponse; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 91a589e7..f5cd0fd8 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -52,13 +52,13 @@ public class CompanyDao { private ApplicationRepository applicationRepository; @Autowired private FaqRepository faqRepository; - + @Autowired private BeneficiaryPreferredCallRepository beneficiaryPreferredCallRepository; @Autowired private UserCompanyDelegationRepository userCompanyDelegationRepository; - + @Autowired private CompanyService companyService; @@ -103,7 +103,7 @@ public class CompanyDao { private void validateCompany(UserEntity userEntity, CompanyRequest companyRequest) { - + if (Boolean.FALSE.equals(StringUtils.isEmpty(companyRequest.getEmail())) && Boolean.FALSE.equals(Utils.isValidEmail(companyRequest.getEmail()))) { throw new CustomValidationException(Status.VALIDATION_ERROR, @@ -169,7 +169,7 @@ public class CompanyDao { entity.setHub(userEntity.getHub()); entity.setJson(Utils.convertMapIntoJsonString(request.getVatCheckResponse())); updateCodiceAtecoFieldWithNewJson(entity); - + return entity; } @@ -483,12 +483,19 @@ public class CompanyDao { return; } + + Object pecEmailObj = dettaglio.get("pec"); + if (pecEmailObj instanceof String pec && !pec.isEmpty()) { + company.setPec(pec); // Only set if valid string + } else { + log.warn("Company ID {}: 'pec' is missing, empty, or not a string.", company.getId()); + } + Object codiceAtecoObj = dettaglio.get("codice_ateco"); if (!(codiceAtecoObj instanceof String codiceAteco) || codiceAteco.isEmpty()) { log.warn("Company ID {}: 'codice_ateco' is missing, empty, or not a string.", company.getId()); return; } - company.setCodiceAteco(codiceAteco); logCodiceAtecoUpdate(company, codiceAteco); } @@ -517,6 +524,13 @@ public class CompanyDao { // if data is a single object updateCodiceAtecoField(company); } else { + + Object pecEmail = Utils.extractMap(dataMap, "pec"); + if (pecEmail == null) { + log.warn("Company ID {}: 'pec' section is missing or invalid.", company.getId()); + company.setPec((String) pecEmail); + } + // Extract 'atecoClassification' section Map atecoClassificationMap = Utils.extractMap(dataMap, "atecoClassification"); if (atecoClassificationMap == null) { @@ -546,4 +560,51 @@ public class CompanyDao { log.info("Company ID {}: codiceAteco updated to {}", company.getId(), atecoCode); } + + public void getCompanyEntity() { + List companyEntities=companyRepository.findAll(); + for (CompanyEntity company:companyEntities){ + if(company.getJson()!=null){ + if (company == null || company.getJson() == null || company.getJson().isEmpty()) { + log.warn("Company is null or JSON data is empty."); + return; + } + Map vatCheckResponse = Utils.convertJsonStringToMap(company.getJson()); + + if (vatCheckResponse == null) { + log.warn("Company ID {}: Invalid JSON response.", company.getId()); + return; + } + Map companyDataMap = Utils.convertJsonStringToMap(company.getJson()); + if (companyDataMap == null) { + log.warn("Company ID {}: Failed to parse JSON data.", company.getId()); + return; + } + + Object dataObj = vatCheckResponse.get("data"); + if (!(dataObj instanceof Map dataMap)) { + log.warn("Company ID {}: 'data' is missing or not a valid object.", company.getId()); + return; + } + + if (!dataMap.containsKey("dettaglio")) { + log.warn("Company ID {}: 'dettaglio' not present inside 'data'. Skipping codiceAteco update.", company.getId()); + return; + } + + Object dettaglioObj = dataMap.get("dettaglio"); + if (!(dettaglioObj instanceof Map dettaglio)) { + log.warn("Company ID {}: 'dettaglio' is not a valid object.", company.getId()); + return; + } + + Object pecEmailObj = dettaglio.get("pec"); + if (pecEmailObj instanceof String pec && !pec.isEmpty()) { + company.setPec(pec); // Only set if valid string + } else { + log.warn("Company ID {}: 'pec' is missing, empty, or not a string.", company.getId()); + } + } + } + } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java index b70bc588..0a337062 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java @@ -1,20 +1,36 @@ package net.gepafin.tendermanagement.dao; +import java.net.URI; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import feign.FeignException; import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.entities.*; +import net.gepafin.tendermanagement.enums.ApplicationSignedDocumentStatusEnum; import net.gepafin.tendermanagement.enums.ProtocolTypeEnum; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; +import net.gepafin.tendermanagement.repositories.ApplicationSignedDocumentRepository; +import net.gepafin.tendermanagement.service.feignClient.ProtocolService; import net.gepafin.tendermanagement.util.LoggingUtil; +import net.gepafin.tendermanagement.util.Utils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import net.gepafin.tendermanagement.entities.ApplicationEntity; -import net.gepafin.tendermanagement.entities.HubEntity; -import net.gepafin.tendermanagement.entities.ProtocolEntity; import net.gepafin.tendermanagement.repositories.ProtocolRepository; import net.gepafin.tendermanagement.util.DateTimeUtil; @@ -33,6 +49,50 @@ public class ProtocolDao { @Autowired private HttpServletRequest request; + + @Autowired + private ProtocolService protocolService; + + @Value("${codAoo}") + private String codAoo; + + @Value("${sviluppumbria.username}") + private String username; + + @Value("${password}") + private String password; + + @Value("${CLASSIFICA}") + private String classifica; + + @Value("${TIPO_PROTOCOLLAZIONE}") + private String TIPO_PROTOCOLLAZIONE; + + @Value("${tipoCorrispondenteCompany}") + private String tipoCorrispondenteCompany; + + @Value("${tipoCorrispondenteWithoutCompany}") + private String tipoCorrispondenteWithoutCompany; + + @Value("${mezzo}") + private String mezzo; + + @Value("${indirizzoPec}") + private String indirizzoPec; + + @Value("${codiceUo}") + private String codiceUo; + + @Value("${competente}") + private Boolean competente; + + @Value("${tipoCorrispondente}") + private String tipoCorrispondente; + + @Autowired + private ApplicationSignedDocumentRepository applicationSignedDocumentRepository; + + public final Logger log = LoggerFactory.getLogger(ProtocolDao.class); public Long getProtocolNumber(HubEntity hubEntity) { Long maxProtocolNumber = protocolRepository.findMaxProtocolNumberAndHubId(hubEntity.getId()); @@ -58,11 +118,160 @@ public class ProtocolDao { }else { protocolEntity.setType(ProtocolTypeEnum.OUTPUT.getValue()); } + + return protocolEntity; + } + + public void saveProtocolEntity(ProtocolEntity protocolEntity) { protocolRepository.save(protocolEntity); /** This code is responsible for adding a version history log for "create protocol" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(protocolEntity).build()); - - return protocolEntity; } + + public String getBearerToken(String codAoo, String username, String password) { + log.info("Requesting bearer token for user: {} and codAoo: {}", username, codAoo); + + HttpHeaders httpHeaders = Utils.getHeaders(); + URI url = URI.create(GepafinConstant.PROTOCOL_SERVICE_BEARER_TOKEN); + + try { + ResponseEntity response = protocolService.getBearerToken(httpHeaders, codAoo,username,password); + + if (response != null && response.getStatusCode().is2xxSuccessful()) { + log.debug("Bearer token successfully retrieved. HTTP Status: {}", response.getStatusCode()); + return response.getBody().toString(); // Use getBody() instead of toString() + } else { + log.warn("Bearer token request failed or returned unexpected status. Response: {}", response); + } + } catch (FeignException ex) { + log.error("FeignException while retrieving bearer token for user {}: {}", username, ex.getMessage(), ex); + Utils.callException(ex.status(), ex); + } catch (Exception ex) { + log.error("Unexpected exception while retrieving bearer token: {}", ex.getMessage(), ex); + } + + log.warn("Returning null bearer token for user: {}", username); + return null; + } + + public ProtocolEntity createExternalProtocol(ApplicationEntity application, CompanyEntity company, ProtocolEntity protocol) { + log.info("Starting createExternalProtocol for application ID: {}", application.getId()); + + log.debug("Successfully retrieved bearer token"); + ApplicationSignedDocumentEntity applicationSignedDocumentEntity=applicationSignedDocumentRepository.findByApplicationIdAndStatus(application.getId(), ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); + + String year = String.valueOf(LocalDateTime.now().getYear()); + String applicationId = String.valueOf(application.getId()); + String mittenteValue=""; + String vatNumber =""; + if(company!=null) { + mittenteValue= tipoCorrispondenteCompany; + vatNumber=company.getVatNumber(); + }else { + mittenteValue = tipoCorrispondenteWithoutCompany; + vatNumber = company.getCodiceFiscale(); + } + mittenteValue=tipoCorrispondenteWithoutCompany; + String companyName = company.getCompanyName() + " " + vatNumber; + String callName = application.getCall().getName(); + String callId = GepafinConstant.PROTOCOL_CALL_NAME+ String.valueOf(application.getCall().getId()); + String pecEmail=company.getPec(); + String docUrl=applicationSignedDocumentEntity.getFilePath(); + + + Map requestBody = new HashMap<>(); + requestBody.put(GepafinConstant.PROTOCOL_DOC_URL,docUrl); + requestBody.put(GepafinConstant.PROTOCOL_COMPANY_NAME,companyName); + requestBody.put(GepafinConstant.PROTOCOL_DOC_HASH,applicationSignedDocumentEntity.getFileHash()); + requestBody.put(GepafinConstant.PROTOCOL_TIPO_PROTOCOLLAZIONE,TIPO_PROTOCOLLAZIONE); + Map mittente = new HashMap<>(); + mittente.put(GepafinConstant.PROTOCOL_TIPO_CORRISPONDENTE_COMPANY, mittenteValue); + mittente.put(GepafinConstant.PROTOCOL_COMPANY_NAME_VAT_NUMBER,company.getCompanyName()); + mittente.put(GepafinConstant.PROTOCOL_MEZZO,mezzo); + mittente.put(GepafinConstant.PROTOCOL_INDIRIZZO_PEC,pecEmail); + mittente.put(GepafinConstant.PROTOCOL_COMPANY_VAT_NUMBER,vatNumber); + List> destinatariObject=new ArrayList<>(); + Map destinatari = new HashMap<>(); + destinatari.put(GepafinConstant.PROTOCOL_CODICE_UO,codiceUo); + destinatari.put(GepafinConstant.PROTOCOL_COMPETENTE,competente); + destinatari.put(GepafinConstant.PROTOCOL_TIPO_CORRISPONDENTE,tipoCorrispondente); + requestBody.put(GepafinConstant.PROTOCOL_MITTENTE,mittente); + destinatariObject.add(destinatari); + requestBody.put(GepafinConstant.PROTOCOL_DESTINATARI,destinatariObject); + List> listObject=new ArrayList<>(); + listObject.add(requestBody); + + log.info("Preparing to create protocol with data: year={}, applicationId={}, companyName={}, callName={}, callId={}", + year, applicationId, companyName, callName, callId); + ResponseEntity response=null; + try { + + String bearerToken = getBearerToken(codAoo, username, password); + if (bearerToken == null) { + log.error("Bearer token retrieval failed for user: {}", username); + return protocol; + } + HttpHeaders httpHeaders = Utils.getHeaders(); + httpHeaders.set(GepafinConstant.AUTHORIZATION, "Bearer " + bearerToken); + URI url = URI.create(GepafinConstant.PROTOCOL_SERVICE_CREATE_PROTOCOL); + + response = protocolService.createProtocol(httpHeaders, classifica, year, applicationId, companyName, callName, callId,listObject + ); + + log.info("Protocol creation response: status={}, body={}", response.getStatusCode(), response.getBody()); + + } catch (FeignException ex) { + log.error("FeignException during protocol creation for application ID {}: {}", applicationId, ex.getMessage(), ex); +// Utils.callException(ex.status(), ex); + } catch (Exception ex) { + log.error("Unexpected exception during protocol creation for application ID {}: {}", applicationId, ex.getMessage(), ex); + } + + log.info("Finished createExternalProtocol for application ID: {}", application.getId()); + if(response!=null && response.getBody()!=null) { + protocol = extractDetailForProtocol((List>) response.getBody(), protocol); + } + return protocol; + } + + public ProtocolEntity extractDetailForProtocol(List> responseObject, ProtocolEntity protocol) { + Map responseField= responseObject.get(0); + Object yearObj = responseField.get(GepafinConstant.PROTOCOL_EXTERNAL_YEAR); + Integer externalProtocolYear = null; + if (yearObj instanceof Integer) { + externalProtocolYear = (Integer) yearObj; + } else if (yearObj instanceof String) { + try { + externalProtocolYear = Integer.parseInt((String) yearObj); + } catch (NumberFormatException e) { + // handle invalid format gracefully + externalProtocolYear = null; + } + } + + Object dateObj = responseField.get(GepafinConstant.PROTOCOL_EXTERNAL_DATE); + LocalDateTime externalProtocolDate = null; + + if (dateObj instanceof LocalDateTime) { + externalProtocolDate = (LocalDateTime) dateObj; + } else if (dateObj instanceof String) { + externalProtocolDate = DateTimeUtil.parseStringToLocalDateTime((String) dateObj); + } + if(externalProtocolDate!=null){ + protocol.setExternalProtocolDate(externalProtocolDate); + } + if (externalProtocolYear!=null){ + protocol.setExternalProtocolYear(externalProtocolYear); + + } + + String externalProtocolNumber = (String) responseField.get(GepafinConstant.PROTOCOL_EXTERNAL_NUMBER); + if (Boolean.FALSE.equals(StringUtils.isEmpty(externalProtocolNumber))) { + protocol.setExternalProtocolNumber(externalProtocolNumber); + } + protocolRepository.save(protocol); + return protocol; + } + } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java index 58975cca..9a90af52 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java @@ -25,4 +25,6 @@ public class ApplicationSignedDocumentEntity extends BaseEntity { @Column(name="STATUS") private String status; + @Column(name="FILE_HASH") + private String fileHash; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java index 12dc2a15..88658077 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/CompanyEntity.java @@ -51,9 +51,6 @@ public class CompanyEntity extends BaseEntity{ @JoinColumn(name = "HUB_ID") private HubEntity hub; -// @Column(name = "JSON") -// private String json; - @Column(name = "NDG") private String ndg; @@ -62,4 +59,7 @@ public class CompanyEntity extends BaseEntity{ @Column(name = "JSON") private String json; + + @Column(name = "PEC") + private String pec; } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ProtocolEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ProtocolEntity.java index 69303b41..e807304a 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ProtocolEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ProtocolEntity.java @@ -4,6 +4,7 @@ import jakarta.persistence.*; import lombok.Data; import net.gepafin.tendermanagement.config.LocalTimeAttributeConverter; +import java.time.LocalDateTime; import java.time.LocalTime; @Entity @@ -33,4 +34,14 @@ public class ProtocolEntity extends BaseEntity { @Column(name = "type") private String type; + @Column(name = "external_protocol_year") + private Integer externalProtocolYear; + + @Column(name = "external_protocol_date") + private LocalDateTime externalProtocolDate; + + @Column(name = "external_protocol_number") + private String externalProtocolNumber; + + } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java index 64b380f5..249ed7f8 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java @@ -11,4 +11,5 @@ public class ApplicationSignedDocumentResponse extends BaseBean{ private String fileName; private String filePath; private ApplicationSignedDocumentStatusEnum status; + private String fileHash; } diff --git a/src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java b/src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java new file mode 100644 index 00000000..625c116b --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java @@ -0,0 +1,32 @@ +package net.gepafin.tendermanagement.service.feignClient; + +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import net.gepafin.tendermanagement.constants.GepafinConstant; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +import java.net.URI; +import java.util.List; +import java.util.Map; + +@FeignClient(value = "protocol-service" ,url = GepafinConstant.PROTOCOL_SERVICE_URL) +public interface ProtocolService { + + @PostMapping(GepafinConstant.PROTOCOL_SERVICE_BEARER_TOKEN) + ResponseEntity getBearerToken(@RequestHeader HttpHeaders headers,@RequestParam("codAoo") String codAoo,@RequestParam("username") String username,@RequestParam("password") String password + ); + + @PutMapping(GepafinConstant.PROTOCOL_SERVICE_CREATE_PROTOCOL) + ResponseEntity createProtocol(@RequestHeader HttpHeaders headers, @RequestParam("CLASSIFICA") String classifica, @RequestParam("ANNO_FASCICOLO") String year, @RequestParam("PROGR_FASCICOLO") String applicationId, + @RequestParam("DES_FASCICOLO") String companyName, @RequestParam("PARENT_PROGR_FASCICOLO") String callName, @RequestParam("PARENT_DES_FASCICOLO") String callId, @RequestBody List> requestBody + + + ); + +} diff --git a/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java b/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java index bafd5d6d..e9bfe870 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java +++ b/src/main/java/net/gepafin/tendermanagement/util/DateTimeUtil.java @@ -98,11 +98,19 @@ public class DateTimeUtil { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); return LocalDateTime.parse(dateTimeStr, formatter); } - public static LocalDateTime parseStringToLocalDateTime(String timestampStr) { - // Use ISO_LOCAL_DATE_TIME to parse the input string - return LocalDateTime.parse(timestampStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME); + public static LocalDateTime parseStringToLocalDateTime(String dateStr) { + if (dateStr == null || dateStr.isEmpty()) return null; + + try { + return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } catch (Exception e) { + try { + return LocalDateTime.parse(dateStr, DateTimeFormatter.ISO_DATE_TIME); // fallback + } catch (Exception ignored) { + } + } + return null; } - public static String parseLocalTimeToString(LocalTime time, String format) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); return time.format(formatter); diff --git a/src/main/java/net/gepafin/tendermanagement/util/FileHashUtil.java b/src/main/java/net/gepafin/tendermanagement/util/FileHashUtil.java new file mode 100644 index 00000000..5e9542a3 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/util/FileHashUtil.java @@ -0,0 +1,40 @@ +package net.gepafin.tendermanagement.util; + +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.InputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; + +@Component +public class FileHashUtil { + + public static String calculateSHA256(InputStream inputStream) throws IOException { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + try (DigestInputStream dis = new DigestInputStream(inputStream, md)) { + byte[] buffer = new byte[8192]; + while (dis.read(buffer) != -1) { + // reading to compute hash + } + } + + byte[] digest = md.digest(); + return bytesToHex(digest); + } catch (Exception e) { + throw new RuntimeException("Could not generate hash", e); + } + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder hexString = new StringBuilder(); + for (byte b : bytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index c14b25d9..469d93ba 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -48,6 +48,7 @@ import net.objecthunter.exp4j.ExpressionBuilder; import org.apache.commons.collections4.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import com.fasterxml.jackson.core.JsonProcessingException; @@ -60,6 +61,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import feign.FeignException; import io.micrometer.common.util.StringUtils; +import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -1043,5 +1045,12 @@ public class Utils { return new ArrayList<>(responseMap.values()); } + public static HttpHeaders getHeaders(){ + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.add(org.apache.http.HttpHeaders.USER_AGENT, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0"); + return headers; + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b165e997..cac5e36b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -75,4 +75,19 @@ spring.cloud.openfeign.client.config.default.readTimeout=300000 spring.rabbitmq.connection-timeout=120000 app.bandi.login.url.suffix=/loginadmin -app.confidi.login.url.suffix=/confidi \ No newline at end of file +app.confidi.login.url.suffix=/confidi + +#sviluppumbria protocol +codAoo=SVILUMBRIA-01 +sviluppumbria.username=protocollatoresvilumbria +password=8e85ea4265e49497d697168fd3d34916 +CLASSIFICA=06.004.3 +TIPO_PROTOCOLLAZIONE=E +tipoCorrispondenteCompany=PersonaGiuridica +tipoCorrispondenteWithoutCompany=Persona +mezzo=Altro +indirizzoPec=ufficio01@domain.com +codiceUo=101_10 +competente=true +tipoCorrispondente=Amministrazione +sviluppumbriaUuid=t7jh5wfg9QXylNaTZkPoE diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 0b4e6cc7..de206a11 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2805,4 +2805,22 @@ + + + + + + + + + + + + + + + + + + From 1f711f407b9e98af93bf273beb8831570d9b45c1 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 26 May 2025 19:12:39 +0530 Subject: [PATCH 60/63] Updated code --- .../java/net/gepafin/tendermanagement/dao/ProtocolDao.java | 3 +-- .../tendermanagement/service/feignClient/ProtocolService.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java index 0a337062..a9b23cd6 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java @@ -172,9 +172,8 @@ public class ProtocolDao { mittenteValue = tipoCorrispondenteWithoutCompany; vatNumber = company.getCodiceFiscale(); } - mittenteValue=tipoCorrispondenteWithoutCompany; String companyName = company.getCompanyName() + " " + vatNumber; - String callName = application.getCall().getName(); + String callName = application.getCall().getName()+" "+ application.getCall().getId(); String callId = GepafinConstant.PROTOCOL_CALL_NAME+ String.valueOf(application.getCall().getId()); String pecEmail=company.getPec(); String docUrl=applicationSignedDocumentEntity.getFilePath(); diff --git a/src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java b/src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java index 625c116b..07322a0c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/feignClient/ProtocolService.java @@ -24,7 +24,7 @@ public interface ProtocolService { @PutMapping(GepafinConstant.PROTOCOL_SERVICE_CREATE_PROTOCOL) ResponseEntity createProtocol(@RequestHeader HttpHeaders headers, @RequestParam("CLASSIFICA") String classifica, @RequestParam("ANNO_FASCICOLO") String year, @RequestParam("PROGR_FASCICOLO") String applicationId, - @RequestParam("DES_FASCICOLO") String companyName, @RequestParam("PARENT_PROGR_FASCICOLO") String callName, @RequestParam("PARENT_DES_FASCICOLO") String callId, @RequestBody List> requestBody + @RequestParam("DES_FASCICOLO") String companyName, @RequestParam("PARENT_DES_FASCICOLO") String callName, @RequestParam("PARENT_PROGR_FASCICOLO") String callId, @RequestBody List> requestBody ); From f9b9c5f2e070a4d5e8e81d95691281b45689a387 Mon Sep 17 00:00:00 2001 From: Piyush Date: Wed, 28 May 2025 11:56:17 +0530 Subject: [PATCH 61/63] Done Ticket GEPAFINBE-171 --- .../dao/ApplicationAmendmentRequestDao.java | 49 ++++++++++-- .../tendermanagement/dao/ApplicationDao.java | 77 ++++++++++++++++--- .../dao/ApplicationEvaluationDao.java | 60 +++++++++++++-- .../tendermanagement/dao/AppointmentDao.java | 51 ++++++++---- .../dao/AssignedApplicationsDao.java | 32 ++++++-- .../gepafin/tendermanagement/dao/CallDao.java | 77 ++++++++++++++++--- .../tendermanagement/dao/CompanyDao.java | 17 +++- .../dao/CompanyDocumentDao.java | 30 ++++++-- .../tendermanagement/dao/DocumentDao.java | 30 +++++++- .../gepafin/tendermanagement/dao/PdfDao.java | 2 + 10 files changed, 361 insertions(+), 64 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index daa4391b..2748f9bf 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -151,7 +151,8 @@ public class ApplicationAmendmentRequestDao { String file=applicationEvaluationEntity.getFile(); String checkList=applicationEvaluationEntity.getChecklist(); if(file != null){ - evaluationFileRequests=Utils.convertJsonStringToList(file,FieldRequest.class); + log.info("Parsing evaluation file data for evaluationId={}", applicationEvaluationId); + evaluationFileRequests=Utils.convertJsonStringToList(file,FieldRequest.class); } if(applicationEvaluationEntity.getEvaluationVersion().equals(EvaluationVersionEnum.V1.getValue())) { checklistValidationForEvaluationV1(evaluationFileRequests, checkList, checklistRequests); @@ -309,6 +310,7 @@ public class ApplicationAmendmentRequestDao { applicationAmendmentRequestEntity.setNote(applicationAmendmentRequest.getNote()); applicationAmendmentRequestEntity.setResponseDays(applicationAmendmentRequest.getResponseDays()); if(applicationAmendmentRequest.getResponseDays()==null || applicationAmendmentRequest.getResponseDays() < 0){ + log.warn("Invalid responseDays received: {}", applicationAmendmentRequest.getResponseDays()); throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.RESPONSE_DAYS_NOT_NULL)); } applicationAmendmentRequestEntity.setEndDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()).plusDays(applicationAmendmentRequest.getResponseDays())); @@ -361,6 +363,8 @@ public class ApplicationAmendmentRequestDao { userEntity.getHub().getId(),false); applicationAmendmentRequestEntity.setProtocol(protocolEntity); ApplicationAmendmentRequestEntity applicationAmendment = saveApplicationAmendmentRequestEntity(applicationAmendmentRequestEntity, null, VersionActionTypeEnum.INSERT); + log.info("Amendment request saved with ID={}", applicationAmendment.getId()); + String evaluationStatusType = applicationEvaluationEntity.getStatus(); if (Boolean.FALSE.equals(evaluationStatusType.equals((ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue())))){ // applicationEvaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.SOCCORSO.getValue()); @@ -399,7 +403,7 @@ public class ApplicationAmendmentRequestDao { loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldAssignedApplication).newData(assignedApplicationsEntity).build()); } - + log.info("Amendment creation process completed successfully for applicationId={}, evaluationId={}", applicationId, applicationEvaluationId); return applicationAmendment; } private void setAmendmentDocuments(String amendmentNotes, String amendmentFieldRequest, @@ -490,7 +494,7 @@ public class ApplicationAmendmentRequestDao { } public DocumentResponseBean createDocumentResponseBean(String documentId) { - + log.info("Initiating document response creation for documentId={}", documentId); if (!StringUtils.isEmpty(documentId)) { Optional documentEntity = documentRepository.findByIdAndNotDeleted(Long.valueOf(documentId)); if(documentEntity.isPresent()){ @@ -653,7 +657,9 @@ public class ApplicationAmendmentRequestDao { } public List getAllApplicationAmendmentRequest(HttpServletRequest request, Long userId) { + log.info("Entering getAllApplicationAmendmentRequest with userId={}", userId); if (validator.checkIsPreInstructor() && userId == null) { + log.warn("Access denied: Pre-instructor must provide userId for amendment request retrieval."); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.USER_ID_NOT_NULL_MSG)); } if (userId != null) { @@ -696,9 +702,11 @@ public class ApplicationAmendmentRequestDao { isBeneficiary=true; } if(Boolean.TRUE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue())){ - throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); + log.warn("Permission denied: Beneficiary tried to update amendment ID {} with status RESPONSE_RECEIVED", id); + throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); } if(Boolean.FALSE.equals(isBeneficiary) && existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())){ + log.warn("Permission denied: Non-beneficiary tried to update amendment ID {} with status AWAITING", id); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); } @@ -721,10 +729,12 @@ public class ApplicationAmendmentRequestDao { } existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); if(updateRequest.getAmendmentDocuments()!=null && Boolean.FALSE.equals(updateRequest.getAmendmentDocuments().isEmpty())) { + log.debug("Setting amendment documents for amendment ID: {}", id); setAmendmentDocuments(updateRequest.getAmendmentNotes(),updateRequest.getAmendmentDocuments(), existingApplicationAmendment); } ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment,oldApplicationAmendmentEntity,VersionActionTypeEnum.UPDATE); ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false); + log.info("Successfully updated ApplicationAmendmentRequest with ID: {}", id); log.info("Application Amendment updated successfully: {}", response); return response; } @@ -1020,6 +1030,7 @@ public class ApplicationAmendmentRequestDao { public List getAllAmendmentRequestByBeneficiaryId(Long beneficiaryUserId) { + log.info("Fetching all amendment requests for beneficiaryUserId={}", beneficiaryUserId); UserEntity userEntity = userService.validateUser(beneficiaryUserId); List entities = applicationAmendmentRequestRepository.findByUserId(beneficiaryUserId); @@ -1039,6 +1050,8 @@ public class ApplicationAmendmentRequestDao { existingApplicationAmendment.getApplicationEvaluationEntity().getId() ); + log.debug("Found {} amendment requests for ApplicationEvaluationId={}", amendmentRequestList.size(), existingApplicationAmendment.getApplicationEvaluationEntity().getId()); + // Check if this is the last amendment being closed boolean isLastRemaining = amendmentRequestList.stream() .filter(amendment -> !amendment.getId().equals(id)) // Exclude the current amendment @@ -1055,6 +1068,8 @@ public class ApplicationAmendmentRequestDao { VersionActionTypeEnum.UPDATE); ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false); + log.info("Updated amendment status to CLOSE for amendment ID: {}", id); + List amendmentRequests = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse( existingApplicationAmendment.getApplicationEvaluationEntity().getId()); Boolean allClosed = amendmentRequests.stream().allMatch(amendment -> (amendment.getStatus().equals(ApplicationAmendmentRequestEnum.CLOSE.getValue()) || amendment.getStatus().equals(ApplicationAmendmentRequestEnum.EXPIRED.getValue()))); @@ -1062,16 +1077,18 @@ public class ApplicationAmendmentRequestDao { ApplicationEntity oldApplicationEntityData = Utils.getClonedEntityForData(application); if (Boolean.TRUE.equals(allClosed)) { existingApplicationAmendment.getApplicationEvaluationEntity().setStatus(ApplicationEvaluationStatusTypeEnum.OPEN.getValue()); - if (allClosed) { ApplicationEvaluationEntity existingApplicationEvaluationEntity = existingApplicationAmendment.getApplicationEvaluationEntity(); ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(existingApplicationEvaluationEntity); existingApplicationEvaluationEntity.setStatus(ApplicationEvaluationStatusTypeEnum.OPEN.getValue()); applicationEvaluationRepository.save(existingApplicationAmendment.getApplicationEvaluationEntity()); + log.info("Updated ApplicationEvaluation status to OPEN for ID: {}", existingApplicationEvaluationEntity.getId()); application.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); applicationRepository.save(application); + log.info("Updated Application status to EVALUATION for Application ID: {}", application.getId()); + existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity().setStatus(AssignedApplicationEnum.OPEN.getValue()); AssignedApplicationsEntity assignedApplicationsEntity = assignedApplicationsDao.validateAssignedApplication( @@ -1079,7 +1096,7 @@ public class ApplicationAmendmentRequestDao { AssignedApplicationsEntity oldAssignedApplicationData = Utils.getClonedEntityForData(assignedApplicationsEntity); assignedApplicationsEntity = assignedApplicationsRepository.save(existingApplicationAmendment.getApplicationEvaluationEntity().getAssignedApplicationsEntity()); - + log.info("Updated AssignedApplication status to OPEN for ID: {}", assignedApplicationsEntity.getId()); Map placeHolders = notificationDao.sendNotificationToBeneficiary(application, NotificationTypeEnum.AMENDMENT_CLOSED); @@ -1106,6 +1123,7 @@ public class ApplicationAmendmentRequestDao { public ApplicationAmendmentRequestResponse extendResponseDays(Long id, Long newResponseDays) { + log.info("Extending response days for Application Amendment ID: {}, Additional Days: {}", id, newResponseDays); ApplicationAmendmentRequestEntity applicationAmendmentRequestEntity = validateApplicationAmendmentRequest(id); if (newResponseDays != null && newResponseDays > 0) { @@ -1156,6 +1174,7 @@ public class ApplicationAmendmentRequestDao { ApplicationAmendmentRequestEntity existingApplicationAmendment = validateApplicationAmendmentRequest(id); ApplicationAmendmentRequestEntity oldApplicationAmendmentEntity = Utils.getClonedEntityForData(existingApplicationAmendment); if (Boolean.TRUE.equals(existingApplicationAmendment.getStatus().equals(ApplicationAmendmentRequestEnum.AWAITING.getValue())) && Boolean.TRUE.equals(statusTypeEnum.equals(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED))) { + log.info("Updating amendment ID {} status from {} to {}", id, existingApplicationAmendment.getStatus(), statusTypeEnum); existingApplicationAmendment.setStatus(ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue()); existingApplicationAmendment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); applicationAmendmentRequestRepository.save(existingApplicationAmendment); @@ -1169,9 +1188,11 @@ public class ApplicationAmendmentRequestDao { } public void sendReminderEmail(Long amendmentId) { - + log.info("Initiating reminder email process for Amendment ID: {}", amendmentId); ApplicationAmendmentRequestEntity amendment = applicationAmendmentRequestRepository.findByIdAndIsDeletedFalse(amendmentId) - .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG))); + .orElseThrow(() -> { log.error("Amendment not found with ID: {}", amendmentId); + return new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_AMENDMENT_NOT_FOUND_MSG)); + }); Optional entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(amendment.getApplicationEvaluationEntity().getId()); if (entityOptional.isPresent()) { @@ -1183,10 +1204,13 @@ public class ApplicationAmendmentRequestDao { String body = prepareBody(emailTemplate, amendment, beneficiaryUser); String email = beneficiaryUser.getEmail(); if (Boolean.TRUE.equals(amendment.getIsEmail()) && email != null && !email.isEmpty()) { + log.info("Sending reminder email to: {}", email); EmailLogRequest emailLogRequest = emailLogDao.createEmailLogRequest(emailTemplate.getEmailScenario(), RecipientTypeEnum.USER, beneficiaryUser.getId(), email, beneficiaryUser.getId(), applicationEntity.getId(), amendment.getId(), applicationEntity.getCall().getId()); emailNotificationDao.sendMail(hub.getId(), subject, body, List.of(email), emailLogRequest); + log.info("Reminder email sent successfully for Amendment ID: {}", amendmentId); } else { + log.warn("Beneficiary email not found or isEmail flag is false for Amendment ID: {}", amendmentId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.BENEFICIARY_EMAIL_NOT_FOUND_MSG)); } } @@ -1220,6 +1244,7 @@ public class ApplicationAmendmentRequestDao { } public ApplicationEvaluationEntity calculateEndDateAndSuspensionDays(ApplicationEvaluationEntity applicationEvaluationEntity){ + log.info("Calculating end date and suspension days for Application Evaluation ID: {}", applicationEvaluationEntity.getId()); LocalDateTime currentDate=DateTimeUtil.DateServerToUTC(LocalDateTime.now()); LocalDateTime endDate=currentDate.plusDays(applicationEvaluationEntity.getRemainingDays()); Long suspendedDays = ChronoUnit.DAYS.between(applicationEvaluationEntity.getStopDateTime(), currentDate); @@ -1230,8 +1255,10 @@ public class ApplicationAmendmentRequestDao { applicationEvaluationEntity.setSuspendedDays(0L); } applicationEvaluationEntity.setSuspendedDays(applicationEvaluationEntity.getSuspendedDays()+suspendedDays); + log.debug("Updated suspended days: {}", applicationEvaluationEntity.getSuspendedDays()); ApplicationEvaluationEntity applicationEvaluation = applicationEvaluationRepository.save(applicationEvaluationEntity); + log.info("Application Evaluation updated successfully. ID: {}", applicationEvaluation.getId()); /** 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()); @@ -1271,7 +1298,9 @@ public class ApplicationAmendmentRequestDao { return response; } private void softDeleteDocument(Long documentId) { + log.info("Initiating soft delete for Document ID: {}", documentId); documentService.deleteFile(documentId); + log.info("Document ID: {} soft deleted successfully.", documentId); } // public PageableResponseBean> getApplicationAmendmentByPaginnation(Long userId, ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { @@ -1390,6 +1419,7 @@ public class ApplicationAmendmentRequestDao { // } public PageableResponseBean> getApplicationAmendmentByPaginationByView(Long userId, ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { + log.info("Fetching paginated application amendments for userId: {}", userId); Integer pageNo = null; Integer pageLimit = null; if (applicationAmendmentPaginationRequestBean.getGlobalFilters() != null) { @@ -1421,6 +1451,7 @@ public class ApplicationAmendmentRequestDao { pageableResponseBean.setTotalRecords(entityPage.getTotalElements()); pageableResponseBean.setPageSize(entityPage.getSize()); + log.info("Paginated response prepared successfully for userId: {}", userId); return pageableResponseBean; } public Specification searchPaginationByView(Long userId,ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { @@ -1452,6 +1483,7 @@ public class ApplicationAmendmentRequestDao { private List getPredicatesByView(ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean, CriteriaBuilder criteriaBuilder, Root root,Long userId) { + log.info("Building predicates for userId: {}", userId); Integer year = null; String search = null; Map filters = new HashMap<>(); @@ -1471,6 +1503,7 @@ public class ApplicationAmendmentRequestDao { LocalDateTime startOfYear = LocalDateTime.of(filterYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(filterYear, 12, 31, 23, 59, 59); + log.debug("Filtering by year between {} and {}", startOfYear, endOfYear); // Add the range comparison to filter records within the year predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), startOfYear, endOfYear)); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index a98b3ff9..f54f26cc 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -198,13 +198,16 @@ public class ApplicationDao { public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) { + log.info("Starting createApplication: formId={}, applicationId={}", formId, applicationId); FormEntity formEntity = formService.validateForm(formId); // callService.validatePublishedCall(formEntity.getCall().getId()); validateFormFields(applicationRequestBean,formEntity); ApplicationEntity applicationEntity = validateApplication(applicationId); checkCallEndDate(applicationEntity.getCall()); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); + log.info("Validated user-company association for company ID: {}", applicationEntity.getCompanyId()); if(Boolean.FALSE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.DRAFT.getValue()))) { + log.warn("Application ID {} is not in DRAFT status", applicationId); throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.APPLICATION_NOT_IN_DRAFT_STATUS)); } formService.validateFormField(applicationRequestBean.getFormFields(),applicationEntity,formEntity); @@ -231,10 +234,12 @@ public class ApplicationDao { } public ApplicationFormEntity createApplicationFormEntity(ApplicationEntity application, FormEntity formEntity) { + log.info("Creating ApplicationFormEntity for applicationId: {}, formId: {}", application.getId(), formEntity.getId()); ApplicationFormEntity applicationFormEntity = new ApplicationFormEntity(); applicationFormEntity.setApplication(application); applicationFormEntity.setForm(formEntity); applicationFormEntity = saveApplicationFormEntity(applicationFormEntity); + log.info("Created ApplicationFormEntity with id: {}", applicationFormEntity.getId()); return applicationFormEntity; } @@ -286,6 +291,7 @@ public class ApplicationDao { List documentResponseBeans = new ArrayList<>(); if (fileUploadContent.isPresent()) { String documentId = applicationFormFieldEntity.getFieldValue(); + log.debug("Field is file upload/select type. Document IDs: {}", documentId); if (documentId != null && !documentId.isEmpty()) { documentResponseBeans = Arrays.stream(documentId.split(",")) .map(String::trim) @@ -293,6 +299,7 @@ public class ApplicationDao { .map(docId -> { DocumentEntity documentEntity = documentService.validateDocument(docId); if (Boolean.FALSE.equals(DocumentSourceTypeEnum.APPLICATION.getValue().equals(documentEntity.getSource()))) { + log.warn("Document {} source type invalid: {}", docId, documentEntity.getSource()); throw new CustomValidationException(Status.NOT_FOUND,Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); } return documentEntity; @@ -318,6 +325,7 @@ public class ApplicationDao { ApplicationEntity applicationEntity= validateApplication(id); if (Boolean.FALSE.equals(ApplicationStatusTypeEnum.DRAFT.getValue().equals(applicationEntity.getStatus()))) { + log.warn("Application with ID: {} is not in DRAFT status, cannot delete. Current status: {}", id, applicationEntity.getStatus()); throw new CustomValidationException( Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.APPLICATION_NOT_IN_DRAFT_STATUS) @@ -328,6 +336,7 @@ public class ApplicationDao { validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); applicationEntity.setIsDeleted(true); applicationEntity = applicationRepository.save(applicationEntity); + log.info("Marked application as deleted and saved for ID: {}", id); /** This code is responsible for adding a version history log for the "Delete application" operation. **/ loggingUtil.addVersionHistory( @@ -415,6 +424,7 @@ public class ApplicationDao { } private ApplicationResponse getApplicationResponse(ApplicationEntity applicationEntity) { + log.info("Generating ApplicationResponse for application ID: {}", applicationEntity.getId()); ApplicationResponse responseBean = new ApplicationResponse(); List flowEdgesList = flowEdgesRepository.findByCallId(applicationEntity.getCall().getId()); Long totalFormSteps = flowFormDao.calculateTotalSteps(flowEdgesList); @@ -455,9 +465,13 @@ public class ApplicationDao { } public ApplicationEntity validateApplication(Long id) { + log.info("Validating existence of Application with ID: {}", id); ApplicationEntity applicationEntity = applicationRepository.findById(id) - .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG))); + .orElseThrow(() -> { + log.warn("Application not found for ID: {}", id); + return new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_NOT_FOUND_MSG)); + }); return applicationEntity; } @@ -481,10 +495,12 @@ public class ApplicationDao { } private ApplicationFormEntity getApplicationFormOrCreate(FormEntity formEntity, ApplicationEntity applicationEntity) { + log.info("Fetching ApplicationForm for Application ID: {} and Form ID: {}", applicationEntity.getId(), formEntity.getId()); ApplicationFormEntity applicationFormEntity = applicationFormRepository.findByApplicationIdAndFormId(applicationEntity.getId(), formEntity.getId()); ApplicationFormEntity oldApplicationFormEntity = Utils.getClonedEntityForData(applicationFormEntity); if (applicationFormEntity == null) { + log.info("No existing ApplicationForm found. Creating new ApplicationForm for Application ID: {}, Form ID: {}", applicationEntity.getId(), formEntity.getId()); applicationFormEntity = createApplicationFormEntity(applicationEntity, formEntity); /** This code is responsible for adding a version history log for the "Create application form" operation. **/ @@ -510,6 +526,8 @@ public class ApplicationDao { public ApplicationFormFieldEntity createOrUpdateApplicationFormField(ApplicationFormFieldRequestBean applicationFormFieldRequestBean, ApplicationFormEntity applicationFormEntity, List applicationFormFieldEntities, FormEntity formEntity,FieldValidator fieldValidator) { + log.info("Starting createOrUpdateApplicationFormField for ApplicationForm ID: {}", applicationFormEntity.getId()); + ApplicationFormFieldEntity applicationFormFieldEntity = new ApplicationFormFieldEntity(); List newDocumentIds = validateFileUploadDocuments(applicationFormFieldRequestBean, formEntity); @@ -529,7 +547,9 @@ public class ApplicationDao { try { BigDecimal amountRequested = new BigDecimal(fieldValue.toString()); applicationFormEntity.getApplication().setAmountRequested(amountRequested); + log.info("Set amountRequested to {} for Application ID: {}", amountRequested, applicationFormEntity.getApplication().getId()); } catch (NumberFormatException e) { + log.error("Invalid number format for requested amount: {}", fieldValue, e); throw new IllegalArgumentException("Field value is not a valid number: " + fieldValue, e); } } @@ -670,6 +690,8 @@ public class ApplicationDao { List documentIds=null; // List contentResponseBeans=Utils.convertJsonStringToList(formEntity.getContent(),ContentResponseBean.class); List contentResponseBeans=formDao.convertFormEntityToFormResponseBean(formEntity).getContent(); + log.debug("Validating file upload documents for field ID: {} in form ID: {}", applicationFormFieldRequestBean.getFieldId(), formEntity.getId()); + for (ContentResponseBean contentResponseBean:contentResponseBeans){ if(Boolean.TRUE.equals(contentResponseBean.getName().equals("fileupload")) || Boolean.TRUE.equals(contentResponseBean.getName().equals("fileselect"))) { if (contentResponseBean.getId().equals(applicationFormFieldRequestBean.getFieldId())) { @@ -679,6 +701,7 @@ public class ApplicationDao { String documentId = (String) fieldValueObject; // Now you can use documentId as needed documentIds = validateDocumentIds(documentId); + log.info("Validated document IDs: {}", documentIds); } } } @@ -688,6 +711,7 @@ public class ApplicationDao { public List validateDocumentIds(String documentId) { if (documentId != null && !documentId.isEmpty()) { + log.info("Validating document IDs: {}", documentId); return Arrays.stream(documentId.split(",")) .map(Long::parseLong) .peek(docId -> documentService.validateDocument(docId)) @@ -740,6 +764,7 @@ public class ApplicationDao { } public ApplicationGetResponseBean getApplicationByFormId(HttpServletRequest request, Long applicationId, Long formId) { + log.info("Received request to get application by formId. ApplicationId: {}, FormId: {}", applicationId, formId); List formApplicationResponses = new ArrayList<>(); List formEntities = new ArrayList<>(); UserEntity userEntity = validator.validateUser(request); @@ -890,6 +915,7 @@ public class ApplicationDao { public ApplicationResponse createApplicationByCallId(CompanyEntity companyEntity, ApplicationRequest applicationRequest, Long callId, UserEntity userEntity) { + log.info("Start creating application for CallId: {}, UserId: {}, CompanyId: {}", callId, userEntity.getId(), companyEntity.getId()); CallEntity call = callService.validateCall(callId); UserWithCompanyEntity userWithCompanyEntity=companyService.getUserWithCompany(userEntity.getId(),companyEntity.getId()); checkCallEndDate(call); @@ -913,11 +939,15 @@ public class ApplicationDao { public void checkIfApplicationExists(CallEntity call, UserWithCompanyEntity userWithCompanyEntity, UserEntity userEntity){ + log.info("Checking existing applications for UserId: {}, UserWithCompanyId: {}, CallId: {}", + userEntity.getId(), userWithCompanyEntity.getId(), call.getId()); List applications = applicationRepository.findByUserIdAndUserWithCompany_IdAndCall_IdAndIsDeletedFalseAndStatusNot( userEntity.getId(), userWithCompanyEntity.getId(), call.getId(), ApplicationStatusTypeEnum.REJECTED.name() ); if (!applications.isEmpty()) { + log.warn("Application already exists for UserId: {}, UserWithCompanyId: {}, CallId: {}. Applications found: {}", + userEntity.getId(), userWithCompanyEntity.getId(), call.getId(), applications.size()); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_EXISTS)); } } @@ -935,10 +965,12 @@ public class ApplicationDao { UserEntity userEntity = userService.validateUser(applicationEntity.getUserId()); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); if (ApplicationStatusTypeEnum.SUBMIT.getValue().equals(applicationEntity.getStatus())) { + log.warn("Attempt to change status after submission denied | applicationId: {}", applicationId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_SUBMITTED_CANNOT_CHANGE)); } if (Boolean.TRUE.equals(applicationEntity.getStatus().equals(status.getValue()))) { + log.warn("Requested status is the same as current status | applicationId: {}, status: {}", applicationId, status); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_IN_PREVIOUS_STATUS)); } if (status.equals(ApplicationStatusTypeEnum.SUBMIT) && Boolean.TRUE.equals(applicationEntity.getStatus().equals(ApplicationStatusTypeEnum.READY.getValue()))) { @@ -1068,6 +1100,7 @@ public class ApplicationDao { } private void sendMailToUserAndCompany(UserEntity userEntity, ApplicationEntity applicationEntity) { + log.info("Preparing to send submission email | applicationId: {}, userId: {}", applicationEntity.getId(), userEntity.getId()); CallEntity call =applicationEntity.getCall(); CompanyEntity company=companyService.validateCompany(applicationEntity.getCompanyId()); UserWithCompanyEntity userWithCompany=companyService.getUserWithCompany(userEntity.getId(),company.getId()); @@ -1176,6 +1209,7 @@ public class ApplicationDao { } public ApplicationSignedDocumentResponse uploadSignedDocument(HttpServletRequest request, Long applicationId, MultipartFile file) { + log.info("Received request to upload signed document | applicationId: {}, fileName: {}", applicationId, file.getOriginalFilename()); ApplicationEntity applicationEntity = validateApplication(applicationId); checkCallEndDate(applicationEntity.getCall()); //cloned entity for old data @@ -1188,9 +1222,11 @@ public class ApplicationDao { ApplicationSignedDocumentEntity oldApplicationSingedDocumentData = Utils.getClonedEntityForData(applicationSignedDocument); if (applicationSignedDocument != null) { + log.info("Existing active signed document found and will be deleted | applicationId: {}, fileName: {}", applicationId, applicationSignedDocument.getFileName()); deleteSignedDocumentFromS3(applicationSignedDocument); } UploadFileOnAmazonS3Response uploadFileOnAmazonS3 = uploadFileOnAmazonS3ForUserSignedDocument(file, applicationEntity.getCall().getId(), applicationId); + log.info("File uploaded to S3 successfully | applicationId: {}", applicationId); applicationSignedDocument = new ApplicationSignedDocumentEntity(); applicationSignedDocument.setApplication(applicationEntity); applicationSignedDocument.setFileName(uploadFileOnAmazonS3.getFileName()); @@ -1204,6 +1240,8 @@ public class ApplicationDao { applicationEntity.setStatus(ApplicationStatusTypeEnum.READY.getValue()); applicationEntity = applicationRepository.save(applicationEntity); + log.info("Application status updated to READY | applicationId: {}", applicationEntity.getId()); + /** This code is responsible for adding a version history log for the "Create Call" operation. **/ loggingUtil.addVersionHistory( @@ -1212,16 +1250,22 @@ public class ApplicationDao { return convertApplicationSignedDocumentToApplicationSignedDocumentResponse(applicationSignedDocument); } public void deleteSignedDocumentFromS3(ApplicationSignedDocumentEntity applicationSignedDocumentEntity){ + log.info("Starting soft delete of signed document | applicationSignedDocumentId: {}, fileName: {}", + applicationSignedDocumentEntity.getId(), applicationSignedDocumentEntity.getFileName()); ApplicationSignedDocumentEntity oldApplicationSignedDocument = Utils.getClonedEntityForData(applicationSignedDocumentEntity); String oldS3Path = applicationSignedDocumentEntity.getFilePath(); + log.debug("Old S3 path: {} ", oldS3Path); String newS3Path = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.DELETED_USER_SIGNED_DOCUMENT,applicationSignedDocumentEntity.getApplication().getCall().getId(),applicationSignedDocumentEntity.getApplication().getId(),0L); + log.debug("Generated new S3 path for deleted document: {}", newS3Path); UploadFileOnAmazonS3Response response = amazonS3Service.moveFile(applicationSignedDocumentEntity.getFileName(), oldS3Path, newS3Path); + log.info("Moved file in S3 from {} to {} | fileName: {}", oldS3Path, newS3Path, response.getFileName()); applicationSignedDocumentEntity.setStatus(ApplicationSignedDocumentStatusEnum.INACTIVE.getValue()); applicationSignedDocumentEntity.setFileName(response.getFileName()); applicationSignedDocumentEntity.setFilePath(response.getFilePath()); applicationSignedDocumentRepository.save(applicationSignedDocumentEntity); + log.info("Updated signed document entity status to INACTIVE and saved | applicationSignedDocumentId: {}", applicationSignedDocumentEntity.getId()); loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldApplicationSignedDocument).newData(applicationSignedDocumentEntity).build()); } @@ -1240,6 +1284,7 @@ public class ApplicationDao { log.info("S3 Path {}", s3Path); return amazonS3Service.uploadFileOnAmazonS3(s3Path, file); } catch (Exception e) { + log.error("Failed to upload user signed document | callId: {}, applicationId: {}, error: {}", callId, applicationId, e.getMessage(), e); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); } } @@ -1247,6 +1292,7 @@ public class ApplicationDao { try { return s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.USER_SIGNED_DOCUMENT, callId, applicationId,0L); } catch (IllegalArgumentException e) { + log.error("Failed to generate S3 path for delegation | callId: {}, applicationId: {}, error: {}", callId, applicationId, e.getMessage(), e); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.S3_PATH_GENERATION_ERROR_MSG)); } } @@ -1271,13 +1317,14 @@ public class ApplicationDao { } String filename = file.getOriginalFilename(); if (filename == null || !filename.endsWith(".p7m")) { + log.warn("Invalid file type detected | filename: {}", filename); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.VALIDATION_ERROR_FILE_INVALIDTYPE)); } } public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId) { - + log.info("Fetching signed document for applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); // validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); @@ -1291,6 +1338,7 @@ public class ApplicationDao { ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); if(applicationSignedDocument == null) { + log.warn("No active signed document found for applicationId: {}", applicationId); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_SIGNED_DOCUMENT_NOT_FOUND)); } @@ -1298,6 +1346,7 @@ public class ApplicationDao { } public void deleteSignedDocument(HttpServletRequest request, Long applicationId) { + log.info("Initiating deletion of signed document for applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); @@ -1306,6 +1355,7 @@ public class ApplicationDao { //cloned entity for old data ApplicationSignedDocumentEntity oldApplicationSignedDocument = Utils.getClonedEntityForData(applicationSignedDocument); if(applicationSignedDocument == null) { + log.warn("No active signed document found to delete for applicationId: {}", applicationId); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_SIGNED_DOCUMENT_NOT_FOUND)); } @@ -1318,7 +1368,7 @@ public class ApplicationDao { } public ApplicationResponse validateApplication(HttpServletRequest request, Long applicationId) { - + log.info("Starting application validation process | applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(applicationEntity); checkCallEndDate(applicationEntity.getCall()); @@ -1326,15 +1376,18 @@ public class ApplicationDao { UserEntity userEntity = userService.validateUser(applicationEntity.getUserId()); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); if (Boolean.FALSE.equals(ApplicationStatusTypeEnum.DRAFT.getValue().equals(applicationEntity.getStatus()))) { + log.warn("Application not in draft status | applicationId: {}, status: {}", applicationId, applicationEntity.getStatus()); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_NOT_IN_DRAFT_STATUS)); } if (applicationEntity.getAmountRequested() == null || applicationEntity.getAmountRequested().compareTo(BigDecimal.ZERO) <= 0 ) { + log.warn("Invalid amount requested | amount: {}", applicationEntity.getAmountRequested()); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.AMOUNT_REQUEST_SHOULD_GREATED_THEN_ZERO)); } List flowEdgesList = flowEdgesRepository.findByCallId(applicationEntity.getCall().getId()); Long totalSteps = flowFormDao.calculateTotalSteps(flowEdgesList); Integer completedSteps = flowFormDao.getCompletedSteps(applicationEntity, true); if (totalSteps.intValue() != completedSteps) { + log.warn("Application incomplete | applicationId: {}", applicationId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_IS_INCOMPLETE_MSG)); } @@ -1349,7 +1402,7 @@ public class ApplicationDao { } public byte[] downloadApplicationDocumentsAsZip(HttpServletRequest request, Long applicationId) { - + log.info("Starting ZIP download process for applicationId: {}", applicationId); ApplicationEntity applicationEntity = validateApplication(applicationId); validateAssignedUser(request, applicationId); Set documentIds = extractDocumentIdsFromApplicationForms(applicationId); @@ -1359,13 +1412,14 @@ public class ApplicationDao { List amendmentDocuments = fetchAmendmentDocuments(applicationId); List evaluationDocuments = fetchEvaluationDocuments(applicationId); if (documents.isEmpty() && signedDocument == null && amendmentDocuments.isEmpty() && evaluationDocuments.isEmpty()) { + log.warn("No documents found for applicationId: {}", applicationId); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); } return createZipWithDocuments(applicationEntity, documents, signedDocument, amendmentDocuments, evaluationDocuments, applicationId); } private void validateAssignedUser(HttpServletRequest request, Long applicationId) { - + log.info("Validating assigned user for applicationId: {}", applicationId); AssignedApplicationsEntity assignedApplications = assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationId).orElse(null); if (assignedApplications != null) { validator.validatePreInstructor(request, assignedApplications.getUserId()); @@ -1373,7 +1427,7 @@ public class ApplicationDao { } private Set extractDocumentIdsFromApplicationForms(Long applicationId) { - + log.info("Extracting document IDs from application forms | applicationId: {}", applicationId); Set documentIds = new HashSet<>(); List applicationForms = applicationFormRepository.findByApplicationId(applicationId); applicationForms.forEach(applicationForm -> { @@ -1395,16 +1449,17 @@ public class ApplicationDao { } private List fetchAmendmentDocuments(Long applicationId) { - + log.info("Fetching amendment documents for applicationId: {}", applicationId); List amendmentRequests = applicationAmendmentRequestRepository.findByApplicationIdAndIsDeletedFalse(applicationId); Set amendmentIds = amendmentRequests.stream().map(ApplicationAmendmentRequestEntity::getId).collect(Collectors.toSet()); return documentRepository.findBySourceIdInAndSourceAndIsDeletedFalse(amendmentIds, DocumentSourceTypeEnum.AMENDMENT.getValue()); } private List fetchEvaluationDocuments(Long applicationId) { - + log.info("Fetching evaluation documents for applicationId: {}", applicationId); Optional evaluationEntity = applicationEvaluationRepository.findByApplicationIdAndIsDeletedFalse(applicationId); if (evaluationEntity.isPresent()) { Long evaluationId = evaluationEntity.get().getId(); + log.debug("Found evaluation entity with id: {}", evaluationId); return documentRepository.findBySourceIdInAndSourceAndIsDeletedFalse(Collections.singleton(evaluationId), DocumentSourceTypeEnum.EVALUATION.getValue()); } return Collections.emptyList(); @@ -1418,12 +1473,14 @@ public class ApplicationDao { return "unknown"; } private void addDocumentToZip(ZipOutputStream zos, String s3Folder, String filePath, String fullPath) { - + log.info("Attempting to add file to ZIP. S3 folder: {}, file path: {}", s3Folder, filePath); try (InputStream fileInputStream = amazonS3Service.getFile(s3Folder, filePath)) { zos.putNextEntry(new ZipEntry(fullPath)); IOUtils.copy(fileInputStream, zos); zos.closeEntry(); } catch (IOException e) { + log.error("Failed to add file to ZIP. S3 folder: {}, file path: {}, error: {}", + s3Folder, filePath, e.getMessage(), e); throw new RuntimeException("Error downloading or adding document to ZIP: " + fullPath, e); } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 17cac4c4..75e2a597 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -653,6 +653,7 @@ public class ApplicationEvaluationDao { ApplicationEvaluationRequest req, Long assignedApplicationId) { + log.info("Start createOrUpdateApplicationEvaluation: assignedApplicationId={}, userId={}", assignedApplicationId, user.getId()); Optional existingEntityOptional = applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse(assignedApplicationId); ApplicationEvaluationEntity entity = null; @@ -663,6 +664,7 @@ public class ApplicationEvaluationDao { VersionActionTypeEnum actionType = VersionActionTypeEnum.INSERT; validateApplicationEvaluationRequest(req, application); if (existingEntityOptional.isPresent()) { + log.info("Updating existing application evaluation for assignedApplicationId={}", assignedApplicationId); entity = existingEntityOptional.get(); oldApplicationEvaluation = Utils.getClonedEntityForData(entity); if(req.getCriteria()!=null) { @@ -688,6 +690,7 @@ public class ApplicationEvaluationDao { entity = applicationEvaluationRepository.save(entity); } else { + log.info("Creating new application evaluation for assignedApplicationId={}", assignedApplicationId); AssignedApplicationsEntity assignedApplicationsEntity = assignedApplicationsService.validateAssignedApplication(assignedApplicationId); entity = convertToEntity(user, req, assignedApplicationId); actionType = VersionActionTypeEnum.INSERT; @@ -716,12 +719,13 @@ public class ApplicationEvaluationDao { List applicationAmendmentRequestEntities = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndIsDeletedFalse(entity.getId()); if(req.getEvaluationDocument()!=null) { + log.info("Updating evaluation document for assignedApplicationId={}", assignedApplicationId); updateApplicationEvaluation(assignedApplicationId, req.getEvaluationDocument()); } // Fetch amendment details from the request if(req.getAmendmentDetails()!=null) { + log.debug("Processing amendment details for evaluationId={}", entity.getId()); List amendmentDetailsRequests = req.getAmendmentDetails(); - updateAmendmentDocumentsAndFormFields(applicationAmendmentRequestEntities, amendmentDetailsRequests); } @@ -734,7 +738,10 @@ public class ApplicationEvaluationDao { } private void validateApplicationEvaluationRequest(ApplicationEvaluationRequest req, ApplicationEntity application) { + log.debug("Validating evaluation request for applicationId={}, evaluationVersion={}", + application.getId(), application.getEvaluationVersion()); if(EvaluationVersionEnum.V2.getValue().equals(application.getEvaluationVersion())) { + log.info("Evaluation version is V2 for applicationId={}; setting checklist and criteria to null", application.getId()); req.setChecklist(null); req.setCriteria(null); } @@ -1059,15 +1066,18 @@ public class ApplicationEvaluationDao { } public ApplicationEvaluationEntity validateApplicationEvaluation(Long id) { - + log.debug("Validating existence of ApplicationEvaluationEntity with ID: {}", id); Optional entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(id); if (entityOptional.isEmpty()) { + log.warn("ApplicationEvaluationEntity not found or marked as deleted for ID: {}", id); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.APPLICATION_EVALUATION_NOT_FOUND, id)); } + log.info("Successfully validated ApplicationEvaluationEntity with ID: {}", id); return entityOptional.get(); } public void validatePreinstructor(HttpServletRequest request,Long applicationId,Long assignedApplicationId){ + log.debug("Validating preinstructor access: applicationId={}, assignedApplicationId={}", applicationId, assignedApplicationId); if (applicationId == null && assignedApplicationId == null) { throw new CustomValidationException( Status.BAD_REQUEST, @@ -1091,12 +1101,14 @@ public class ApplicationEvaluationDao { validator.validatePreInstructor(request, assignedApplications.getUserId()); } public ApplicationEvaluationResponse getApplicationEvaluationByApplicationId(HttpServletRequest request, UserEntity user, Long applicationID, Long assignedApplicationID) { + log.info("Entering getApplicationEvaluationByApplicationId: applicationID={}, assignedApplicationID={}", applicationID, assignedApplicationID); Long applicationId; Long assignedApplicationId; validatePreinstructor(request, applicationID, assignedApplicationID); if (applicationID == null && assignedApplicationID != null) { assignedApplicationId = assignedApplicationID; + log.debug("applicationID is null, fetching from assignedApplicationID={}", assignedApplicationId); Optional assignedApplicationsOptional = assignedApplicationsRepository.findByIdAndIsDeletedFalse(assignedApplicationId); @@ -1140,6 +1152,7 @@ public class ApplicationEvaluationDao { public ApplicationEvaluationResponse getEvaluationResponseByApplicationid(UserEntity user, Long applicationId, Long assignedApplicationId) { + log.debug("Entering getEvaluationResponseByApplicationid with applicationId={}, assignedApplicationId={}, userId={}", applicationId, assignedApplicationId, user.getId()); ApplicationEvaluationEntity entity = new ApplicationEvaluationEntity(); ApplicationEvaluationResponse response = new ApplicationEvaluationResponse(); CallEntity call = null; @@ -1193,6 +1206,7 @@ public class ApplicationEvaluationDao { ApplicationEvaluationResponse response, List evaluationCriterias) { + log.info("Setting criteria responses for applicationId: {}", applicationId); List criteriaResponses = getInitialCriteriaResponses(entity, applicationId); criteriaResponses.forEach(criteriaResponse -> { @@ -1388,6 +1402,7 @@ public class ApplicationEvaluationDao { private void setChecklistResponses(ApplicationEvaluationEntity entity, Long applicationId, ApplicationEvaluationResponse response, List checklistEntities) { + log.info("Setting checklist responses for applicationId: {}", applicationId); List checklistResponses = entity.getChecklist() != null ? Utils.convertJsonToList(entity.getChecklist(), new TypeReference>() { }) : getChecklistResponse(applicationId); @@ -1506,6 +1521,7 @@ public class ApplicationEvaluationDao { } List getCriteriaResponse(Long applicationId) { + log.info("Getting criteria response for applicationId: {}", applicationId); CallEntity call = getCallEntityByApplicationId(applicationId); List evaluationCriterias = getEvaluationCriterias(call); @@ -1515,10 +1531,12 @@ public class ApplicationEvaluationDao { } private CallEntity getCallEntityByApplicationId(Long applicationId) { + log.info("Fetching CallEntity for applicationId: {}", applicationId); return callRepository.findCallEntityByApplicationId(applicationId); } private List getEvaluationCriterias(CallEntity call) { + log.info("Fetching evaluation criterias for callId: {}", call.getId()); return evaluationCriteriaRepository .findByCallIdAndLookupDataTypeAndIsDeletedFalse(call.getId(), LookUpDataEntity.LookUpDataTypeEnum.EVALUATION_CRITERIA.getValue()); } @@ -1765,6 +1783,7 @@ public class ApplicationEvaluationDao { List getChecklistResponse(Long applicationId) { + log.info("Fetching checklist responses for applicationId: {}", applicationId); CallEntity call = callRepository.findCallEntityByApplicationId(applicationId); List checklistEntities = callTargetAudienceChecklistRepository .findByCallIdAndLookupDataTypeAndIsDeletedFalse(call.getId(), LookUpDataEntity.LookUpDataTypeEnum.CHECKLIST.getValue()); @@ -1850,7 +1869,7 @@ public class ApplicationEvaluationDao { } public void deleteById(Long id) { - + log.info("Starting soft delete for ApplicationEvaluation with id: {}", id); ApplicationEvaluationEntity applicationEvaluationEntity = validateApplicationEvaluation(id); ApplicationEvaluationEntity oldApplicationEvaluation = Utils.getClonedEntityForData(applicationEvaluationEntity); applicationEvaluationEntity.setIsDeleted(true); @@ -1872,6 +1891,8 @@ public class ApplicationEvaluationDao { public ApplicationEvaluationResponse updateApplicationEvaluationStatus(ApplicationEntity application, AssignedApplicationsEntity assignedApplicationsEntity, ApplicationStatusForEvaluation newStatus) { + log.info("Starting updateApplicationEvaluationStatus for applicationId: {}, assignedApplicationId: {}, newStatus: {}", + application.getId(), assignedApplicationsEntity.getId(), newStatus); Optional existingEntityOptional = applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse( assignedApplicationsEntity.getId()); ApplicationEvaluationEntity entity; @@ -1891,11 +1912,13 @@ public class ApplicationEvaluationDao { } if(newStatus.equals(ApplicationStatusForEvaluation.TECHNICAL_EVALUATION) && Boolean.TRUE.equals(application.getStatus().equals(ApplicationStatusTypeEnum.ADMISSIBLE.getValue()))){ + log.info("Processing technical evaluation for applicationId: {}", application.getId()); processTechnicalEvaluation(application.getId(), application, newStatus); } if((newStatus.equals(ApplicationStatusForEvaluation.APPROVED) || newStatus.equals(ApplicationStatusForEvaluation.REJECTED)) && application.getStatus().equals(ApplicationStatusTypeEnum.EVALUATION.getValue())) { application.setStatus(newStatus.getValue()); + log.info("Application status updated to {} for applicationId: {}", newStatus, application.getId()); } application = applicationRepository.save(application); @@ -1907,6 +1930,7 @@ public class ApplicationEvaluationDao { List amendmentRequest = applicationAmendmentRequestRepository.findAllByApplicationEvaluationIdAndStatusAndIsDeletedFalse(existingEntity.getId(),List.of(ApplicationAmendmentRequestEnum.AWAITING.getValue(),ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue())); if(amendmentRequest !=null && Boolean.FALSE.equals(amendmentRequest.isEmpty())){ + log.warn("Application cannot be approved or rejected due to pending amendment requests. applicationEvaluationId: {}", existingEntity.getId()); throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.APPLICATION_CANNOT_APPROVED_OR_REJECTED)); } String statusType = application.getStatus(); @@ -1914,11 +1938,13 @@ public class ApplicationEvaluationDao { existingEntity.setStatus(ApplicationEvaluationStatusTypeEnum.CLOSE.getValue()); existingEntity.setClosingDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); assignedApplicationsEntity.setStatus(AssignedApplicationEnum.CLOSE.getValue()); + log.info("Closing ApplicationEvaluation and AssignedApplication for applicationId: {}", application.getId()); } if (existingEntity.getStartDate() != null && existingEntity.getClosingDate() != null) { long activeDays = ChronoUnit.DAYS.between(existingEntity.getStartDate(), existingEntity.getClosingDate()); activeDays -= existingEntity.getSuspendedDays() != null ? existingEntity.getSuspendedDays() : 0; existingEntity.setActiveDays(activeDays); + log.debug("Calculated active days for ApplicationEvaluationEntity id {}: {}", existingEntity.getId(), activeDays); } entity = applicationEvaluationRepository.save(existingEntity); assignedApplicationsRepository.save(assignedApplicationsEntity); @@ -1956,15 +1982,20 @@ public class ApplicationEvaluationDao { } public ApplicationEvaluationEntity validateApplicationEvaluationByApplicationId(Long applicationId) { + log.info("Validating ApplicationEvaluation for applicationId: {}", applicationId); return applicationEvaluationRepository .findByApplicationIdAndIsDeletedFalse(applicationId) - .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.APPLICATION_EVALUATION_NOT_FOUND))); + .orElseThrow(() -> { + log.error("ApplicationEvaluation not found for applicationId: {}", applicationId); + return new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_EVALUATION_NOT_FOUND)); + }); } public ApplicationEvaluationResponse updateApplicationEvaluation( Long assignedApplicationId, List docRequest) { + log.info("Starting updateApplicationEvaluation for assignedApplicationId: {}", assignedApplicationId); Optional entityOptional=applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse(assignedApplicationId); ApplicationEvaluationEntity applicationEvaluationEntity =null; ApplicationEvaluationEntity oldApplicationEvaluation = Utils.getClonedEntityForData(entityOptional.get()); @@ -1986,14 +2017,17 @@ public class ApplicationEvaluationDao { applicationEvaluationEntity.setEvaluationDocument(updatedEvaluationDocJson); } ApplicationEvaluationEntity savedEntity = applicationEvaluationRepository.save(applicationEvaluationEntity); + log.info("Saved ApplicationEvaluationEntity with id: {}", savedEntity.getId()); /** This code is responsible for adding a version history log for the "Upload Document in Application Evaluation" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluation).newData(savedEntity).build()); + log.info("Version history logged for update on ApplicationEvaluationEntity id: {}", savedEntity.getId()); return convertToResponse(savedEntity); } public ApplicationEvaluationFormResponse createApplicationEvaluation(HttpServletRequest request, ApplicationEvaluationFormRequestBean applicationEvaluationFormRequestBean, Long evaluationFormId, Long assignedApplicationId){ - + + log.info("Start createApplicationEvaluation - assignedApplicationId: {}, evaluationFormId: {}", assignedApplicationId, evaluationFormId); UserEntity user = validator.validateUser(request); AssignedApplicationsEntity assignedApplicationsEntity = assignedApplicationsService.validateAssignedApplication(assignedApplicationId); ApplicationEntity application = applicationService.validateApplication(assignedApplicationsEntity.getApplication().getId()); @@ -2054,6 +2088,7 @@ public class ApplicationEvaluationDao { String fieldId = requestField.getFieldId(); if (!contentMap.containsKey(fieldId)) { + log.warn("Field ID not found in evaluation form: {}", fieldId); validator.addError(MessageFormat.format(Translator.toLocale(GepafinConstant.FIELD_ID_NOT_FOUND), fieldId)); } @@ -2081,6 +2116,7 @@ public class ApplicationEvaluationDao { ApplicationEvaluationFormEntity applicationEvaluationFormEntity, List applicationEvaluationFormFieldEntities, EvaluationFormEntity evaluationFormEntity,FieldValidator fieldValidator){ + log.debug("Starting createOrUpdateApplicationEvaluationFormField for fieldId: {}", applicationFormFieldRequestBean.getFieldId()); ApplicationEvaluationFormFieldEntity applicationEvaluationFormFieldEntity = new ApplicationEvaluationFormFieldEntity(); validateFileUploadDocuments(applicationFormFieldRequestBean, evaluationFormEntity); VersionActionTypeEnum actionType = VersionActionTypeEnum.INSERT; @@ -2121,6 +2157,7 @@ public class ApplicationEvaluationDao { } private List validateFileUploadDocuments(ApplicationFormFieldRequestBean applicationFormFieldRequestBean, EvaluationFormEntity evaluationFormEntity) { + log.debug("Validating file upload documents for fieldId: {}", applicationFormFieldRequestBean.getFieldId()); List documentIds=null; List contentResponseBeans=evaluationFormDao.convertEvaluationFormEntityToEvaluationFormResponseBean(evaluationFormEntity).getContent(); @@ -2145,6 +2182,9 @@ public class ApplicationEvaluationDao { private List createEvaluationFormFieldResponse( List evaluationFormFieldEntities, ApplicationEvaluationFormEntity applicationEvaluationFormEntity){ + log.info("Starting to create evaluation form field response for EvaluationFormEntity ID: {}", + applicationEvaluationFormEntity.getEvaluationForm().getId()); + List evaluationFormFieldResponseBeans = new ArrayList<>(); List contentResponseBeans =evaluationFormDao.convertEvaluationFormEntityToEvaluationFormResponseBean(applicationEvaluationFormEntity.getEvaluationForm()).getContent(); @@ -2236,6 +2276,7 @@ public class ApplicationEvaluationDao { public ApplicationEvaluationFormResponse getApplicationEvaluationForm(HttpServletRequest request, Long applicationId, Long assignedApplicationId ){ + log.debug("Fetching evaluation form. applicationId: {}, assignedApplicationId: {}", applicationId, assignedApplicationId); if (applicationId == null && assignedApplicationId == null) { throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.EITHER_APPLICATION_ID_OR_ASSIGNED_APPLICATION_ID_MUST_BE_PROVIDED)); } @@ -2464,6 +2505,7 @@ public class ApplicationEvaluationDao { return false; } private void processTechnicalEvaluation(Long applicationId, ApplicationEntity applicationEntity, ApplicationStatusForEvaluation status){ + log.info("Starting technical evaluation processing for applicationId: {}", applicationId); Optional evaluationEntityOpt = applicationEvaluationRepository.findByApplicationIdAndIsDeletedFalse(applicationId); if (evaluationEntityOpt.isPresent()){ ApplicationEvaluationEntity evaluationEntity = evaluationEntityOpt.get(); @@ -2472,9 +2514,10 @@ public class ApplicationEvaluationDao { Integer totalScore = calculateTotalScore(evaluationEntity.getCriteria()); if (totalScore > 40) { applicationEntity.setStatus(status.getValue()); - log.info("Status updated to TECHNICAL_EVALUATION for applicationId: " + applicationId); + log.info("Status updated to TECHNICAL_EVALUATION for applicationId: {}", applicationId); } else{ + log.warn("Insufficient score ({}) for applicationId: {}. Throwing validation exception.", totalScore, applicationId); throw new CustomValidationException(Status.BAD_REQUEST,Translator.toLocale(GepafinConstant.INSUFFICIENT_SCORE_MESSAGE)); } } @@ -2493,10 +2536,11 @@ public class ApplicationEvaluationDao { .mapToInt(obj -> obj.get("score") != null ? ((Number) obj.get("score")).intValue() : 0) .sum(); + log.info("Total score calculated successfully: {}", totalScore); return totalScore; } catch (Exception e) { - log.error(" Error parsing criteria JSON: {}", e.getMessage()); + log.error("Error parsing criteria JSON. Input: {}. Exception: {}", criteriaJson, e.getMessage(), e); return 0; } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index 46af8a26..a12278fe 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -148,10 +148,11 @@ public class AppointmentDao { private static final ThreadLocal threadLocalHubId = new ThreadLocal<>(); public NdgResponse checkNdgForAppointment(Long applicationId) { - + log.info("Starting NDG check for appointment. applicationId: {}", applicationId); ApplicationEntity application = applicationService.validateApplication(applicationId); NdgResponse ndgResponse = new NdgResponse(); if (application.getNdgStatus() != null && application.getNdgStatus().equalsIgnoreCase(GepafinConstant.NDG_IN_PROGRESS)) { + log.warn("NDG generation already in progress. applicationId: {}", applicationId); throw new CustomValidationException(Status.SUCCESS, Translator.toLocale(GepafinConstant.NDG_GENERATION_IS_IN_PROGRESS)); } @@ -161,6 +162,7 @@ public class AppointmentDao { } // Update application status + log.info("Updating NDG status to IN_PROGRESS. applicationId: {}", applicationId); application.setNdgStatus(GepafinConstant.NDG_IN_PROGRESS); applicationRepository.save(application); @@ -168,10 +170,12 @@ public class AppointmentDao { HubEntity hub = hubRepository.findByHubId(application.getHubId()); loginToOdessa(hub, application); startAsyncNdgProcessing(applicationId); + log.info("NDG check initiation completed. applicationId: {}", applicationId); return ndgResponse; } private HubEntity loginToOdessa(HubEntity hub, ApplicationEntity application) { + log.info("Starting login to Odessa. HubId: {}, ApplicationId: {}", hub.getId(), application.getId()); 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(); @@ -181,7 +185,7 @@ public class AppointmentDao { Map body = Collections.emptyMap(); ResponseEntity responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body); if (responseLogin.getStatusCode() == HttpStatus.OK) { - log.info("Login successful to odessa. Parsing response."); + log.info("Login to Odessa successful. Parsing response. HubId: {}", hub.getId()); String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody()); AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson); @@ -193,12 +197,14 @@ public class AppointmentDao { log.info("Saved new authToken and areaCode for Hub."); return hub; } else { + log.error("Login response from Odessa missing tokenId. HubId: {}", hub.getId()); 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.warn("Received 403 Forbidden from Odessa. Attempting to parse error response."); logForbiddenError(); // Extract raw response body @@ -216,6 +222,7 @@ public class AppointmentDao { if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { application.setNdgStatus(GepafinConstant.NDG_FAILED); applicationRepository.save(application); + log.warn("Detected PASSWORD_EXPIRED error during Odessa login. ApplicationId: {}", application.getId()); throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); } @@ -240,7 +247,7 @@ public class AppointmentDao { loginToOdessa(hub, application); } catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); + log.error("Unexpected exception during Odessa login. HubId: {}, Error: {}", hub.getId(), e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); } return null; @@ -280,6 +287,7 @@ public class AppointmentDao { private void processNdgGeneration(Long applicationId) { // Validate application, company, and hub + log.info("Starting NDG generation process for applicationId: {}", applicationId); ApplicationEntity application = applicationService.validateApplication(applicationId); CompanyEntity company = companyService.validateCompany(application.getCompanyId()); HubEntity hub = hubRepository.findByHubId(application.getHubId()); @@ -307,14 +315,15 @@ public class AppointmentDao { handleNdgPolling(application, company, hub, authorizationToken); } } catch (Exception e) { - log.error("Error during NDG generation for applicationId: {}", applicationId, e); + log.error("Exception occurred during NDG generation. ApplicationId: {}, CompanyId: {}, HubId: {}, Error: {}", + applicationId, company.getId(), hub.getId(), e.getMessage(), e); } } private void handleNdgPolling(ApplicationEntity application, CompanyEntity company, HubEntity hub, String authorizationToken) { try { - log.info("Starting NDG polling for applicationId: {}", application.getId()); + log.info("Starting NDG polling for applicationId: {}, CompanyId: {}, HubId: {}", application.getId(),company.getId(), hub.getId()); long startTime = System.currentTimeMillis(); while (true) { @@ -326,12 +335,13 @@ public class AppointmentDao { try { // Fetch Visura list and attempt to parse NDG String visuraListJson = getVisuraList(application.getIdVisura(), authorizationToken, application, hub); + log.debug("Parsing NDG from visura list response | ApplicationId: {}", application.getId()); String ndg = parseNdgFromVisuraListResponse(visuraListJson); - if (isNdgValid(ndg)) { // CompanyEntity oldCompanyData = Utils.getClonedEntityForData(company); // ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(application); + log.info("Valid NDG retrieved: {} | ApplicationId: {}", ndg, application.getId()); company.setNdg(ndg); application.setNdg(ndg); application.setNdgStatus(GepafinConstant.NDG_GENERATED); @@ -397,6 +407,7 @@ public class AppointmentDao { private String getVisuraList(String idVisura, String authorizationToken, ApplicationEntity application, HubEntity hub) { + log.info("Initiating Visura list retrieval | ApplicationId: {}, HubId: {}, IdVisura: {}", application.getId(), hub.getId(), idVisura); AppointmentVisuraListRequest visuraListRequest = new AppointmentVisuraListRequest(); AppointmentVisuraListRequest.VisuraFilter filter = new AppointmentVisuraListRequest.VisuraFilter(); filter.setIdVisura(idVisura); @@ -407,12 +418,12 @@ public class AppointmentDao { ResponseEntity response = appointmentApiService.getVisuraList(requestJson, authorizationToken); return Utils.convertObjectToJson(response.getBody()); } catch (FeignException.Forbidden forbiddenException) { - log.error("403 Forbidden received while getting visuraList for Ndg code. Regenerating token..."); + log.warn("403 Forbidden while fetching Visura list. Attempting token regeneration | ApplicationId: {}, HubId: {}", application.getId(), hub.getId()); // Regenerate the token and retry String newAuthorizationToken = regenerateTokenAndSave(hub); return getVisuraList(idVisura, newAuthorizationToken, application, hub); } catch (Exception e) { - log.error("Failed to fetch Ndg code: {}", e.getMessage(), e); + log.error("Error while fetching Visura list | ApplicationId: {}, HubId: {}, Error: {}", application.getId(), hub.getId(), e.getMessage(), e); throw new RuntimeException("Error fetching Ndg List", e); } } @@ -420,6 +431,7 @@ public class AppointmentDao { private HubEntity authenticateAndSaveToken(HubEntity hub) { try { + log.info("Starting authentication to Odessa | HubId: {}", hub.getId()); //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); @@ -445,12 +457,14 @@ public class AppointmentDao { log.info("Saved new authToken and areaCode for Hub."); return hub; } else { + log.error("Login response missing tokenId | HubId: {}", hub.getId()); 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("403 Forbidden during Odessa login | HubId: {}", hub.getId()); logForbiddenError(); // Extract raw response body @@ -466,6 +480,7 @@ public class AppointmentDao { for (JsonNode error : errorsNode) { // Check the main errorCode if (GepafinConstant.PASSWORD_EXPIRED.equals(error.path("errorCode").asText())) { + log.warn("Odessa password expired detected in login response | HubId: {}", hub.getId()); throw new CustomValidationException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PASSWORD_EXPIRED_LOGIN_TO_ODESSA)); } @@ -481,13 +496,13 @@ public class AppointmentDao { } } } catch (IOException e) { - log.error("Error parsing JSON response: {}", e.getMessage()); + log.error("Error parsing forbidden JSON response | HubId: {}, Error: {}", hub.getId(), e.getMessage(), e); } // Regenerate the token and retry regenerateTokenAndSave(hub); } catch (Exception e) { - log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e); + log.error("Unexpected error during Odessa authentication | HubId: {}, Error: {}", hub.getId(), e.getMessage(), e); throw new RuntimeException("Authentication failed on Odessa. try again", e); } return null; @@ -496,6 +511,7 @@ public class AppointmentDao { private AppointmentLoginResponse retrieveNdgByVatNumber(String vatNumber, String authorizationToken, HubEntity hub, ApplicationEntity application) { try { + log.info("Initiating NDG retrieval by VAT number | ApplicationId: {}, HubId: {}, VAT: {}", application.getId(), hub.getId(), vatNumber); // Prepare the NDG request AppointmentNdgRequest ndgRequest = getAppointmentNdgRequest(vatNumber); // Call the API to retrieve NDG @@ -504,12 +520,13 @@ public class AppointmentDao { // Parse and return the NDG response return parseNdgResponse(responseJson); } catch (FeignException.Forbidden forbiddenException) { + log.error("403 Forbidden during NDG retrieval | ApplicationId: {}, HubId: {}", application.getId(), hub.getId()); logForbiddenError(); // Regenerate the token and retry String newAuthorizationToken = regenerateTokenAndSave(hub); return retrieveNdgByVatNumber(vatNumber, newAuthorizationToken, hub, application); } catch (Exception e) { - log.error("Failed to retrieve NDG by VAT number: {}", e.getMessage(), e); + log.error("Error during NDG retrieval | ApplicationId: {}, HubId: {}, Message: {}", application.getId(), hub.getId(), e.getMessage(), e); throw new RuntimeException("NDG retrieval failed.", e); } } @@ -544,6 +561,7 @@ public class AppointmentDao { private static AppointmentNdgRequest getAppointmentNdgRequest(String vatNumber) { + log.info("Creating Appointment NDG Request | VAT Number: {}", vatNumber); AppointmentNdgRequest request = new AppointmentNdgRequest(); AppointmentNdgRequest.Filter filter = new AppointmentNdgRequest.Filter(); filter.setPartitaIva(vatNumber); @@ -674,6 +692,7 @@ public class AppointmentDao { public AppointmentCreationResponse createAppointment(Long applicationId, CreateAppointmentRequest createAppointmentRequest) { // Validate the application + log.info("Starting appointment creation for applicationId: {}", applicationId); ApplicationEntity application = applicationService.validateApplication(applicationId); AppointmentCreationResponse appointmentCreationResponse = new AppointmentCreationResponse(); @@ -696,6 +715,7 @@ public class AppointmentDao { } if (application.getNdg() == null && Objects.equals(application.getNdgStatus(), GepafinConstant.NDG_IN_PROGRESS)) { + log.warn("NDG in progress but not available for applicationId: {}", applicationId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_NOT_FOUND_FOR_APPLICATION)); } @@ -704,6 +724,7 @@ public class AppointmentDao { String authorizationToken = getBearerToken(hub); Long appointmentTemplateId = application.getCall().getAppointmentTemplateId(); if (appointmentTemplateId == null) { + log.error("Missing appointment template ID for applicationId: {}", applicationId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPOINTMENT_CANNOT_BE_CREATED)); } ResponseEntity response = appointmentApiService.getAppointmentTemplateForTemplateCreation(authorizationToken, appointmentTemplateId); @@ -727,6 +748,7 @@ public class AppointmentDao { String appointmentId = extractAppointmentIdFromResponse(appointmentResponse); if (appointmentId == null) { + log.error("Failed to extract appointment ID from response for applicationId: {}", applicationId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPOINTMENT_NOT_CREATED)); } // Update application with the appointment ID @@ -742,7 +764,7 @@ public class AppointmentDao { return appointmentCreationResponse; } catch (FeignException.Forbidden forbiddenException) { - log.error("403 Forbidden received while retrieving template. Regenerating token..."); + log.error("403 Forbidden received while retrieving template. Attempting to regenerate token and retry. Application ID: {}", applicationId); regenerateTokenAndSave(hub); return createAppointment(applicationId, createAppointmentRequest); } @@ -857,6 +879,7 @@ public class AppointmentDao { } public DocumentUploadResponse uploadDocumentToExternalSystem(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest) { + log.info("Initiating upload to external system for documentId: {}", documentId); // Check if the document is already being processed DocumentEntity systemDoc = documentDao.validateDocument(documentId); @@ -907,6 +930,7 @@ public class AppointmentDao { } private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest) { + log.info("Starting sync document upload for documentId: {}", documentId); // Synchronous upload logic DocumentEntity systemDoc = documentDao.validateDocument(documentId); @@ -937,6 +961,7 @@ public class AppointmentDao { DocumentUploadResponse parsedResponse = parseDocumentUploadResponse(responseData); if (parsedResponse == null) { + log.error("Upload failed: parsed response is null for documentId: {}", documentId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_UPLOADING_DOCUMENT)); } @@ -946,7 +971,7 @@ public class AppointmentDao { log.info("Document uploaded successfully to external system: {}", parsedResponse); } catch (FeignException.Forbidden forbiddenException) { - log.error("403 Forbidden received while uploading document. Regenerating token..."); + log.error("403 Forbidden from external system during upload for documentId: {}. Retrying with new token...", documentId); regenerateTokenAndSave(hub); uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest); } catch (Exception e) { diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java index 17f18c9c..151f8306 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AssignedApplicationsDao.java @@ -87,8 +87,10 @@ public class AssignedApplicationsDao { AssignedApplicationsEntity assignedApplications = assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationId).orElse(null); if (assignedApplications != null && assignedApplications.getUserId().equals(userId)) { + log.warn("Application ID={} is already assigned to User ID={}", applicationId, userId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_ASSIGNED)); } else if(assignedApplications != null) { + log.info("Reassigning Application ID={} from User ID={} to User ID={}", applicationId, assignedApplications.getUserId(), userId); assignedApplications = reassignApplication(userId, assignedByUser, assignedApplications); AssignedApplicationsResponse assignApplicationToInstructorResponse = convertEntityToResponse(assignedApplications); log.info("Application re-assigned succesfully {}", assignApplicationToInstructorResponse); @@ -98,6 +100,7 @@ public class AssignedApplicationsDao { if (Boolean.FALSE.equals(ApplicationStatusTypeEnum.SUBMIT.getValue().equals(application.getStatus()))) { + log.warn("Invalid application status for assignment. Application ID={}, Current Status={}", applicationId, application.getStatus()); throw new CustomValidationException( Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.INVALID_APPLICATION_STATUS) @@ -106,6 +109,7 @@ public class AssignedApplicationsDao { ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(application); application.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); applicationRepository.save(application); + log.info("Application status updated to EVALUATION for Application ID={}", applicationId); /** This code is responsible for adding a version history log for the "Update Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEntity).newData(application).build()); @@ -120,7 +124,10 @@ public class AssignedApplicationsDao { private AssignedApplicationsEntity reassignApplication(Long userId, UserEntity assignedByUser, AssignedApplicationsEntity assignedApplication) { - + + log.info("Starting reassignment for AssignedApplication ID={}, from User ID={} to User ID={}, Assigned By User ID={}", + assignedApplication.getId(), assignedApplication.getUserId(), userId, assignedByUser.getId()); + AssignedApplicationsEntity oldAssignedApplicationEntity = Utils.getClonedEntityForData(assignedApplication); setIfUpdated(assignedApplication::getAssignedBy, assignedApplication::setAssignedBy, assignedByUser.getId()); @@ -135,11 +142,13 @@ public class AssignedApplicationsDao { /** This code is responsible for adding a version history log for the "Create Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(entityOptional.get()).build()); + log.info("Updated ApplicationEvaluationEntity for AssignedApplication ID={}", assignedApplication.getId()); }; assignedApplication = assignedApplicationsRepository.save(assignedApplication); /** This code is responsible for adding a version history log for the "Create Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldAssignedApplicationEntity).newData(assignedApplication).build()); + log.info("Reassignment completed for AssignedApplication ID={}, new User ID={}", assignedApplication.getId(), userId); return assignedApplication; } @@ -220,8 +229,13 @@ public class AssignedApplicationsDao { } public AssignedApplicationsEntity validateAssignedApplication(Long id) { - AssignedApplicationsEntity assignedApplication = assignedApplicationsRepository.findByIdAndIsDeletedFalse(id).orElseThrow(() -> - new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.ASSIGNED_APPLICATION_NOT_FOUND_MSG))); + AssignedApplicationsEntity assignedApplication = assignedApplicationsRepository.findByIdAndIsDeletedFalse(id) .orElseThrow(() -> { + log.warn("AssignedApplication not found or deleted for ID: {}", id); + return new ResourceNotFoundException( + Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.ASSIGNED_APPLICATION_NOT_FOUND_MSG) + ); + }); return assignedApplication; } @@ -232,11 +246,12 @@ public class AssignedApplicationsDao { AssignedApplicationsEntity oldAssignedApplicationEntity = Utils.getClonedEntityForData(assignedApplicationsEntity); assignedApplicationsEntity.setIsDeleted(true); assignedApplicationsEntity = saveAssignedApplication(assignedApplicationsEntity, oldAssignedApplicationEntity, VersionActionTypeEnum.SOFT_DELETE); - log.info("Assigned Application deleted with ID: {}", id); + log.info("Soft-delete completed for AssignedApplication ID: {} by User ID: {}", id, assignedApplicationsEntity.getUserId()); } public List getAllAssignedApplications(HttpServletRequest request, Long userId,List statusList) { - UserEntity user = validator.validateUser(request); + log.info("Fetching all assigned applications. Filtered target userId: {}", userId); + UserEntity user = validator.validateUser(request); if(validator.checkIsPreInstructor() && userId == null) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.USER_ID_NOT_NULL_MSG)); } @@ -303,6 +318,8 @@ public class AssignedApplicationsDao { return response; } public PageableResponseBean> getAllAssignedApplicationsByPagination(UserEntity user, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean,Long userId) { + log.info("Fetching assigned applications. Requestor: {}, Target User: {}", user.getId(), userId); + Integer pageNo = null; Integer pageLimit = null; if (assignedApplicationPageableRequestBean.getGlobalFilters() != null) { @@ -474,13 +491,16 @@ public class AssignedApplicationsDao { } public AssignedApplicationsResponse updateAssignedApplicationStatus(HttpServletRequest request, Long assignedApplicationId, AssignedApplicationEnum status) { - + log.info("Request received to update status of assigned application. AssignedApplicationId: {}, NewStatus: {}", assignedApplicationId, status); AssignedApplicationsEntity assignedApplication = validateAssignedApplication(assignedApplicationId); validator.validatePreInstructor(request, assignedApplication.getUserId()); AssignedApplicationsEntity oldAssignedApplicationEntity = Utils.getClonedEntityForData(assignedApplication); assignedApplication.setStatus(status.getValue()); AssignedApplicationsEntity updatedAssignment = saveAssignedApplication(assignedApplication, oldAssignedApplicationEntity, VersionActionTypeEnum.UPDATE); + log.info("Assigned application status updated successfully. AssignedApplicationId: {}, OldStatus: {}, NewStatus: {}", + assignedApplicationId, oldAssignedApplicationEntity.getStatus(), status.getValue()); + return convertEntityToResponse(updatedAssignment); } private void applyFilters(Root root, CriteriaBuilder criteriaBuilder, List predicates, Map filters) { diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index fa02eac1..4caa970a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -50,6 +50,7 @@ import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundExceptio import net.gepafin.tendermanagement.web.rest.api.errors.Status; import static net.gepafin.tendermanagement.enums.RoleStatusEnum.ROLE_SUPER_ADMIN; +import static net.gepafin.tendermanagement.util.Utils.log; import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.hibernate.internal.util.collections.CollectionHelper.listOf; @@ -128,6 +129,7 @@ public class CallDao { private ApplicationRepository applicationRepository; public CallResponse createCallStep1(CreateCallRequestStep1 createCallRequest, UserEntity userEntity) { + log.info("Starting Call creation - Step 1 by userId: {}", userEntity.getId()); createCallRequest.setRegionId(userEntity.getRoleEntity().getRegion().getId()); CallEntity callEntity = convertToCallEntity(createCallRequest, userEntity); @@ -136,12 +138,15 @@ public class CallDao { CallResponse createCallResponseBean = getCallResponseBean(callEntity); createCallResponseBean.setCurrentStep(GepafinConstant.STEP_1); + log.info("Call creation - Step 1 completed successfully for callId: {}", callEntity.getId()); return createCallResponseBean; } public byte[] downloadCallDocumentsAsZip(Long callId) { + log.info("Starting download of call documents as ZIP for callId: {}", callId); List documents = documentRepository.findBySourceIdAndSourceAndTypeAndIsDeletedFalse(callId, DocumentSourceTypeEnum.CALL.getValue(),DocumentTypeEnum.DOCUMENT.getValue()); if (documents.isEmpty()) { + log.warn("No documents found for callId: {}", callId); throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); } @@ -149,6 +154,7 @@ public class CallDao { ZipOutputStream zos = new ZipOutputStream(zipOutputStream)) { for (DocumentEntity document : documents) { + log.info("Adding document to ZIP: documentId={}, fileName={}", document.getId(), document.getFileName()); String s3Folder = s3PathConfig.generateDocumentPath(DocumentSourceTypeEnum.CALL, callId, 0L,0L); try (InputStream fileInputStream = amazonS3Service.getFile(s3Folder, document.getFilePath())) { String fileName = Utils.extractFileName(document.getFilePath()); @@ -157,14 +163,17 @@ public class CallDao { IOUtils.copy(fileInputStream, zos); zos.closeEntry(); } catch (IOException e) { + log.error("Error downloading or adding document to ZIP. documentId={}, fileName={}", document.getId(), document.getFileName(), e); throw new RuntimeException("Error downloading or adding document to ZIP: " + document.getFileName(), e); } } zos.finish(); + log.info("Successfully created ZIP file for callId: {}", callId); return zipOutputStream.toByteArray(); } catch (IOException e) { + log.error("Error while creating ZIP file for callId: {}", callId, e); throw new RuntimeException("Error while creating ZIP file", e); } } @@ -175,8 +184,11 @@ public class CallDao { CallEntity callEntity = new CallEntity(); // validateCallEntity(createCallRequest); RegionEntity region = regionRepository.findById(createCallRequest.getRegionId()) - .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.REGION_NOT_FOUND))); + .orElseThrow(() -> { + log.error("Region not found for id: {}", createCallRequest.getRegionId()); + return new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.REGION_NOT_FOUND)); + }); + callEntity.setRegion(region); callEntity.setName(createCallRequest.getName()); callEntity.setDescriptionShort(createCallRequest.getDescriptionShort()); @@ -198,6 +210,7 @@ public class CallDao { } callEntity.setDocumentationRequested(createCallRequest.getDocumentationRequested()); if (createCallRequest.getAmountMin() != null && createCallRequest.getAmountMin().compareTo(BigDecimal.ZERO) < 0) { + log.error("Invalid minimum amount: {}", createCallRequest.getAmountMin()); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.AMOUNT_GREATER_THAN_ZERO_MSG)); } callEntity.setAmountMin(createCallRequest.getAmountMin()); @@ -212,6 +225,7 @@ public class CallDao { callEntity.setNumberOfCheck(createCallRequest.getNumberOfCheck()); callEntity.setAppointmentTemplateId(createCallRequest.getAppointmentTemplateId()); callEntity = callRepository.save(callEntity); + log.info("CallEntity saved with ID: {} for call name: '{}'", callEntity.getId(), callEntity.getName()); /** This code is responsible for adding a version history log for the "Create Call" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(callEntity).build()); @@ -237,9 +251,11 @@ public class CallDao { } private void softDeleteEvaluationCriteria(EvaluationCriteriaEntity evaluationCriteriaEntity) { + log.info("Starting soft delete for EvaluationCriteriaEntity with ID: {}", evaluationCriteriaEntity.getId()); EvaluationCriteriaEntity oldEvaluationCriteriaEntity = Utils.getClonedEntityForData(evaluationCriteriaEntity); evaluationCriteriaEntity.setIsDeleted(true); evaluationCriteriaRepository.save(evaluationCriteriaEntity); + log.info("Soft deleted EvaluationCriteriaEntity with ID: {}", evaluationCriteriaEntity.getId()); /** This code is responsible for adding a version history log for the "soft delete evaluation criteria" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldEvaluationCriteriaEntity).newData(evaluationCriteriaEntity).build()); @@ -256,8 +272,8 @@ public class CallDao { /** This code is responsible for adding a version history log for the "soft delete criteria form field" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.SOFT_DELETE).oldData(oldCriteriaFormFieldEntity).newData(data).build()); }); - criteriaFormFieldRepository.saveAll(list); - + criteriaFormFieldRepository.saveAll(list); + log.info("Soft deleted all linked CriteriaFormFieldEntity records for EvaluationCriteriaEntity ID: {}", evaluationCriteriaEntity.getId()); } } @@ -327,8 +343,11 @@ public class CallDao { private DocumentEntity convertToDocumentEntity(DocumentReq documentReq,Long sourceId) { validateDocumentEntity(documentReq.getId()); DocumentEntity documentEntity = documentRepository.findByIdAndSourceIdAndSourceAndIsDeletedFalse(documentReq.getId(),sourceId, DocumentSourceTypeEnum.CALL.getValue()) - .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND))); + .orElseThrow(() -> { + log.error("Document not found or already deleted. Document ID: {}, Source ID: {}", documentReq.getId(), sourceId); + return new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); + }); return documentEntity; } @@ -353,6 +372,7 @@ public class CallDao { public void validateDocumentEntity(Long documentId) { if (documentId == null || documentId < 1) { + log.warn("Invalid Document ID provided: {}", documentId); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.DOCUMENT_ID_NOT_FOUND)); } @@ -491,13 +511,16 @@ public class CallDao { } public CallEntity validateCall(Long callId) { - return callRepository.findById(callId).orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.CALL_NOT_FOUND))); + return callRepository.findById(callId).orElseThrow(() -> { log.error("Call not found for ID: {}", callId); + return new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.CALL_NOT_FOUND)); + }); } public CallResponse getCallById(HttpServletRequest request,UserEntity user, CallEntity callEntity, Long companyId) { Long userId = user.getId(); Long callId = callEntity.getId(); + log.info("Fetching Call details for Call ID: {}, User ID: {}, Company ID: {}", callId, userId, companyId); BeneficiaryPreferredCallEntity preferredCall; if (companyId != null) { @@ -523,10 +546,13 @@ public class CallDao { public CallResponse createCallStep2(CallEntity callEntity, CreateCallRequestStep2 createCallRequest, UserEntity user) { // validateUpdate(callEntity); + log.info("Starting Call Step 2 update for Call ID: {}, User ID: {}", callEntity.getId(), user.getId()); if(createCallRequest.getThreshold() != null && Boolean.FALSE.equals(createCallRequest.getThreshold().equals(callEntity.getThreshold()))) { CallEntity oldCallEntity = Utils.getClonedEntityForData(callEntity); setIfUpdated(callEntity::getThreshold, callEntity::setThreshold, createCallRequest.getThreshold()); callEntity = callRepository.save(callEntity); + + log.info("Updated threshold for Call ID: {}", callEntity.getId()); /** This code is responsible for adding a version history log for the "update call step 2" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCallEntity).newData(callEntity).build()); @@ -546,6 +572,7 @@ public class CallDao { public void validateUpdate(CallEntity callEntity) { if(callEntity.getStatus().equals(CallStatusEnum.PUBLISH.getValue())) { + log.warn("Attempted update on published call. Call ID: {}", callEntity.getId()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PUBLISHED_CALL_NOT_UPDATE)); } @@ -574,12 +601,14 @@ public class CallDao { } if (Boolean.FALSE.equals(isValid)) { + log.error("Invalid date range detected for Call ID: {}", callEntity.getId()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_DATE_MSG)); } } public CallResponse updateCallStep1(HttpServletRequest request,CallEntity callEntity, UpdateCallRequestStep1 updateCallRequest, UserEntity userEntity) { + log.info("Updating Call ID: {}, by User ID: {}", callEntity.getId(),userEntity.getId() ); CallEntity oldCallEntity = Utils.getClonedEntityForData(callEntity); isValidDateRange(updateCallRequest, callEntity); setIfUpdated(callEntity::getName, callEntity::setName, updateCallRequest.getName()); @@ -639,9 +668,11 @@ public class CallDao { updateCallRequest.getDocumentationRequested()); if (updateCallRequest.getAmountMin() != null && updateCallRequest.getAmountMin().compareTo(BigDecimal.ZERO) < 0) { + log.error("Validation failed: Invalid email {} for Call ID: {}", updateCallRequest.getEmail(), callEntity.getId()); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.AMOUNT_GREATER_THAN_ZERO_MSG)); } if(updateCallRequest.getEmail()!=null && Boolean.FALSE.equals(Utils.isValidEmail(updateCallRequest.getEmail()))){ + log.error("Validation failed: Invalid email {} for Call ID: {}", updateCallRequest.getEmail(), callEntity.getId()); throw new CustomValidationException(Status.VALIDATION_ERROR,Translator.toLocale(GepafinConstant.VALIDATION_EMAIL,updateCallRequest.getEmail())); } setIfUpdated(callEntity::getAmountMin, callEntity::setAmountMin, updateCallRequest.getAmountMin()); @@ -661,6 +692,7 @@ public class CallDao { updateFaq(updateCallRequest.getFaq(), callEntity, userEntity, LookUpDataTypeEnum.FAQ); CallResponse createCallResponseBean = getCallResponseBean(callEntity); createCallResponseBean.setCurrentStep(GepafinConstant.STEP_1); + log.info("Call Step 1 update completed for Call ID: {}", callEntity.getId()); return createCallResponseBean; } @@ -764,6 +796,7 @@ public class CallDao { } private CallResponse getCallResponseBean(CallEntity callEntity) { + log.info("Building CallResponse for Call ID: {}", callEntity.getId()); List documentEntities = documentRepository.findBySourceIdAndSourceAndTypeAndIsDeletedFalse(callEntity.getId(),DocumentSourceTypeEnum.CALL.getValue() , DocumentTypeEnum.DOCUMENT.getValue()); List imageEntities = documentRepository.findBySourceIdAndSourceAndTypeAndIsDeletedFalse(callEntity.getId(), DocumentSourceTypeEnum.CALL.getValue() @@ -790,6 +823,9 @@ public class CallDao { public List getAllCalls(HttpServletRequest request,UserEntity user, Long companyId,Boolean onlyPreferredCall,Boolean onlyConfidiCall) { String type = user.getRoleEntity().getRoleType(); + log.info("Fetching calls for User ID: {}, Role: {}, Company ID: {}, onlyPreferredCall: {}, onlyConfidiCall: {}", + user.getId(), type, companyId, onlyPreferredCall, onlyConfidiCall); + List callStatusList = CallStatusEnum.getStatusValues(); if (Boolean.FALSE.equals(ROLE_SUPER_ADMIN.getValue().equals(type))) { callStatusList = List.of(CallStatusEnum.PUBLISH.getValue()); @@ -811,6 +847,7 @@ public class CallDao { call.getEndDate() != null && call.getEndTime() != null) { LocalDateTime callEndDateTime = LocalDateTime.of(LocalDate.from(call.getEndDate()), call.getEndTime()); if (callEndDateTime.isBefore(now)) { + log.info("Call ID: {} has expired. Updating status from PUBLISH to EXPIRED.", call.getId()); call.setStatus(CallStatusEnum.EXPIRED.getValue()); callRepository.save(call); } @@ -846,14 +883,17 @@ public class CallDao { } public Map getBeneficiaryPreferredCallsForUser(HttpServletRequest request, UserEntity user, List callIds, Long companyId) { + log.info("Fetching preferred calls for User ID: {}, Company ID: {}, Call IDs: {}", user.getId(), companyId, callIds); List beneficiaryPreferredCalls; if (companyId != null && (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi()))) { + log.info("Validating user with company for preferred calls: User ID: {}, Company ID: {}", user.getId(), companyId); validator.validateUserWithCompany(request, companyId); UserWithCompanyEntity userWithCompanyEntity=companyService.getUserWithCompany(user.getId(),companyId); beneficiaryPreferredCalls = beneficiaryPreferredCallRepository .findByUserIdAndCallIdInAndUserWithCompanyIdAndIsDeletedFalse(user.getId(), callIds, userWithCompanyEntity.getId()); } else { + log.info("Fetching preferred calls without company filtering for User ID: {}", user.getId()); beneficiaryPreferredCalls = beneficiaryPreferredCallRepository .findByUserIdAndCallIdInAndIsDeletedFalse(user.getId(), callIds); beneficiaryPreferredCalls = beneficiaryPreferredCalls.stream() @@ -877,6 +917,7 @@ public class CallDao { public CallResponse validateCallData(CallEntity callEntity) { + log.info("Starting call validation for Call ID: {}, Current Status: {}", callEntity.getId(), callEntity.getStatus()); CallEntity oldCallEntity = Utils.getClonedEntityForData(callEntity); validateUpdate(callEntity); CallResponse callResponseBean = getCallResponseBean(callEntity); @@ -886,6 +927,7 @@ public class CallDao { CallValidatorServiceImpl.validateResponse(callResponseBean,flowResponseBean,formResponseBean,evaluationFormResponseBean); callEntity.setStatus(CallStatusEnum.READY_TO_PUBLISH.getValue()); callEntity = callRepository.save(callEntity); + log.info("Call status updated to READY_TO_PUBLISH for Call ID: {}", callEntity.getId()); /** This code is responsible for adding a version history log for the "validate call" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCallEntity).newData(callEntity).build()); @@ -903,11 +945,13 @@ public class CallDao { // } public CallResponse updateCallStatus(CallEntity callEntity, CallStatusEnum statusReq) { + log.info("Updating call status for Call ID: {} from {} to {}", callEntity.getId(), callEntity.getStatus(), statusReq); CallEntity oldCallEntity = Utils.getClonedEntityForData(callEntity); CallStatusEnum currentStatus = CallStatusEnum.valueOf(callEntity.getStatus()); validateStatusChange(currentStatus, statusReq, callEntity.getId()); callEntity.setStatus(statusReq.getValue()); callEntity = callRepository.save(callEntity); + log.info("Call status updated in DB for Call ID: {}. New Status: {}", callEntity.getId(), callEntity.getStatus()); //Creating notification. List userIds = beneficiaryRepository.findUserIdsByHubIdAndBeneficiaryId(callEntity.getHub().getId()); @@ -926,27 +970,32 @@ public class CallDao { } private void validateStatusChange(CallStatusEnum currentStatus, CallStatusEnum newStatus, Long callId) { - + log.info("Validating status change for Call ID: {} from '{}' to '{}'", callId, currentStatus, newStatus); if (currentStatus == newStatus) { + log.warn("Validation failed: current status and new status are the same for Call ID: {}", callId); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.STATUS_SAME_ERROR)); } switch (currentStatus) { case DRAFT: if (newStatus == CallStatusEnum.READY_TO_PUBLISH || newStatus == CallStatusEnum.PUBLISH) { + log.warn("Invalid status change attempt from DRAFT to {} for Call ID: {}", newStatus, callId); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_DRAFT)); } break; case PUBLISH: if (newStatus == CallStatusEnum.READY_TO_PUBLISH) { + log.warn("Invalid status change attempt from PUBLISH to READY_TO_PUBLISH for Call ID: {}", callId); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_PUBLISH)); } if (newStatus == CallStatusEnum.DRAFT && Boolean.TRUE.equals(applicationRepository.existsByCallId(callId))) { + log.warn("Invalid status change attempt from PUBLISH to DRAFT for Call ID: {} due to existing applications", callId); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_PUBLISH_TO_DRAFT)); } break; case EXPIRED: + log.warn("Attempt to change status from EXPIRED for Call ID: {} which is not allowed", callId); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.STATUS_CANNOT_BE_CHANGED)); case READY_TO_PUBLISH: @@ -957,9 +1006,11 @@ public class CallDao { } public CallEntity validatePublishedCall(Long callId, Long hubId) { + log.info("Validating published call for Call ID: {}, Hub ID: {}", callId, hubId); CallEntity callEntity= callRepository .findByIdAndStatusAndHubId(callId, CallStatusEnum.PUBLISH.getValue(), hubId); if(callEntity==null){ + log.warn("No published call found with Call ID: {} and Hub ID: {}", callId, hubId); throw new ResourceNotFoundException( Status.NOT_FOUND, Translator.toLocale(GepafinConstant.CALL_NOT_PUBLISHED)); @@ -969,6 +1020,7 @@ public class CallDao { if (currentDate.isBefore(callEntity.getStartDate().toLocalDate()) || (currentDate.isEqual(callEntity.getStartDate().toLocalDate()) && currentTime.isBefore(callEntity.getStartTime()))) { + log.warn("Call ID: {} has not started yet. Current time is before start time.", callId); throw new CustomValidationException( Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.CALL_NOT_STARTED_YET) @@ -977,6 +1029,7 @@ public class CallDao { if (currentDate.isAfter(callEntity.getEndDate().toLocalDate()) || (currentDate.isEqual(callEntity.getEndDate().toLocalDate()) && currentTime.isAfter(callEntity.getEndTime()))) { + log.warn("Call ID: {} has already ended. Current time is after end time.", callId); throw new CustomValidationException( Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.CALL_ALREADY_ENDED) @@ -987,6 +1040,7 @@ public class CallDao { } public PageableResponseBean> getAllCallsByPagination(HttpServletRequest request,UserEntity user,Long companyId , Boolean onlyPreferredCall, CallPageableRequestBean callPageableRequestBean) { + log.info("Fetching paginated calls for userId={}, companyId={}, onlyPreferredCall={}", user.getId(), companyId, onlyPreferredCall); Integer pageNo = null; Integer pageLimit = null; if (callPageableRequestBean.getGlobalFilters() != null) { @@ -1009,6 +1063,7 @@ public class CallDao { Specification spec = search(request,user, callPageableRequestBean); Page entityPage; if (Boolean.TRUE.equals(onlyPreferredCall)) { + log.debug("Filtering calls for preferred by userId={} and companyId={}", user.getId(), companyId); validator.validateUserWithCompany(request, companyId); UserWithCompanyEntity userWithCompanyEntity = companyService.getUserWithCompany(user.getId(), companyId); List preferredCalls = beneficiaryPreferredCallRepository @@ -1171,6 +1226,8 @@ public class CallDao { LocalDate currentDate = DateTimeUtil.DateServerToUTC(LocalDateTime.now()).toLocalDate(); LocalTime currentTime = DateTimeUtil.LocalTimeServerToEurope(LocalTime.now()); + + log.info("Checking for expired published calls at date={}, time={}", currentDate, currentTime); List expirdedCallList = callRepository.findExpiredCallsWhichIsPublished(CallStatusEnum.PUBLISH.getValue(), currentDate, currentTime); @@ -1321,7 +1378,7 @@ public class CallDao { public CallResponse createCallStep2EvaluationV2(CallEntity callEntity, CreateCallRequestStep2EvaluationV2 createCallRequest, UserEntity user) { - + log.info("Starting Step 2 Evaluation (V2) for Call ID={}, User ID={}", callEntity.getId(), user.getId()); convertToDocumentEntities(createCallRequest.getDocs(), callEntity.getId(), DocumentTypeEnum.DOCUMENT); convertToDocumentEntities(createCallRequest.getImages(), callEntity.getId(), DocumentTypeEnum.IMAGES); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 91a589e7..9cf2e0e2 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -73,6 +73,7 @@ public class CompanyDao { public CompanyResponse createCompany(UserEntity userEntity, CompanyRequest companyRequest) { + log.info("Initiating company creation by userId: {}", userEntity.getId()); CompanyEntity existingCompany = companyRepository.findByVatNumberAndHubId(companyRequest.getVatNumber(), userEntity.getHub().getId()); UserWithCompanyEntity userWithCompanyEntity = null; if (existingCompany != null) { @@ -84,6 +85,7 @@ public class CompanyDao { loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(userWithCompanyEntity).build()); } else { + log.warn("User already connected to company. userId: {}, companyId: {}", userEntity.getId(), existingCompany.getId()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.USER_ALREADY_CONNECTED_TO_COMPANY)); } return convertCompanyEntityToCompanyResponse(existingCompany, userWithCompanyEntity); @@ -121,6 +123,7 @@ public class CompanyDao { private UserWithCompanyEntity createUserWithCompanyRelation(UserEntity userEntity, CompanyEntity companyEntity, Boolean isLegalRepresentant,CompanyRequest companyRequest) { + log.info("Creating user-company relation. userId: {}, companyId: {}, isLegalRep: {}", userEntity.getId(), companyEntity.getId(), isLegalRepresentant); UserWithCompanyEntity userWithCompanyEntity = new UserWithCompanyEntity(); if (userEntity.getBeneficiary() != null) { userWithCompanyEntity.setBeneficiaryId(userEntity.getBeneficiary().getId()); @@ -140,6 +143,7 @@ public class CompanyDao { companyEntity.setJson(Utils.convertMapIntoJsonString(companyRequest.getVatCheckResponse())); updateCodiceAtecoFieldWithNewJson(companyEntity); companyEntity = companyRepository.save(companyEntity); + log.info("Updated company JSON field and saved. companyId: {}", companyEntity.getId()); /** This code is responsible for adding a version history log for "updating company json field" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder() @@ -202,6 +206,7 @@ public class CompanyDao { public CompanyResponse updateCompany(UserEntity userEntity, Long companyId, CompanyRequest companyRequest) { + log.info("Updating company. companyId: {}, userId: {}", companyId, userEntity.getId()); CompanyEntity companyEntity = validateCompany(companyId); //cloned entity for old data CompanyEntity oldCompanyData = Utils.getClonedEntityForData(companyEntity); @@ -226,11 +231,14 @@ public class CompanyDao { // // } companyRepository.save(companyEntity); + log.info("Company updated and saved. companyId: {}", companyEntity.getId()); /** This code is responsible for adding a version history log for the "Update company" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCompanyData).newData(companyEntity).build()); + log.info("Logged version history for company update. companyId: {}", companyEntity.getId()); + UserWithCompanyEntity userWithCompanyEntity = getUserWithCompany(userEntity.getId(), companyId); //cloned entity for old data UserWithCompanyEntity oldUserWithCompanyData = Utils.getClonedEntityForData(userWithCompanyEntity); @@ -253,17 +261,19 @@ public class CompanyDao { } public CompanyEntity validateCompany(Long companyId) { + log.info("Validating company. companyId: {}", companyId); return companyRepository.findById(companyId).orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.COMPANY_NOT_FOUND_MSG))); } public CompanyResponse getCompany(UserEntity userEntity, Long companyId) { + log.info("Fetching company details. userId: {}, companyId: {}", userEntity.getId(), companyId); UserWithCompanyEntity userWithCompanyEntity = getUserWithCompany(userEntity.getId(), companyId); return convertCompanyEntityToCompanyResponse(validateCompany(companyId), userWithCompanyEntity); } public void deleteCompany(UserEntity userEntity, Long companyId) { - + log.info("Deleting company. userId: {}, companyId: {}", userEntity.getId(), companyId); CompanyEntity companyEntity = validateCompany(companyId); /** This code is responsible for adding a version history log for the "delete company" operation. **/ @@ -281,6 +291,7 @@ public class CompanyDao { } public List getCompanyByUserId(Long userId) { + log.info("Fetching companies by userId: {}", userId); UserEntity userEntity = userService.validateUser(userId); List activeCompanyIds = userWithCompanyRepository.findActiveCompanyIdsByUserId(userEntity.getId()); List companies = companyRepository.findByIdInAndHubId(activeCompanyIds, userEntity.getHub().getId()); @@ -291,15 +302,18 @@ public class CompanyDao { } public UserWithCompanyEntity validateUserWithCompny(Long userId, Long companyId) { + log.info("Validating user-company access. userId: {}, companyId: {}", userId, companyId); return userWithCompanyRepository.findByUserIdAndCompanyIdAndIsDeletedFalse(userId, companyId).orElseThrow(() -> new ForbiddenAccessException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PERMISSION_DENIED))); } public UserWithCompanyEntity getUserWithCompany(Long userId, Long compnayId) { + log.info("Fetching user-company relation. userId: {}, companyId: {}", userId, compnayId); return userWithCompanyRepository.findByUserIdAndCompanyIdAndIsDeletedFalse(userId, compnayId).orElseThrow( () -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_COMPANY_RELATION_NOT_FOUND))); } public void removeCompanyFromList(UserEntity userEntity, Long companyId) { + log.info("Initiating removal of company from user list. userId: {}, companyId: {}", userEntity.getId(), companyId); CompanyEntity companyEntity = validateCompany(companyId); UserWithCompanyEntity existingRelation=companyService.getUserWithCompany(userEntity.getId(),companyEntity.getId()); List userApplications = applicationRepository.findByUserWithCompanyIdAndUserIdAndIsDeletedFalse(existingRelation.getId(), userEntity.getId()); @@ -314,6 +328,7 @@ public class CompanyDao { boolean notAllowedStatus = userApplications.stream() .anyMatch(application -> !applicationStatusAllowed.contains(application.getStatus())); if (notAllowedStatus) { + log.warn("Cannot remove company. One or more applications in non-removable status. userId: {}, companyId: {}", userEntity.getId(), companyId); throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.CANNOT_DELETE_COMPANY_WITH_APPLICATION_SUBMITT)); } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java index 53a1f410..acf12515 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDocumentDao.java @@ -92,16 +92,20 @@ public class CompanyDocumentDao { private AmazonS3 amazonS3; public List uploadFileForCompany(HttpServletRequest request, Long userId, List files, Long companyId, Long documentCategoryId, CompanyDocumentTypeEnum companyDocumentSourceTypeEnum, LocalDateTime expirationDate,String name){ + + log.info("Uploading files for company. userId={}, companyId={}, documentCategoryId={}", userId, companyId, documentCategoryId); DocumentCategoryEntity categoryEntity = categoryDao.validateCategory(documentCategoryId); validator.validateUserWithCompany(request,companyId); UserWithCompanyEntity userWithCompanyEntity=companyService.getUserWithCompany(userId,companyId); LocalDateTime currentDate = LocalDateTime.now(); if (expirationDate.isBefore(currentDate)) { + log.warn("Expiration date {} is before current time {}", expirationDate, currentDate); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_EXPIRATION_DATE)); } List companyDocumentEntities = new ArrayList<>(); for (MultipartFile file : files){ + log.info("Uploading file '{}' for companyId={}", file.getOriginalFilename(), companyId); UploadFileOnAmazonS3Response uploadFileOnAmazonS3Response = uploadFileOnAmazonS3(file, companyDocumentSourceTypeEnum, companyId); if (uploadFileOnAmazonS3Response != null) { CompanyDocumentEntity companyDocumentEntity = new CompanyDocumentEntity(); @@ -114,8 +118,10 @@ public class CompanyDocumentDao { companyDocumentEntity.setName(name); if (expirationDate.isBefore(currentDate.plusDays(7))) { companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.DUE.getValue()); + log.info("Document '{}' marked as DUE (expires within 7 days).", uploadFileOnAmazonS3Response.getFileName()); } else { companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.VALID.getValue()); + log.info("Document '{}' marked as VALID.", uploadFileOnAmazonS3Response.getFileName()); } companyDocumentEntity.setCategoryEntity(categoryEntity); @@ -125,9 +131,9 @@ public class CompanyDocumentDao { } } companyDocumentRepository.saveAll(companyDocumentEntities); + log.info("Saved {} documents for companyId={}", companyDocumentEntities.size(), companyId); /** This code is responsible for adding a version history log for the "Upload company document" operation. **/ - companyDocumentEntities.forEach(entity -> loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(entity).build())); @@ -143,6 +149,7 @@ public class CompanyDocumentDao { log.info("Generated S3 path {}", s3Path); return amazonS3Service.uploadFileOnAmazonS3(s3Path, file); } catch (Exception e) { + log.error("Error occurred while uploading file '{}' for Company ID '{}': {}", file.getOriginalFilename(), companyId, e.getMessage()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); } } @@ -151,13 +158,17 @@ public class CompanyDocumentDao { try { return s3ConfigBean.generateCompanyDocumentPath(typeOfDocument, companyId); } catch (IllegalArgumentException e) { + log.error("Failed to generate S3 path for Company ID '{}' and Document Type '{}': {}", companyId, typeOfDocument, e.getMessage()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.S3_PATH_GENERATION_ERROR_MSG)); } } public CompanyDocumentEntity validateCompanyDocument(Long id) { - return companyDocumentRepository.findByIdAndNotDeleted(id).orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_NOT_FOUND))); + return companyDocumentRepository.findByIdAndNotDeleted(id).orElseThrow(() -> { + log.warn("Company Document not found with ID '{}'", id); + return new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.COMPANY_DOCUMENT_NOT_FOUND)); + }); } public CompanyDocumentResponseBean convertToCompanyDocumentResponseBean(CompanyDocumentEntity entity) { @@ -182,20 +193,23 @@ public class CompanyDocumentDao { } public CompanyDocumentResponseBean updateCompanyDocument(HttpServletRequest request,Long companyDocumentId, CompanyDocumentRequest companyDocumentRequest){ - + log.info("Start: Updating company document with ID: {}", companyDocumentId); CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId); validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId()); CompanyDocumentEntity oldCompanyDocumentData = Utils.getClonedEntityForData(companyDocumentEntity); LocalDateTime currentDate = LocalDateTime.now(); if (companyDocumentRequest.getExpirationDate() != null) { if (companyDocumentRequest.getExpirationDate().isBefore(currentDate)) { + log.warn("Invalid expiration date: {}", companyDocumentRequest.getExpirationDate()); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_EXPIRATION_DATE)); } companyDocumentEntity.setExpirationDate(companyDocumentRequest.getExpirationDate()); if (companyDocumentRequest.getExpirationDate().isBefore(currentDate.plusDays(7))) { companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.DUE.getValue()); + log.info("Document '{}' marked as DUE.", companyDocumentEntity.getName()); } else { companyDocumentEntity.setStatus(CompanyDocumentStatusEnum.VALID.getValue()); + log.info("Document '{}' marked as VALID (expiration is beyond 7 days).", companyDocumentEntity.getName()); } } if (companyDocumentRequest.getCategoryId() != null && companyDocumentRequest.getCategoryId() >0) { @@ -204,6 +218,7 @@ public class CompanyDocumentDao { } setIfUpdated(companyDocumentEntity::getName, companyDocumentEntity::setName, companyDocumentRequest.getName()); companyDocumentRepository.save(companyDocumentEntity); + log.info("Saved updates for Company Document ID '{}'", companyDocumentId); /** This code is responsible for adding a version history log for the "updating company document" operation. **/ loggingUtil.addVersionHistory( @@ -213,12 +228,14 @@ public class CompanyDocumentDao { } public CompanyDocumentResponseBean getCompanyDocument(UserEntity user ,Long companyDocumentId) { + log.info("Fetching company document with ID '{}' for user '{}'", companyDocumentId, user.getId()); CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId); validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId()); return convertToCompanyDocumentResponseBean(companyDocumentEntity); } public void deleteCompanyFile(Long companyDocumentId){ + log.info("Deleting file for company document ID '{}'", companyDocumentId); CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId); deleteCompanyFileFromS3(companyDocumentEntity); } @@ -259,6 +276,7 @@ public class CompanyDocumentDao { } public DocumentResponseBean createDuplicateCompanyDocument(HttpServletRequest request , Long userId ,Long companyDocumentId , Long applicationId , DocumentTypeEnum documentTypeEnum){ + log.info("Creating duplicate of company document ID '{}' for application ID '{}'", companyDocumentId, applicationId); ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); CompanyDocumentEntity companyDocumentEntity = validateCompanyDocument(companyDocumentId); validator.validateUserWithCompany(request,companyDocumentEntity.getCompanyId()); @@ -272,7 +290,7 @@ public class CompanyDocumentDao { try { response = amazonS3ServiceImpl.copyFile(companyDocumentEntity.getName(), companyDocumentPath, documentPath); } catch (Exception e) { - log.error("Error occurred while uploading file from Amazon S3: {}", e); + log.error("Error occurred while uploading file from Amazon S3: {} for application ID '{}' and company Document ID '{}' ", e,applicationId,companyDocumentId); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); } @@ -296,12 +314,14 @@ public class CompanyDocumentDao { } public List getAllCompanyDocument(UserEntity user , Long companyId, CompanyDocumentTypeEnum typeEnum){ + log.info("Fetching all company documents for Company ID '{}', User ID '{}', Type '{}'", companyId, user.getId(), typeEnum); validator.validateUserWithCompany(request, companyId); companyService.validateCompany(companyId); Specification spec = filterCompanyDocuments(companyId, user.getId(), typeEnum); List companyDocumentEntities = companyDocumentRepository.findAll(spec); + log.info("Retrieved all documents for Company ID '{}'", companyId); return companyDocumentEntities.stream() .map(this::convertToCompanyDocumentResponseBean) .collect(Collectors.toList()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java index 81400797..3b5b41f6 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java @@ -82,10 +82,11 @@ public class DocumentDao { // private String s3Folder; public List uploadFiles(Long userId,List files, Long sourceId, DocumentSourceTypeEnum sourceType, DocumentTypeEnum fileType) { - + log.info("Uploading files userId={}, sourceType={}, fileType={}", userId,sourceType,fileType); List documentEntities = new ArrayList<>(); Long source = resolveSourceId(sourceId, sourceType); for (MultipartFile file : files) { + log.info("Uploading file '{}'", file.getOriginalFilename()); UploadFileOnAmazonS3Response uploadFileOnAmazonS3Response = uploadFileOnAmazonS3(file, sourceType, sourceId); if (uploadFileOnAmazonS3Response != null) { DocumentEntity documentEntity = new DocumentEntity(); @@ -148,6 +149,7 @@ public class DocumentDao { private UploadFileOnAmazonS3Response uploadFileOnAmazonS3(MultipartFile file, DocumentSourceTypeEnum type, Long sourceId) { + log.info("Starting S3 upload: fileName={}, documentType={}, sourceId={}", file.getOriginalFilename(), type, sourceId); Long applicationId = 0L; Long amendmentId = 0L; Long evaluationId = 0L; @@ -155,26 +157,32 @@ public class DocumentDao { if (type == DocumentSourceTypeEnum.APPLICATION) { applicationId = sourceId; callId = applicationRepository.findCallIdById(applicationId); + log.info("Processing document of type APPLICATION .Resolved applicationId={}, callId={}", applicationId, callId); } else if (type == DocumentSourceTypeEnum.AMENDMENT) { amendmentId = sourceId; ApplicationEntity applicationEntity = applicationAmendmentRequestRepository.findApplicationByAmendmentId(amendmentId); applicationId = applicationEntity.getId(); callId = applicationEntity.getCall().getId(); + log.info("Processing document of type AMENDMENT .Resolved amendmentId={}, applicationId={}, callId={}", amendmentId, applicationId, callId); }else if (type == DocumentSourceTypeEnum.EVALUATION) { evaluationId = sourceId; ApplicationEntity applicationEntity = applicationEvaluationRepository.findApplicationByEvaluationId(evaluationId); applicationId = applicationEntity.getId(); callId = applicationEntity.getCall().getId(); + log.info("Processing document of type EVALUATION .Resolved evaluationId={}, applicationId={}, callId={}", evaluationId, applicationId, callId); } try { String s3Path = generateS3Path(type, callId, applicationId, amendmentId); log.info("Generated S3 path {}", s3Path); return amazonS3Service.uploadFileOnAmazonS3(s3Path, file); } catch (Exception e) { + log.error("Error uploading file to S3: fileName={}, documentType={}, sourceId={}, error={}", + file.getOriginalFilename(), type, sourceId, e.getMessage(), e); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); } } + public String generateS3Path(DocumentSourceTypeEnum typeOfDocument, Long callId, Long applicationId, Long amendmentId) { try { return s3ConfigBean.generateDocumentPath(typeOfDocument, callId, applicationId, amendmentId); @@ -202,6 +210,7 @@ public class DocumentDao { DocumentEntity documentEntity = documentRepository.findById(documentId).orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND))); if(Boolean.TRUE.equals(documentEntity.getIsDeleted())){ + log.info("Document with id={} is already marked as deleted. Skipping deletion.", documentId); return; } Long callId = null; @@ -211,24 +220,28 @@ public class DocumentDao { if (DocumentSourceTypeEnum.CALL.getValue().equalsIgnoreCase(documentEntity.getSource())) { callId = documentEntity.getSourceId(); + log.info("Processing document of type CALL. Resolved callId={}", callId); } else if (DocumentSourceTypeEnum.APPLICATION.getValue().equalsIgnoreCase(documentEntity.getSource())) { applicationId = documentEntity.getSourceId(); ApplicationEntity applicationEntity = applicationService.validateApplication(applicationId); callId = applicationEntity.getCall().getId(); + log.info("Processing document of type APPLICATION. Resolved applicationId={}, callId={}", applicationId, callId); } else if(DocumentSourceTypeEnum.AMENDMENT.getValue().equalsIgnoreCase(documentEntity.getSource())){ amendmentId = documentEntity.getSourceId(); ApplicationEntity applicationEntity = applicationAmendmentRequestRepository.findApplicationByAmendmentId(amendmentId); applicationId = applicationEntity.getId(); callId = applicationEntity.getCall().getId(); + log.info("Processing document of type AMENDMENT. Resolved amendmentId={}, applicationId={}, callId={}", amendmentId, applicationId, callId); } else if(DocumentSourceTypeEnum.EVALUATION.getValue().equalsIgnoreCase(documentEntity.getSource())){ evaluationId = documentEntity.getSourceId(); ApplicationEntity applicationEntity = applicationEvaluationRepository.findApplicationByEvaluationId(evaluationId); applicationId = applicationEntity.getId(); callId = applicationEntity.getCall().getId(); + log.info("Processing document of type EVALUATION. Resolved evaluationId={}, applicationId={}, callId={}", evaluationId, applicationId, callId); } deleteFileFromS3(documentEntity, callId, applicationId,amendmentId); - + log.info("Successfully deleted file from S3 for documentId={}", documentId); } public DocumentEntity validateDocument(Long id) { @@ -238,6 +251,9 @@ public class DocumentDao { public DocumentResponseBean updateDocument(Long documentId, MultipartFile file, DocumentTypeEnum documentTypeEnum) { + log.info("Starting document update: documentId={} , newDocumentType={}", + documentId , documentTypeEnum); + DocumentEntity documentEntity = validateDocument(documentId); //cloned entity for old data DocumentEntity oldDocumentData = Utils.getClonedEntityForData(documentEntity); @@ -245,12 +261,15 @@ public class DocumentDao { String type = documentEntity.getSource(); UploadFileOnAmazonS3Response uploadFileOnAmazonS3Response = updateFileOnAmazonS3(file, DocumentSourceTypeEnum.valueOf(type), documentEntity.getSourceId()); if (uploadFileOnAmazonS3Response != null) { + log.info("Successfully uploaded new file to S3: fileName={}", + uploadFileOnAmazonS3Response.getFileName()); documentEntity.setFileName(uploadFileOnAmazonS3Response.getFileName()); documentEntity.setFilePath(uploadFileOnAmazonS3Response.getFilePath()); documentEntity.setType(documentTypeEnum.getValue()); documentEntity.setSource(documentEntity.getSource()); documentEntity.setSourceId(documentEntity.getSourceId()); documentRepository.save(documentEntity); + log.info("Document updated in database for documentId={}", documentId); /** This code is responsible for adding a version history log for the "updating doc or image" operation. **/ loggingUtil.addVersionHistory( @@ -260,7 +279,6 @@ public class DocumentDao { } private UploadFileOnAmazonS3Response updateFileOnAmazonS3(MultipartFile file, DocumentSourceTypeEnum type, Long id) { - try { Long callId=null; Long applicationId=null; @@ -269,27 +287,32 @@ public class DocumentDao { if (type.equals(DocumentSourceTypeEnum.APPLICATION)) { callId = applicationRepository.findCallIdById(id); applicationId = id; + log.info("Processing document of type APPLICATION . Resolved applicationId={}, callId={}", applicationId, callId); } else if(type.equals(DocumentSourceTypeEnum.AMENDMENT)){ amendmentId = id; ApplicationEntity applicationEntity = applicationAmendmentRequestRepository.findApplicationByAmendmentId(amendmentId); applicationId = applicationEntity.getId(); callId = applicationEntity.getCall().getId(); + log.info("Processing document of type AMENDMENT . Resolved amendmentId={}, applicationId={}, callId={}", amendmentId, applicationId, callId); }else if(type.equals(DocumentSourceTypeEnum.EVALUATION)){ evaluationId = id; ApplicationEntity applicationEntity = applicationEvaluationRepository.findApplicationByEvaluationId(evaluationId); applicationId = applicationEntity.getId(); callId = applicationEntity.getCall().getId(); + log.info("Processing document of type EVALUATION . Resolved evaluationId={}, applicationId={}, callId={}", evaluationId, applicationId, callId); } else { callId = id; applicationId = 0L; + log.info("Processing document of type CALL . Resolved callId={}", callId); } String s3Path = generateS3Path(type, callId, applicationId,amendmentId); log.info("Generated S3 path {}", s3Path); return amazonS3Service.uploadFileOnAmazonS3(s3Path, file); } catch (Exception e) { + log.error("Error during file update to S3: documentType={}, sourceId={}, error={}",type, id, e.getMessage(), e); throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); } } @@ -304,6 +327,7 @@ public class DocumentDao { DocumentEntity oldDocumentEntity = Utils.getClonedEntityForData(documentEntity); String oldS3Path = documentEntity.getFilePath(); String newS3Path = s3ConfigBean.generateDocumentPathForOther(DocOtherSourceTypeEnum.valueOf("DELETED_" + documentEntity.getSource().toUpperCase()), callId, applicationId,amendmentId); + log.info("Moving file to deleted path: oldS3Path={}, newS3Path={}", oldS3Path, newS3Path); UploadFileOnAmazonS3Response response = amazonS3Service.moveFile(documentEntity.getFileName(), oldS3Path, newS3Path); documentEntity.setFileName(response.getFileName()); documentEntity.setFilePath(response.getFilePath()); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/PdfDao.java b/src/main/java/net/gepafin/tendermanagement/dao/PdfDao.java index 46cae083..9eda7968 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/PdfDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/PdfDao.java @@ -62,6 +62,7 @@ public class PdfDao { public byte[] generatePdf(HttpServletRequest request,Long applicationId) { try { + log.info("Start generating PDF for applicationId: {}", applicationId); UserEntity userEntity = validator.validateUser(request); ApplicationEntity applicationEntity = applicationDao.validateApplication(applicationId); validator.validateUserWithCompany(request, applicationEntity.getCompanyId()); @@ -125,6 +126,7 @@ public class PdfDao { return pdfBytes; } catch (Exception e) { + log.error("Error generating PDF for applicationId: {}", applicationId, e); e.printStackTrace(); } return null; From b63373d3de6e6813f1b089be28293e2a4bc12a3b Mon Sep 17 00:00:00 2001 From: nisha Date: Wed, 28 May 2025 14:02:00 +0530 Subject: [PATCH 62/63] Done ticket GEPAFINBE-221 --- .../dao/ApplicationEvaluationDao.java | 17 ++++++++++------- .../gepafin/tendermanagement/dao/CallDao.java | 2 +- .../dao/EvaluationCriteriaDao.java | 3 ++- .../entities/EvaluationCriteriaEntity.java | 4 +++- .../model/request/CriteriaRequest.java | 4 +++- .../model/request/EvaluationCriteriaReq.java | 4 +++- .../request/EvaluationCriteriaRequest.java | 4 +++- .../model/response/CriteriaResponse.java | 5 +++-- .../EvaluationCriteriaResponseBean.java | 4 +++- 9 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java index 8d4ce08e..b9782af0 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationEvaluationDao.java @@ -2510,8 +2510,8 @@ public class ApplicationEvaluationDao { ApplicationEvaluationEntity evaluationEntity = evaluationEntityOpt.get(); String criteriaJson = evaluationEntity.getCriteria(); if (criteriaJson != null){ - Integer totalScore = calculateTotalScore(evaluationEntity.getCriteria()); - if (totalScore > 40) { + BigDecimal totalScore = calculateTotalScore(evaluationEntity.getCriteria()); + if (totalScore.compareTo(new BigDecimal("40")) > 0) { applicationEntity.setStatus(status.getValue()); log.info("Status updated to TECHNICAL_EVALUATION for applicationId: " + applicationId); } @@ -2522,7 +2522,7 @@ public class ApplicationEvaluationDao { } } - private Integer calculateTotalScore(String criteriaJson){ + private BigDecimal calculateTotalScore(String criteriaJson){ try { ObjectMapper objectMapper = new ObjectMapper(); // Convert JSON string to List of Maps @@ -2530,15 +2530,18 @@ public class ApplicationEvaluationDao { }); // Sum all scores (ignoring null scores) - Integer totalScore = criteriaList.stream() - .mapToInt(obj -> obj.get("score") != null ? ((Number) obj.get("score")).intValue() : 0) - .sum(); + BigDecimal totalScore = criteriaList.stream() + .map(obj -> { + Object score = obj.get("score"); + return score != null ? new BigDecimal(score.toString()) : BigDecimal.ZERO; + }) + .reduce(BigDecimal.ZERO, BigDecimal::add); return totalScore; } catch (Exception e) { log.error(" Error parsing criteria JSON: {}", e.getMessage()); - return 0; + return BigDecimal.ZERO; } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index 3cb86a50..7fc9663a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -277,7 +277,7 @@ public class CallDao { criteriaEntity = new EvaluationCriteriaEntity(); criteriaEntity.setCall(callEntity); criteriaEntity.setLookupData(lookupDataEntity); - criteriaEntity.setScore(0L); + criteriaEntity.setScore(BigDecimal.ZERO); criteriaEntity.setIsDeleted(false); actionType = VersionActionTypeEnum.INSERT; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/EvaluationCriteriaDao.java b/src/main/java/net/gepafin/tendermanagement/dao/EvaluationCriteriaDao.java index 8f7897c4..fa59c0ab 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/EvaluationCriteriaDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/EvaluationCriteriaDao.java @@ -20,6 +20,7 @@ import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; +import java.math.BigDecimal; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; @@ -68,7 +69,7 @@ public class EvaluationCriteriaDao { LookUpDataEntity lookupDataEntity = lookUpDataService.getOrCreateLookUpDataEntity(evaluationCriteriaRequest, LookUpDataEntity.LookUpDataTypeEnum.EVALUATION_CRITERIA); entity.setCall(callEntity); entity.setLookupData(lookupDataEntity); - entity.setScore(0L); + entity.setScore(BigDecimal.ZERO); if (evaluationCriteriaRequest.getScore() != null) { entity.setScore(evaluationCriteriaRequest.getScore()); } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/EvaluationCriteriaEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/EvaluationCriteriaEntity.java index 39b3eb05..8d1c0c69 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/EvaluationCriteriaEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/EvaluationCriteriaEntity.java @@ -6,6 +6,8 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import lombok.Data; +import java.math.BigDecimal; + @Entity @Table(name = "EVALUATION_CRITERIA") @@ -21,7 +23,7 @@ public class EvaluationCriteriaEntity extends BaseEntity { private LookUpDataEntity lookupData; @Column(name = "SCORE", nullable = false) - private Long score; + private BigDecimal score; @Column(name ="IS_DELETED", nullable = false) private Boolean isDeleted = false; diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/CriteriaRequest.java b/src/main/java/net/gepafin/tendermanagement/model/request/CriteriaRequest.java index ada0d83c..6ed6dfa7 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/CriteriaRequest.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/CriteriaRequest.java @@ -2,9 +2,11 @@ package net.gepafin.tendermanagement.model.request; import lombok.Data; +import java.math.BigDecimal; + @Data public class CriteriaRequest { private Long id; - private Long score; + private BigDecimal score; private Boolean valid; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaReq.java index 7d504f7f..3d1c46c1 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaReq.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaReq.java @@ -3,9 +3,11 @@ package net.gepafin.tendermanagement.model.request; import lombok.Data; import lombok.NoArgsConstructor; +import java.math.BigDecimal; + @NoArgsConstructor @Data public class EvaluationCriteriaReq extends LookUpDataReq{ - private Long score; + private BigDecimal score; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaRequest.java b/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaRequest.java index a2e5a92b..1426748c 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaRequest.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaRequest.java @@ -3,11 +3,13 @@ package net.gepafin.tendermanagement.model.request; import lombok.Data; import lombok.NoArgsConstructor; +import java.math.BigDecimal; + @NoArgsConstructor @Data public class EvaluationCriteriaRequest extends LookUpDataReq { private Long callId; - private Long score; + private BigDecimal score; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/CriteriaResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/CriteriaResponse.java index ebbb2f2c..9d239a44 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/CriteriaResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/CriteriaResponse.java @@ -2,14 +2,15 @@ package net.gepafin.tendermanagement.model.response; import lombok.Data; +import java.math.BigDecimal; import java.util.List; @Data public class CriteriaResponse { private Long id; private String label; - private Long score; - private Long maxScore; + private BigDecimal score; + private BigDecimal maxScore; private List criteriaMappedFields; private Boolean valid; } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EvaluationCriteriaResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/EvaluationCriteriaResponseBean.java index 50a984cc..4e1d564e 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/EvaluationCriteriaResponseBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/EvaluationCriteriaResponseBean.java @@ -3,9 +3,11 @@ package net.gepafin.tendermanagement.model.response; import lombok.Data; import net.gepafin.tendermanagement.model.BaseBean; +import java.math.BigDecimal; + @Data public class EvaluationCriteriaResponseBean extends LookUpDataResponse{ - private Long score; + private BigDecimal score; } From 5df897680a96cbc14c7c851759246b6b2aa60c8e Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 3 Jun 2025 13:04:32 +0530 Subject: [PATCH 63/63] Added #noauth in doc url of sviluppUmbria protocol --- .../gepafin/tendermanagement/constants/GepafinConstant.java | 6 +++--- .../java/net/gepafin/tendermanagement/dao/ProtocolDao.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 1fe74e81..57139e52 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -568,9 +568,9 @@ public class GepafinConstant { public static final String PROTOCOL_MITTENTE="mittente"; public static final String PROTOCOL_DESTINATARI="destinatari"; public static final String PROTOCOL_EXTERNAL_YEAR="ANNO_PG"; - public static final String PROTOCOL_EXTERNAL_NUMBER=""; - public static final String PROTOCOL_EXTERNAL_DATE=""; - + public static final String PROTOCOL_EXTERNAL_NUMBER="NUM_PG"; + public static final String PROTOCOL_EXTERNAL_DATE="DATA_PG_DT"; + public static final String PROTOCOL_DOC_SUFFIX="#noauth"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java index a9b23cd6..c90ddf30 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ProtocolDao.java @@ -176,7 +176,7 @@ public class ProtocolDao { String callName = application.getCall().getName()+" "+ application.getCall().getId(); String callId = GepafinConstant.PROTOCOL_CALL_NAME+ String.valueOf(application.getCall().getId()); String pecEmail=company.getPec(); - String docUrl=applicationSignedDocumentEntity.getFilePath(); + String docUrl=applicationSignedDocumentEntity.getFilePath()+GepafinConstant.PROTOCOL_DOC_SUFFIX; Map requestBody = new HashMap<>();