From c4626a834b9178d825e0ed034608b908d687d139 Mon Sep 17 00:00:00 2001 From: rajesh Date: Tue, 1 Apr 2025 18:09:01 +0530 Subject: [PATCH 01/14] 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 e9c72b5463e000ad0fe6e7046f59928b3d194c09 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Wed, 2 Apr 2025 13:36:25 +0530 Subject: [PATCH 02/14] Done ticket GEPAFINBE-201 Fixed the issue for filteration on number value as string in application pagination API. --- .../gepafin/tendermanagement/util/Utils.java | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 93af188d..51091508 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -826,20 +826,48 @@ public class Utils { } public static void applyNumberFilter(Path fieldPath, CriteriaBuilder criteriaBuilder, List predicates, Object value, MatchModeEnum matchMode) { + if (Number.class.isAssignableFrom(fieldPath.getJavaType())) { Number numberValue = null; - if (value instanceof Number) { - numberValue = (Number) value; + + if (value instanceof String stringValue) { + if (isInteger(stringValue)) { + numberValue = Long.parseLong(stringValue); + } else if (isDecimal(stringValue)) { + numberValue = Double.parseDouble(stringValue); + } + } else if (value instanceof Number number) { + numberValue = number; } - MatchModeEnum mode = MatchModeEnum.fromObject(matchMode.getValue()); - switch (mode) { - case EQUALS -> predicates.add(criteriaBuilder.equal(fieldPath, numberValue)); + if (numberValue != null) { + MatchModeEnum mode = MatchModeEnum.fromObject(matchMode.getValue()); + + if (mode == MatchModeEnum.EQUALS) { + predicates.add(criteriaBuilder.equal(fieldPath, numberValue)); + } } } } + private static boolean isInteger(String value) { + try { + Long.parseLong(value); + return true; + } catch (NumberFormatException e) { + return false; + } + } + private static boolean isDecimal(String value) { + + try { + Double.parseDouble(value); + return value.contains("."); + } catch (NumberFormatException e) { + return false; + } + } public static void applyDateFilter(Path fieldPath, CriteriaBuilder criteriaBuilder, List predicates, Object value, MatchModeEnum matchMode, Root root) { if (fieldPath.getJavaType().equals(LocalDateTime.class)) { From 5afdf042bcfe0b1d1251786674317f099b2875c3 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Thu, 3 Apr 2025 14:51:16 +0530 Subject: [PATCH 03/14] Done ticket GEPAFINBE-195 --- .../constants/GepafinConstant.java | 4 + .../dao/ApplicationAmendmentRequestDao.java | 215 ++++++++++++++-- .../tendermanagement/dao/ApplicationDao.java | 236 ++---------------- .../ApplicationAmendmentRequestView.java | 67 +++++ .../ApplicationAmendmentRequestViewId.java | 14 ++ .../entities/ApplicationView.java | 2 +- ...icationAmendmentPaginationRequestBean.java | 6 + ...plicationAmendmentRequestViewResponse.java | 27 ++ ...icationAmendmentRequestViewRepository.java | 8 + .../ApplicationAmendmentRequestService.java | 3 +- ...pplicationAmendmentRequestServiceImpl.java | 20 +- .../gepafin/tendermanagement/util/Utils.java | 22 ++ .../tendermanagement/util/Validator.java | 8 + .../api/ApplicationAmendmentRequestApi.java | 10 +- ...ApplicationAmendmentRequestController.java | 5 +- .../db/changelog/db.changelog-1.0.0.xml | 5 + ...ate_application_amendment_request_view.sql | 26 ++ src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 3 +- 19 files changed, 429 insertions(+), 253 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestViewId.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestViewRepository.java create mode 100644 src/main/resources/db/dump/create_application_amendment_request_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 9b37da79..a87b2631 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -504,6 +504,10 @@ public class GepafinConstant { 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"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index a766d1a5..daa4391b 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -134,6 +134,12 @@ public class ApplicationAmendmentRequestDao { @Autowired private ApplicationEvaluationFormRepository applicationEvaluationFormRepository; + @Autowired + private ApplicationAmendmentRequestViewRepository applicationAmendmentRequestViewRepository; + + @Autowired + private ApplicationDao applicationDao; + public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(Long applicationEvaluationId) { log.info("Fetching the application data for the Amendment process {}", applicationEvaluationId); ApplicationEvaluationEntity applicationEvaluationEntity = applicationEvaluationService.validateApplicationEvaluation(applicationEvaluationId); @@ -1268,7 +1274,122 @@ public class ApplicationAmendmentRequestDao { documentService.deleteFile(documentId); } - public PageableResponseBean> getApplicationAmendmentByPaginnation(Long userId, ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { +// public PageableResponseBean> getApplicationAmendmentByPaginnation(Long userId, ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { +// Integer pageNo = null; +// Integer pageLimit = null; +// if (applicationAmendmentPaginationRequestBean.getGlobalFilters() != null) { +// pageNo = applicationAmendmentPaginationRequestBean.getGlobalFilters().getPage(); +// pageLimit = applicationAmendmentPaginationRequestBean.getGlobalFilters().getLimit(); +// } +// if (pageLimit == null || pageLimit <= 0) { +// pageLimit = GepafinConstant.DEFAULT_PAGE_LIMIT; +// } +// if (pageNo == null || pageNo <= 0) { +// pageNo = GepafinConstant.DEFAULT_PAGE; +// } +// Specification spec = searchPagination(userId,applicationAmendmentPaginationRequestBean); +// Page entityPage = applicationAmendmentRequestRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); +// +// +// List applicationResponses = entityPage.getContent().stream() +// .map(application -> { +// ApplicationAmendmentRequestResponse response = convertEntityToResponse(application,false); +// return response; +// }) +// .collect(Collectors.toList()); +// +// +// PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); +// pageableResponseBean.setBody(applicationResponses); +// pageableResponseBean.setCurrentPage(entityPage.getNumber() + 1); // Page numbers typically start from 0, so add 1 for user-friendly indexing +// pageableResponseBean.setTotalPages(entityPage.getTotalPages()); +// pageableResponseBean.setTotalRecords(entityPage.getTotalElements()); +// pageableResponseBean.setPageSize(entityPage.getSize()); +// +// return pageableResponseBean; +// } +// +// public Specification searchPagination(Long userId,ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { +// return (root, query, criteriaBuilder) -> { +// +// List predicates = getPredicates(applicationAmendmentPaginationRequestBean, criteriaBuilder, root,userId); +// SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); +// +// if (applicationAmendmentPaginationRequestBean .getGlobalFilters() != null +// && applicationAmendmentPaginationRequestBean.getGlobalFilters().getSortBy() != null && +// applicationAmendmentPaginationRequestBean.getGlobalFilters().getSortBy().getColumnName() != null && Boolean.FALSE.equals( +// isEmpty(applicationAmendmentPaginationRequestBean.getGlobalFilters().getSortBy().getColumnName()))) { +// sortBy.setColumnName(applicationAmendmentPaginationRequestBean.getGlobalFilters().getSortBy().getColumnName()); +// sortBy.setSortDesc(true); +// if (applicationAmendmentPaginationRequestBean.getGlobalFilters().getSortBy().getSortDesc() != null) { +// sortBy.setSortDesc(applicationAmendmentPaginationRequestBean.getGlobalFilters().getSortBy().getSortDesc()); +// } +// } +// +// query.orderBy(criteriaBuilder.desc(root.get(sortBy.getColumnName()))); +// if (Boolean.FALSE.equals(sortBy.getSortDesc())) { +// query.orderBy(criteriaBuilder.asc(root.get(sortBy.getColumnName()))); +// } +// return query.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))).getRestriction(); +// }; +// } +// +// +// private List getPredicates(ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean, +// CriteriaBuilder criteriaBuilder, Root root,Long userId) { +// +// Integer year = null; +// String search = null; +// if (amendmentPaginationRequestBean.getGlobalFilters() != null) { +// year = amendmentPaginationRequestBean.getGlobalFilters().getYear(); +// search = amendmentPaginationRequestBean.getGlobalFilters().getSearch(); +// } +// List predicates = new ArrayList<>(); +// +// if (year != null && year > 0) { +// int filterYear = amendmentPaginationRequestBean.getGlobalFilters().getYear(); +// +//// Create LocalDateTime boundaries for the start and end of the year +// LocalDateTime startOfYear = LocalDateTime.of(filterYear, 1, 1, 0, 0); +// LocalDateTime endOfYear = LocalDateTime.of(filterYear, 12, 31, 23, 59, 59); +// +//// Add the range comparison to filter records within the year +// predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), startOfYear, endOfYear)); +// +// } +// // Search in `title` and `message` (if search term is provided) +// if (search != null && !search.isEmpty()) { +// Predicate notePredicate = criteriaBuilder.like( +// criteriaBuilder.upper(root.get(GepafinConstant.NOTE)), +// "%" + search.toUpperCase() + "%" +// ); +// predicates.add(criteriaBuilder.or(notePredicate)); +// Predicate internalNotePredicate = criteriaBuilder.like( +// criteriaBuilder.upper(root.get(GepafinConstant.INTERNAL_NOTE)), +// "%" + search.toUpperCase() + "%" +// ); +// predicates.add(criteriaBuilder.or(internalNotePredicate)); +// } +// +// // Filter by `status` (if status list is provided) +// if (amendmentPaginationRequestBean.getStatus() != null && !amendmentPaginationRequestBean.getStatus().isEmpty()) { +// List statusValues = amendmentPaginationRequestBean.getStatus().stream() +// .map(ApplicationAmendmentRequestEnum::name) // Convert enum to string +// .toList(); +// predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); +// } +// if(Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { +// predicates.add(root.get("applicationEvaluationEntity").get("assignedApplicationsEntity").get("application").get("userId").in(userId)); +// } +// else { +// predicates.add(root.get("applicationEvaluationEntity").get("assignedApplicationsEntity").get("userId").in(userId)); +// } +// +// return predicates; +// +// } + + public PageableResponseBean> getApplicationAmendmentByPaginationByView(Long userId, ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { Integer pageNo = null; Integer pageLimit = null; if (applicationAmendmentPaginationRequestBean.getGlobalFilters() != null) { @@ -1281,20 +1402,20 @@ public class ApplicationAmendmentRequestDao { if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } - Specification spec = searchPagination(userId,applicationAmendmentPaginationRequestBean); - Page entityPage = applicationAmendmentRequestRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); + Specification spec = searchPaginationByView(userId,applicationAmendmentPaginationRequestBean); + Page entityPage = applicationAmendmentRequestViewRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); - List applicationResponses = entityPage.getContent().stream() - .map(application -> { - ApplicationAmendmentRequestResponse response = convertEntityToResponse(application,false); + List applicationAmendmentRequestViewResponses = entityPage.getContent().stream() + .map(amendmentRequestView -> { + ApplicationAmendmentRequestViewResponse response = convertAmendmentEntityToApplicationAmendmentRequestViewResponse(amendmentRequestView); return response; }) .collect(Collectors.toList()); - PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); - pageableResponseBean.setBody(applicationResponses); + PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); + pageableResponseBean.setBody(applicationAmendmentRequestViewResponses); pageableResponseBean.setCurrentPage(entityPage.getNumber() + 1); // Page numbers typically start from 0, so add 1 for user-friendly indexing pageableResponseBean.setTotalPages(entityPage.getTotalPages()); pageableResponseBean.setTotalRecords(entityPage.getTotalElements()); @@ -1302,11 +1423,10 @@ public class ApplicationAmendmentRequestDao { return pageableResponseBean; } - - public Specification searchPagination(Long userId,ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { + public Specification searchPaginationByView(Long userId,ApplicationAmendmentPaginationRequestBean applicationAmendmentPaginationRequestBean) { return (root, query, criteriaBuilder) -> { - List predicates = getPredicates(applicationAmendmentPaginationRequestBean, criteriaBuilder, root,userId); + List predicates = getPredicatesByView(applicationAmendmentPaginationRequestBean, criteriaBuilder, root,userId); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (applicationAmendmentPaginationRequestBean .getGlobalFilters() != null @@ -1329,15 +1449,19 @@ public class ApplicationAmendmentRequestDao { } - private List getPredicates(ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean, - CriteriaBuilder criteriaBuilder, Root root,Long userId) { + private List getPredicatesByView(ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean, + CriteriaBuilder criteriaBuilder, Root root,Long userId) { Integer year = null; String search = null; + Map filters = new HashMap<>(); if (amendmentPaginationRequestBean.getGlobalFilters() != null) { year = amendmentPaginationRequestBean.getGlobalFilters().getYear(); search = amendmentPaginationRequestBean.getGlobalFilters().getSearch(); } + if (amendmentPaginationRequestBean.getFilters() != null) { + filters = amendmentPaginationRequestBean.getFilters(); + } List predicates = new ArrayList<>(); if (year != null && year > 0) { @@ -1351,19 +1475,37 @@ public class ApplicationAmendmentRequestDao { predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), startOfYear, endOfYear)); } - // Search in `title` and `message` (if search term is provided) + if (search != null && !search.isEmpty()) { - Predicate notePredicate = criteriaBuilder.like( - criteriaBuilder.upper(root.get(GepafinConstant.NOTE)), + List searchPredicates = new ArrayList<>(); + + searchPredicates.add(criteriaBuilder.like( + criteriaBuilder.upper(root.get(GepafinConstant.CALL_NAME)), "%" + search.toUpperCase() + "%" - ); - predicates.add(criteriaBuilder.or(notePredicate)); - Predicate internalNotePredicate = criteriaBuilder.like( - criteriaBuilder.upper(root.get(GepafinConstant.INTERNAL_NOTE)), + )); + + searchPredicates.add(criteriaBuilder.like( + criteriaBuilder.upper(root.get(GepafinConstant.COMPANY_NAME)), "%" + search.toUpperCase() + "%" - ); - predicates.add(criteriaBuilder.or(internalNotePredicate)); + )); + + // Uncomment these if needed + // searchPredicates.add(criteriaBuilder.like( + // criteriaBuilder.upper(root.get(GepafinConstant.NOTE)), + // "%" + search.toUpperCase() + "%" + // )); + // + // searchPredicates.add(criteriaBuilder.like( + // criteriaBuilder.upper(root.get(GepafinConstant.INTERNAL_NOTE)), + // "%" + search.toUpperCase() + "%" + // )); + + Predicate finalPredicate = criteriaBuilder.or(searchPredicates.toArray(new Predicate[0])); + + predicates.add(finalPredicate); } + Utils.applyFiltersByPagination(root, criteriaBuilder, predicates, filters); + // Filter by `status` (if status list is provided) if (amendmentPaginationRequestBean.getStatus() != null && !amendmentPaginationRequestBean.getStatus().isEmpty()) { @@ -1372,14 +1514,33 @@ public class ApplicationAmendmentRequestDao { .toList(); predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); } - if(Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { - predicates.add(root.get("applicationEvaluationEntity").get("assignedApplicationsEntity").get("application").get("userId").in(userId)); - } - else { - predicates.add(root.get("applicationEvaluationEntity").get("assignedApplicationsEntity").get("userId").in(userId)); + boolean isBeneficiaryOrConfidi = validator.checkIsBeneficiary() || validator.checkIsConfidi(); + boolean isPreInstructor = validator.checkIsPreInstructor(); + boolean isInstructorManagerWithPersonalRecords = validator.checkIsInstructorManager() && + Boolean.TRUE.equals(amendmentPaginationRequestBean.getPersonalRecords()); + + if (isBeneficiaryOrConfidi) { + predicates.add(root.get(GepafinConstant.APPLICATION_USER_ID).in(userId)); + } else if (isPreInstructor || isInstructorManagerWithPersonalRecords) { + predicates.add(root.get(GepafinConstant.ASSIGNED_USER_ID).in(userId)); } return predicates; } + public ApplicationAmendmentRequestViewResponse convertAmendmentEntityToApplicationAmendmentRequestViewResponse(ApplicationAmendmentRequestView applicationAmendmentRequestView){ + ApplicationAmendmentRequestViewResponse applicationAmendmentRequestViewResponse=new ApplicationAmendmentRequestViewResponse(); + applicationAmendmentRequestViewResponse.setId(applicationAmendmentRequestView.getId()); + applicationAmendmentRequestViewResponse.setApplicationId(applicationAmendmentRequestView.getApplicationId()); + applicationAmendmentRequestViewResponse.setProtocolNumber(applicationAmendmentRequestView.getProtocolNumber()); + applicationAmendmentRequestViewResponse.setCallName(applicationAmendmentRequestView.getCallName()); + applicationAmendmentRequestViewResponse.setCompanyName(applicationAmendmentRequestView.getCompanyName()); + applicationAmendmentRequestViewResponse.setStartDate(applicationAmendmentRequestView.getStartDate()); + applicationAmendmentRequestViewResponse.setExpirationDate(applicationAmendmentRequestView.getExpirationDate()); + applicationAmendmentRequestViewResponse.setAssigendUserName(applicationAmendmentRequestView.getAssigendUserName()); + applicationAmendmentRequestViewResponse.setStatus(applicationAmendmentRequestView.getStatus()); + return applicationAmendmentRequestViewResponse; + } + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index b63a63fc..a98b3ff9 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -1467,185 +1467,6 @@ public class ApplicationDao { } } - public PageableResponseBean> getAllApplicationByPagination(UserEntity userEntity, Long callId, Long companyId, ApplicationPageableRequestBean applicationPageableRequestBean) { - Integer pageNo = null; - Integer pageLimit = null; - - UserWithCompanyEntity userWithCompany= userWithCompanyRepository.findByUserIdAndCompanyIdAndIsDeletedFalse(userEntity.getId(), companyId).orElse(null); - Long userWithCompanyId = userWithCompany!=null?userWithCompany.getId():null; - if (applicationPageableRequestBean.getGlobalFilters() != null) { - pageNo = applicationPageableRequestBean.getGlobalFilters().getPage(); - pageLimit = applicationPageableRequestBean.getGlobalFilters().getLimit(); - } - if (pageLimit == null || pageLimit <= 0) { - pageLimit = GepafinConstant.DEFAULT_PAGE_LIMIT; - } - if (pageNo == null || pageNo <= 0) { - pageNo = GepafinConstant.DEFAULT_PAGE; - } - Specification spec = search(callId,companyId, userWithCompanyId, applicationPageableRequestBean, userEntity); - Page entityPage = applicationRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); - // Prepare the response - - - List applicationResponses = entityPage.getContent().stream() - .map(application -> { - ApplicationResponse response = getApplicationResponse(application); - return response; - }) - .collect(Collectors.toList()); - - - PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); - pageableResponseBean.setBody(applicationResponses); - pageableResponseBean.setCurrentPage(entityPage.getNumber() + 1); // Page numbers typically start from 0, so add 1 for user-friendly indexing - pageableResponseBean.setTotalPages(entityPage.getTotalPages()); - pageableResponseBean.setTotalRecords(entityPage.getTotalElements()); - pageableResponseBean.setPageSize(entityPage.getSize()); - - return pageableResponseBean; - } - - public Specification search(Long callId, Long companyId, Long userWithCompanyId, ApplicationPageableRequestBean applicationPageableRequestBean, UserEntity userEntity) { - return (root, query, criteriaBuilder) -> { - - List predicates = getPredicates(applicationPageableRequestBean, criteriaBuilder, root, callId,companyId, userWithCompanyId, userEntity); - SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); - - if (applicationPageableRequestBean.getGlobalFilters() != null - && applicationPageableRequestBean.getGlobalFilters().getSortBy() != null && - applicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName() != null && Boolean.FALSE.equals( - isEmpty(applicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName()))) { - sortBy.setColumnName(applicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName()); - sortBy.setSortDesc(true); - if (applicationPageableRequestBean.getGlobalFilters().getSortBy().getSortDesc() != null) { - sortBy.setSortDesc(applicationPageableRequestBean.getGlobalFilters().getSortBy().getSortDesc()); - } - } - - query.orderBy(criteriaBuilder.desc(root.get(sortBy.getColumnName()))); - if (Boolean.FALSE.equals(sortBy.getSortDesc())) { - query.orderBy(criteriaBuilder.asc(root.get(sortBy.getColumnName()))); - } - return query.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))).getRestriction(); - }; - } - - - private List getPredicates(ApplicationPageableRequestBean applicationPageableRequestBean, - CriteriaBuilder criteriaBuilder, Root root, Long callId,Long companyId, Long userWithCompanyId, UserEntity userEntity) { - - Integer year = null; - String search = null; - Integer daysRange = null; - Map filters = new HashMap<>(); - if (applicationPageableRequestBean.getGlobalFilters() != null) { - year = applicationPageableRequestBean.getGlobalFilters().getYear(); - search = applicationPageableRequestBean.getGlobalFilters().getSearch(); - daysRange = applicationPageableRequestBean.getDaysRange(); - } - if (applicationPageableRequestBean.getFilters() != null) { - filters = applicationPageableRequestBean.getFilters(); - } - List predicates = new ArrayList<>(); - -// Boolean isBeneficiary = validator.checkIsBeneficiary(); - if (Boolean.TRUE.equals(validator.checkIsBeneficiary()) || Boolean.TRUE.equals(validator.checkIsConfidi())) { - predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.USER_ID), userEntity.getId())); - } - if (year != null && year > 0) { - int filterYear = applicationPageableRequestBean.getGlobalFilters().getYear(); - -// Create LocalDateTime boundaries for the start and end of the year - LocalDateTime startOfYear = LocalDateTime.of(filterYear, 1, 1, 0, 0); - LocalDateTime endOfYear = LocalDateTime.of(filterYear, 12, 31, 23, 59, 59); - -// Add the range comparison to filter records within the year - predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), startOfYear, endOfYear)); - - } - // Search in `title` and `message` (if search term is provided) - if (search != null && !search.isEmpty()) { - Predicate titlePredicate = criteriaBuilder.like( - criteriaBuilder.upper(root.get(GepafinConstant.COMMENTS)), - "%" + search.toUpperCase() + "%" - ); -// Predicate protocolPredicate = criteriaBuilder.like( -// criteriaBuilder.function( -// "TO_CHAR", -// String.class, -// criteriaBuilder.function("CAST", String.class, root.get(GepafinConstant.PROTOCOL).get(GepafinConstant.PROTOCOL_NUMBER)) -// ), -// "%" + search + "%" -// ); - - Predicate callNamePredicate =criteriaBuilder.like( - criteriaBuilder.upper(root.get(GepafinConstant.CALL).get(GepafinConstant.NAME)), // Adjust field name - "%" + search.toUpperCase() + "%" - ); - -// predicates.add(criteriaBuilder.or(protocolPredicate)); - predicates.add(criteriaBuilder.or(callNamePredicate)); - predicates.add(criteriaBuilder.or(titlePredicate)); - } - - // Filter by `status` (if status list is provided) - if (applicationPageableRequestBean.getStatus() != null && !applicationPageableRequestBean.getStatus().isEmpty()) { - List statusValues = applicationPageableRequestBean.getStatus().stream() - .map(ApplicationStatusTypeEnum::name) // Convert enum to string - .toList(); - predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); - } - - if (callId != null) { - CallEntity call = callService.validateCall(callId); - predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.CALL).get(GepafinConstant.ID), callId)); - } - - // Optional companyId filter - if (userWithCompanyId != null) { - predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.USER_WITH_COMPANY).get(GepafinConstant.ID), userWithCompanyId)); - } - if (companyId != null) { - predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.COMPANY_ID), companyId)); - } - - if (daysRange != null && daysRange >= 0) { - LocalDateTime today = LocalDateTime.now(); - LocalDateTime pastDate = today.minusDays(daysRange); - predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), pastDate, today)); - } - applyFilters(root, criteriaBuilder, predicates, filters); - - predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); - - predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.HUB_ID), userEntity.getHub().getId())); - - - return predicates; - } - private void applyFilters(Root root, CriteriaBuilder criteriaBuilder, List predicates, Map filters) { - if (Boolean.FALSE.equals(filters.isEmpty())) { - for (Map.Entry entry : filters.entrySet()) { - String fieldName = entry.getKey(); - FilterCriteria filterCriteria = entry.getValue(); - Object value = filterCriteria.getValue(); - MatchModeEnum matchMode = filterCriteria.getMatchMode(); - - if (value != null && matchMode != null) { - Path fieldPath = root.get(fieldName); - if (fieldPath != null) { - Utils.applyStringFilter(fieldPath, criteriaBuilder, predicates, value, matchMode); - Utils.applyNumberFilter(fieldPath, criteriaBuilder, predicates, value, matchMode); - Utils.applyDateFilter(fieldPath, criteriaBuilder, predicates, value, matchMode,root); - } - } - } - } - } - - - // private Path getFieldPath(Root root, String fieldName) { // try { @@ -1918,27 +1739,29 @@ public class ApplicationDao { } // Search in `title` and `message` (if search term is provided) if (search != null && !search.isEmpty()) { + String searchPattern = "%" + search.toUpperCase() + "%"; + Predicate titlePredicate = criteriaBuilder.like( criteriaBuilder.upper(root.get(GepafinConstant.COMMENTS)), - "%" + search.toUpperCase() + "%" - ); -// Predicate protocolPredicate = criteriaBuilder.like( -// criteriaBuilder.function( -// "TO_CHAR", -// String.class, -// criteriaBuilder.function("CAST", String.class, root.get(GepafinConstant.PROTOCOL).get(GepafinConstant.PROTOCOL_NUMBER)) -// ), -// "%" + search + "%" -// ); - - Predicate callNamePredicate =criteriaBuilder.like( - criteriaBuilder.upper(root.get(GepafinConstant.CALL_TITLE)), // Adjust field name - "%" + search.toUpperCase() + "%" + searchPattern ); -// predicates.add(criteriaBuilder.or(protocolPredicate)); - predicates.add(criteriaBuilder.or(callNamePredicate)); - predicates.add(criteriaBuilder.or(titlePredicate)); + Predicate callTitlePredicate = criteriaBuilder.like( + criteriaBuilder.upper(root.get(GepafinConstant.CALL_TITLE)), + searchPattern + ); + Predicate callNamePredicate = criteriaBuilder.like( + criteriaBuilder.upper(root.get(GepafinConstant.CALL_NAME)), + searchPattern + ); + Predicate companyName = criteriaBuilder.like( + criteriaBuilder.upper(root.get(GepafinConstant.COMPANY_NAME)), + searchPattern + ); + + // Combine them using a single `or()` + Predicate finalPredicate = criteriaBuilder.or(titlePredicate, callTitlePredicate,callNamePredicate,companyName); + predicates.add(finalPredicate); } // Filter by `status` (if status list is provided) @@ -1967,7 +1790,7 @@ public class ApplicationDao { LocalDateTime pastDate = today.minusDays(daysRange); predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), pastDate, today)); } - applyFilters(root, criteriaBuilder, predicates, filters); + Utils.applyFiltersByPagination(root, criteriaBuilder, predicates, filters); predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); @@ -1981,7 +1804,7 @@ public class ApplicationDao { ApplicationResponse responseBean = new ApplicationResponse(); List flowEdgesList = flowEdgesRepository.findByCallId(applicationView.getCallId()); Long totalFormSteps = flowFormDao.calculateTotalSteps(flowEdgesList); - Long completedSteps= Long.valueOf(flowFormDao.getCompletedStepsByView(applicationView.getId(), false)); + Long completedSteps = Long.valueOf(flowFormDao.getCompletedStepsByView(applicationView.getId(), false)); Integer progress = calculateProgress(totalFormSteps, completedSteps); responseBean.setId(applicationView.getId()); responseBean.setProgress(progress); @@ -1995,19 +1818,10 @@ public class ApplicationDao { responseBean.setEvaluationVersion(EvaluationVersionEnum.valueOf(applicationView.getEvaluationVersion())); responseBean.setComments(applicationView.getComments()); responseBean.setCompanyId(applicationView.getCompanyId()); - Optional assignedApplicationsOptional = - assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationView.getId()); - if(assignedApplicationsOptional.isPresent()){ - responseBean.setAssignedUserId(assignedApplicationsOptional.get().getUserId()); - UserEntity user = userService.validateUser(assignedApplicationsOptional.get().getUserId()); - String firstName = user.getFirstName() != null ? user.getFirstName() : ""; - String lastName = user.getLastName() != null ? user.getLastName() : ""; - String userName = String.join(" ", firstName, lastName).trim(); - responseBean.setAssignedUserName(userName); - } - CompanyEntity company=companyService.validateCompany(applicationView.getCompanyId()); - responseBean.setCompanyName(company.getCompanyName()); - responseBean.setProtocolNumber(applicationView.getProtocolNumber()); + responseBean.setAssignedUserId(applicationView.getAssignedUserId()); + responseBean.setAssignedUserName(applicationView.getAssignedUserName()); + responseBean.setCompanyName(applicationView.getCompanyName()); + responseBean.setProtocolNumber(applicationView.getProtocolNumber()); responseBean.setAmountAccepted(applicationView.getAmountAccepted()); responseBean.setAmountRequested(applicationView.getAmountRequested()); responseBean.setDateAccepted(applicationView.getDateAccepted()); diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java new file mode 100644 index 00000000..b5ee0ecc --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestView.java @@ -0,0 +1,67 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Immutable; + +import java.time.LocalDateTime; + +@Entity +@Immutable +@Table(name = "application_amendment_request_view") +@Getter +@Setter +@IdClass(ApplicationAmendmentRequestViewId.class) +public class ApplicationAmendmentRequestView { + + + @Id + @Column(name = "ID") + private Long id; + + @Column(name = "APPLICATION_ID") + private Long applicationId; + + @Column(name = "PROTOCOL_NUMBER") + private Long protocolNumber; + + @Column(name = "CALL_NAME") + private String callName; + + @Column(name = "COMPANY_NAME") + private String companyName; + + @Column(name = "START_DATE") + private LocalDateTime startDate; + + @Column(name = "EXPIRATION_DATE") + private LocalDateTime expirationDate; + + @Column(name = "ASSIGNED_USER_NAME") + private String assigendUserName; + + @Column(name = "ASSIGNED_USER_ID") + private Long assignedUserId; + + @Column(name = "STATUS") + private String status; + + @Column(name = "NOTE") + private String note; + + @Column(name = "INTERNAL_NOTE") + private String internalNote; + + @Column(name = "APPLICATION_USER_ID") + private Long applicationUserId; + + @Column(name = "CREATED_DATE") + private String createdDate; + + @Column(name = "UPDATED_DATE") + private String updatedDate; + + @Column(name = "IS_DELETED") + private Boolean isDeleted; +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestViewId.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestViewId.java new file mode 100644 index 00000000..f80e5475 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestViewId.java @@ -0,0 +1,14 @@ +package net.gepafin.tendermanagement.entities; + +public class ApplicationAmendmentRequestViewId { + + private static final long serialVersionUID = 1L; + private Long id; + + public ApplicationAmendmentRequestViewId() { + } + + public ApplicationAmendmentRequestViewId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationView.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationView.java index ec9c0965..54593c2e 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationView.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationView.java @@ -80,7 +80,7 @@ public class ApplicationView implements Serializable { private Long protocolNumber; @Column(name = "ASSIGNED_USER_ID") - private Long assigned_user_id; + private Long assignedUserId; @Column(name = "ASSIGNED_USER_NAME") private String assignedUserName; diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentPaginationRequestBean.java b/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentPaginationRequestBean.java index 42318247..8f717f92 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentPaginationRequestBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationAmendmentPaginationRequestBean.java @@ -4,6 +4,7 @@ import lombok.Data; import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum; import java.util.List; +import java.util.Map; @Data public class ApplicationAmendmentPaginationRequestBean { @@ -11,4 +12,9 @@ public class ApplicationAmendmentPaginationRequestBean { private GlobalFilters globalFilters; private List status; + + private Map filters; + + private Boolean personalRecords; + } diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java new file mode 100644 index 00000000..e4139131 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationAmendmentRequestViewResponse.java @@ -0,0 +1,27 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ApplicationAmendmentRequestViewResponse { + + private Long id; + + private Long applicationId; + + private Long protocolNumber; + + private String callName; + + private String companyName; + + private LocalDateTime startDate; + + private LocalDateTime expirationDate; + + private String assigendUserName; + + private String status; +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestViewRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestViewRepository.java new file mode 100644 index 00000000..adce7672 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestViewRepository.java @@ -0,0 +1,8 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestView; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface ApplicationAmendmentRequestViewRepository extends JpaRepository , JpaSpecificationExecutor { +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java index 7893b776..d54d49d3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationAmendmentRequestService.java @@ -9,6 +9,7 @@ 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; @@ -29,5 +30,5 @@ public interface ApplicationAmendmentRequestService { public ApplicationAmendmentRequestResponse updateApplicationAmendmentStatus(HttpServletRequest request, Long applicationAmendmentId, ApplicationAmendmentRequestEnum status); void sendReminderEmail(HttpServletRequest request,Long amendmentId); - PageableResponseBean> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean); + PageableResponseBean> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean); } 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 af31f78a..1d7a38a9 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationAmendmentRequestServiceImpl.java @@ -13,12 +13,15 @@ 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.repositories.ApplicationAmendmentRequestRepository; import net.gepafin.tendermanagement.repositories.ApplicationEvaluationRepository; import net.gepafin.tendermanagement.service.ApplicationAmendmentRequestService; +import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.util.Validator; +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; @@ -41,6 +44,9 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm @Autowired private ApplicationEvaluationRepository applicationEvaluationRepository; + @Autowired + private UserService userService; + @Override public ApplicationAmendmentRequestResponse getApplicationDataForAmendment(HttpServletRequest request, Long applicationEvaluationId) { Optional entityOptional = applicationEvaluationRepository.findByIdAndIsDeletedFalse(applicationEvaluationId); @@ -153,8 +159,16 @@ public class ApplicationAmendmentRequestServiceImpl implements ApplicationAmendm } @Override - public PageableResponseBean> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean) { - UserEntity user=validator.validateUser(request); - return applicationAmendmentRequestDao.getApplicationAmendmentByPaginnation(userId,amendmentPaginationRequestBean); + public PageableResponseBean> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean) { + boolean isSpecialUser = validator.checkIsBeneficiary() || + validator.checkIsConfidi() || + validator.checkIsPreInstructor() || + validator.checkIsInstructorManager(); + + if (isSpecialUser && Boolean.TRUE.equals(validator.checkRequestedUserWithUserId(request,userId))) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_USER_ID)); + } + + return applicationAmendmentRequestDao.getApplicationAmendmentByPaginationByView(userId,amendmentPaginationRequestBean); } } diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 51091508..7a578334 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -37,6 +37,7 @@ import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.enums.MatchModeEnum; +import net.gepafin.tendermanagement.model.request.FilterCriteria; import net.gepafin.tendermanagement.model.request.GlobalFilters; import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; @@ -932,4 +933,25 @@ public class Utils { Object obj = parentMap.get(key); return (obj instanceof String str) ? str : null; } + + + public static void applyFiltersByPagination(Root root, CriteriaBuilder criteriaBuilder, List predicates, Map filters) { + if (Boolean.FALSE.equals(filters.isEmpty())) { + for (Map.Entry entry : filters.entrySet()) { + String fieldName = entry.getKey(); + FilterCriteria filterCriteria = entry.getValue(); + Object value = filterCriteria.getValue(); + MatchModeEnum matchMode = filterCriteria.getMatchMode(); + + if (value != null && matchMode != null) { + Path fieldPath = root.get(fieldName); + if (fieldPath != null) { + Utils.applyStringFilter(fieldPath, criteriaBuilder, predicates, value, matchMode); + Utils.applyNumberFilter(fieldPath, criteriaBuilder, predicates, value, matchMode); + Utils.applyDateFilter(fieldPath, criteriaBuilder, predicates, value, matchMode,root); + } + } + } + } + } } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/util/Validator.java b/src/main/java/net/gepafin/tendermanagement/util/Validator.java index 21e2bd1a..a68dc1bd 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Validator.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Validator.java @@ -206,4 +206,12 @@ public class Validator { } return false; } + public Boolean checkRequestedUserWithUserId(HttpServletRequest request,Long userId){ + UserEntity user=validateUser(request); + UserEntity requestedUser=userService.validateUser(userId); + if( Boolean.FALSE.equals(user.getId().equals(requestedUser.getId()))){ + return true; + } + return false; + } } 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 8f1c5b2b..eb0c05f0 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 @@ -10,11 +10,7 @@ import jakarta.validation.Valid; import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.model.request.*; -import net.gepafin.tendermanagement.model.response.ApplicationAmendmentRequestResponse; -import net.gepafin.tendermanagement.model.response.ApplicationResponse; -import net.gepafin.tendermanagement.model.response.PageableResponseBean; -import net.gepafin.tendermanagement.model.response.SummaryPageResponseBean; -import net.gepafin.tendermanagement.model.response.GetAllAmendmentResponseBean; +import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; import org.springframework.http.MediaType; @@ -201,7 +197,7 @@ public interface ApplicationAmendmentRequestApi { @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = { @ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) }) @PostMapping(value = "/user/{userId}/pagination", produces = { "application/json" }) - ResponseEntity>>> getApplicationAmendmentByPaginnation(HttpServletRequest request, @Parameter(description = "The user id", required = true) @PathVariable("userId") Long userId, - @RequestBody ApplicationAmendmentPaginationRequestBean userActionPaginationRequest); + ResponseEntity>>> getApplicationAmendmentByPaginnation(HttpServletRequest request, @Parameter(description = "The user id", required = true) @PathVariable("userId") Long userId, + @RequestBody ApplicationAmendmentPaginationRequestBean userActionPaginationRequest); } 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 562a84b3..585a6d1e 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 @@ -9,6 +9,7 @@ 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.util.Response; @@ -187,11 +188,11 @@ public class ApplicationAmendmentRequestController implements ApplicationAmendme } @Override - public ResponseEntity>>> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean) { + public ResponseEntity>>> getApplicationAmendmentByPaginnation(HttpServletRequest request, Long userId, ApplicationAmendmentPaginationRequestBean amendmentPaginationRequestBean) { loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW) .actionContext(UserActionContextEnum.GET_ALL_APPLICATION_AMENDMENT_BY_PAGINATION).build()); - PageableResponseBean> listPageableResponseBean=applicationAmendmentRequestService.getApplicationAmendmentByPaginnation(request,userId,amendmentPaginationRequestBean); + PageableResponseBean> listPageableResponseBean=applicationAmendmentRequestService.getApplicationAmendmentByPaginnation(request,userId,amendmentPaginationRequestBean); return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(listPageableResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_DATA_FOR_AMENDMENT_SUCCESS_MSG))); 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 a692a560..379e56e2 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 @@ -2690,4 +2690,9 @@ + + + + diff --git a/src/main/resources/db/dump/create_application_amendment_request_view.sql b/src/main/resources/db/dump/create_application_amendment_request_view.sql new file mode 100644 index 00000000..ec882e6e --- /dev/null +++ b/src/main/resources/db/dump/create_application_amendment_request_view.sql @@ -0,0 +1,26 @@ +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 +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/message_en.properties b/src/main/resources/message_en.properties index 2c27f379..80915228 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -398,3 +398,4 @@ error.invalid.limit=Limit should be between 1 and 3000. insufficient.score.msg = Insufficient score to pass to the technical and economic-financial evaluation password.expired.for.login.to.odessa = Odessa login password has been expired. +invalid.user=Invalid user. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 7b0293bf..02fdd1a7 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -389,4 +389,5 @@ 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 \ No newline at end of file +password.expired.for.login.to.odessa = La password di accesso a Odessa è scaduta +invalid.user=Utente non valido. \ No newline at end of file From 2090b5d256526ed3461fd91bffb422bb88634320 Mon Sep 17 00:00:00 2001 From: nisha Date: Thu, 3 Apr 2025 15:50:22 +0530 Subject: [PATCH 04/14] Done ticket GEPAFINBE-200 --- .../gepafin/tendermanagement/dao/DelegationDao.java | 1 - .../service/impl/ApplicationServiceImpl.java | 2 ++ .../service/impl/CompanyDocumentServiceImpl.java | 2 ++ .../service/impl/CompanyServiceImpl.java | 3 +++ .../service/impl/DocumentServiceImpl.java | 2 ++ .../net/gepafin/tendermanagement/util/Utils.java | 13 +++++++++---- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java index a3243c22..b39efce7 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java @@ -209,7 +209,6 @@ public class DelegationDao { companyDao.validateCompany(companyId); companyDao.getUserWithCompany(userEntity.getId(), companyId); - validateFileType(file); UserWithCompanyEntity userWithCompanyEntity=companyService.getUserWithCompany(userEntity.getId(),companyId); UserCompanyDelegationEntity userCompanyDelegationEntity = userCompanyDelegationRepository .findByUserIdAndUserWithCompanyIdAndStatus(userEntity.getId(), userWithCompanyEntity.getId(), 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 70ed5794..0c84086b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -15,6 +15,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.util.Utils; import net.gepafin.tendermanagement.util.Validator; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.ForbiddenAccessException; @@ -112,6 +113,7 @@ public class ApplicationServiceImpl implements ApplicationService { @Override @Transactional(rollbackFor = Exception.class) public ApplicationSignedDocumentResponse uploadSignedDocument(HttpServletRequest request, Long applicationId, MultipartFile file) { + Utils.validateFileType(file); return applicationDao.uploadSignedDocument(request, applicationId, file); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyDocumentServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyDocumentServiceImpl.java index 74b680e4..c12e1ab3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyDocumentServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyDocumentServiceImpl.java @@ -9,6 +9,7 @@ import net.gepafin.tendermanagement.model.request.CompanyDocumentRequest; import net.gepafin.tendermanagement.model.response.CompanyDocumentResponseBean; import net.gepafin.tendermanagement.model.response.DocumentResponseBean; import net.gepafin.tendermanagement.service.CompanyDocumentService; +import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -31,6 +32,7 @@ public class CompanyDocumentServiceImpl implements CompanyDocumentService { public List uploadFileForCompany(HttpServletRequest request, List files, Long companyId, Long documentCategoryId , CompanyDocumentTypeEnum documentSourceTypeEnum, LocalDateTime expirationDate,String name) { Map userInfo = validator.getUserInfoFromToken(request); Long userId = validator.getUserId(userInfo); + files.forEach(Utils::validateFileType); return companyDocumentDao.uploadFileForCompany(request,userId,files,companyId,documentCategoryId,documentSourceTypeEnum,expirationDate,name); } 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 1e77eddb..924f379c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java @@ -4,8 +4,10 @@ import java.io.ByteArrayOutputStream; import java.util.List; import java.util.Map; +import jdk.jshell.execution.Util; import net.gepafin.tendermanagement.model.request.LimitRequest; import net.gepafin.tendermanagement.model.response.VatCheckResponseBean; +import net.gepafin.tendermanagement.util.Utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -107,6 +109,7 @@ public class CompanyServiceImpl implements CompanyService { public CompanyDelegationResponse uploadCompanyDelegation(HttpServletRequest request, Long companyId, MultipartFile file) { UserEntity userEntity = validator.validateUser(request); validator.validateUserWithCompany(request, companyId); + Utils.validateFileType(file); return delegationDao.uploadCompanyDelegation(userEntity, companyId, file); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/DocumentServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/DocumentServiceImpl.java index d7a46aa6..087bf06b 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/DocumentServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/DocumentServiceImpl.java @@ -11,6 +11,7 @@ import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.enums.DocumentTypeEnum; import net.gepafin.tendermanagement.model.response.DocumentResponseBean; import net.gepafin.tendermanagement.service.DocumentService; +import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.util.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -31,6 +32,7 @@ public class DocumentServiceImpl implements DocumentService { public List uploadFile(HttpServletRequest request,List files, Long sourceId, DocumentSourceTypeEnum sourceType, DocumentTypeEnum fileType) { Map userInfo = validator.getUserInfoFromToken(request); Long userId = validator.getUserId(userInfo); + files.forEach(Utils::validateFileType); return documentDao.uploadFiles(userId,files,sourceId,sourceType,fileType); } @Override diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index 51091508..aa62ab23 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -38,6 +38,7 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.enums.MatchModeEnum; import net.gepafin.tendermanagement.model.request.GlobalFilters; +import net.gepafin.tendermanagement.web.rest.api.errors.*; import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; import org.apache.commons.collections4.MapUtils; @@ -55,13 +56,10 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import feign.FeignException; import io.micrometer.common.util.StringUtils; -import net.gepafin.tendermanagement.web.rest.api.errors.FeignClientForbiddenException; -import net.gepafin.tendermanagement.web.rest.api.errors.FeignClientNotFoundException; -import net.gepafin.tendermanagement.web.rest.api.errors.FeignClientUnauthorizedException; -import net.gepafin.tendermanagement.web.rest.api.errors.FeignClientValidationException; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; import javax.crypto.Cipher; import javax.crypto.Mac; @@ -932,4 +930,11 @@ public class Utils { Object obj = parentMap.get(key); return (obj instanceof String str) ? str : null; } + + public static void validateFileType(MultipartFile file) { + if (file.isEmpty()) { + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.VALIDATION_ERROR_FILE_EMPTY)); + } + } } \ No newline at end of file From cca4fe11007f4a69442309b5b0412f49d0f525fc Mon Sep 17 00:00:00 2001 From: piyushkag Date: Fri, 4 Apr 2025 19:05:23 +0530 Subject: [PATCH 05/14] Done ticket GEPAFINBE-205 Handled the old and new vatCheck company json through versioning. --- .../constants/GepafinConstant.java | 5 +- .../tendermanagement/dao/CompanyDao.java | 138 ++++----- .../gepafin/tendermanagement/dao/FormDao.java | 2 +- .../tendermanagement/dao/VatCheckDao.java | 268 ++++++++++-------- .../entities/GlobalConfigEntity.java | 21 ++ .../enums/VatCheckVersionTypeEnum.java | 19 ++ .../repositories/GlobalConfigRepository.java | 11 + .../service/CompanyService.java | 1 - ...eckService.java => VatCheckV1Service.java} | 10 +- .../feignClient/VatCheckV2Service.java | 19 ++ src/main/resources/application.properties | 3 +- .../db/changelog/db.changelog-1.0.0.xml | 27 ++ 12 files changed, 319 insertions(+), 205 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/GlobalConfigEntity.java create mode 100644 src/main/java/net/gepafin/tendermanagement/enums/VatCheckVersionTypeEnum.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/GlobalConfigRepository.java rename src/main/java/net/gepafin/tendermanagement/service/feignClient/{VatCheckService.java => VatCheckV1Service.java} (70%) create mode 100644 src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckV2Service.java diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index a87b2631..9ccfe7e5 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -136,8 +136,9 @@ public class GepafinConstant { public static final String UPDATING_FORM_VALUE_IMPACT_ON_FLOW = "updating.form.value.impact.on.flow"; public static final String APPLICATION_IS_INCOMPLETE_MSG = "application.is.incomplete"; public static final String AUTHORIZATION = "Authorization"; - public static final String CHECK_VATNUMBER_V2_NEW_URL = "https://imprese.openapi.it/advance"; - public static final String CHECK_VATNUMBER_V2_NEW_URL_IT_ADVANCE = "https://company.openapi.com/IT-advanced"; + public static final String CHECK_VATNUMBER_URL_V1 = "https://imprese.openapi.it/advance"; + public static final String CHECK_VATNUMBER_URL_V2 = "https://company.openapi.com/IT-advanced"; + public static final String VAT_CHECK_API_VERSION = "VAT_CHECK_API_VERSION"; public static final String VALIDATION_FIELD_CUSTOM = "validation.field.custom"; public static final String VALIDATION_CODICE_FISCALE = "validation.codice.fiscale"; public static final String VALIDATION_CAP = "validation.cap"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 909798e6..91a589e7 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -1,9 +1,7 @@ package net.gepafin.tendermanagement.dao; -import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.data.domain.Pageable; // Correct package -import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -20,7 +18,6 @@ import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; import net.gepafin.tendermanagement.repositories.ApplicationRepository; import net.gepafin.tendermanagement.repositories.FaqRepository; -import net.gepafin.tendermanagement.service.feignClient.VatCheckService; import net.gepafin.tendermanagement.util.LoggingUtil; import net.gepafin.tendermanagement.web.rest.api.errors.*; import org.apache.commons.lang3.StringUtils; @@ -37,7 +34,6 @@ import net.gepafin.tendermanagement.model.response.CompanyResponse; import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.util.Utils; -import static net.gepafin.tendermanagement.util.Utils.convertObjectToJsonString; import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; @Component @@ -73,10 +69,6 @@ public class CompanyDao { private HttpServletRequest request; - @Autowired - private VatCheckService vatCheckService; // Service to call VAT API - - private static final String NOT_FOUND_JSON = "{\"data\": \"not found\"}"; public CompanyResponse createCompany(UserEntity userEntity, CompanyRequest companyRequest) { @@ -146,8 +138,6 @@ public class CompanyDao { loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(userWithCompany).build()); if (StringUtils.isEmpty(companyEntity.getJson())) { companyEntity.setJson(Utils.convertMapIntoJsonString(companyRequest.getVatCheckResponse())); - Map vatCheckResponse = companyRequest.getVatCheckResponse(); - Map data = (Map) vatCheckResponse.get("data"); updateCodiceAtecoFieldWithNewJson(companyEntity); companyEntity = companyRepository.save(companyEntity); @@ -178,7 +168,7 @@ public class CompanyDao { entity.setAnnualRevenue(request.getAnnualRevenue()); entity.setHub(userEntity.getHub()); entity.setJson(Utils.convertMapIntoJsonString(request.getVatCheckResponse())); - updateCodiceAtecoFieldWithNewJson(entity); + updateCodiceAtecoFieldWithNewJson(entity); return entity; } @@ -437,7 +427,6 @@ public class CompanyDao { log.info("Company ID {}: JSON field updated successfully.", company.getId()); // Extract and set codiceAteco field -// updateCodiceAtecoField(company); updateCodiceAtecoFieldWithNewJson(company); successfulUpdates++; @@ -472,50 +461,38 @@ public class CompanyDao { private void updateCodiceAtecoField(CompanyEntity company) { Map vatCheckResponse = Utils.convertJsonStringToMap(company.getJson()); - if (vatCheckResponse != null && vatCheckResponse.containsKey("data")) { - Object dataObj = vatCheckResponse.get("data"); - - if (dataObj instanceof Map) { - Map dataMap = (Map) dataObj; - log.info("Company ID {}: Available keys inside 'data' -> {}", company.getId(), dataMap.keySet()); - - if (dataMap.containsKey("dettaglio")) { - Object dettaglioObj = dataMap.get("dettaglio"); - - if (dettaglioObj instanceof Map) { - Map dettaglio = (Map) dettaglioObj; - - if (dettaglio.containsKey("codice_ateco")) { - Object codiceAtecoObj = dettaglio.get("codice_ateco"); - - if (codiceAtecoObj instanceof String) { - String codiceAteco = (String) codiceAtecoObj; - - if (codiceAteco != null && !codiceAteco.isEmpty()) { - company.setCodiceAteco(codiceAteco); - log.info("Company ID {}: codiceAteco updated to {}", company.getId(), codiceAteco); - } else { - log.warn("Company ID {}: codiceAteco is null or empty in the response.", company.getId()); - } - } else { - log.warn("Company ID {}: 'codice_ateco' is not a string, actual type: {}", company.getId(), codiceAtecoObj.getClass()); - } - } else { - log.warn("Company ID {}: 'dettaglio' does not contain 'codice_ateco' key.", company.getId()); - } - } else { - log.warn("Company ID {}: 'dettaglio' is not a Map, actual type: {}", company.getId(), dettaglioObj.getClass()); - } - } else { - log.warn("Company ID {}: 'dettaglio' section is missing inside 'data'!", company.getId()); - } - } else { - log.warn("Company ID {}: 'data' is not a Map, actual type: {}", company.getId(), dataObj.getClass()); - } - } else { - log.warn("Company ID {}: 'data' section missing in the JSON response.", company.getId()); + if (vatCheckResponse == null) { + log.warn("Company ID {}: Invalid JSON response.", 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 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); } + private void updateCodiceAtecoFieldWithNewJson(CompanyEntity company) { if (company == null || company.getJson() == null || company.getJson().isEmpty()) { log.warn("Company is null or JSON data is empty."); @@ -530,32 +507,43 @@ public class CompanyDao { // Extract 'data' section Map dataMap = Utils.extractMap(companyDataMap, "data"); + Object dataObj = companyDataMap.get("data"); + if (dataMap == null) { log.warn("Company ID {}: 'data' section is missing or invalid in the JSON.", company.getId()); return; } - - // Extract 'atecoClassification' section - Map atecoClassificationMap = Utils.extractMap(dataMap, "atecoClassification"); - if (atecoClassificationMap == null) { - log.warn("Company ID {}: 'atecoClassification' section is missing or invalid.", company.getId()); - return; - } - - // Extract 'ateco' section - Map atecoMap = Utils.extractMap(atecoClassificationMap, "ateco"); - if (atecoMap == null) { - log.warn("Company ID {}: 'ateco' section is missing or invalid.", company.getId()); - return; - } - - // Extract and set 'code' - String atecoCode = Utils.extractString(atecoMap, "code"); - if (atecoCode != null && !atecoCode.isEmpty()) { - company.setCodiceAteco(atecoCode); - log.info("Company ID {}: codiceAteco updated to {}", company.getId(), atecoCode); + if (dataObj instanceof Map) { + // if data is a single object + updateCodiceAtecoField(company); } else { - log.warn("Company ID {}: 'code' inside 'ateco' is empty or missing.", company.getId()); + // Extract 'atecoClassification' section + Map atecoClassificationMap = Utils.extractMap(dataMap, "atecoClassification"); + if (atecoClassificationMap == null) { + log.warn("Company ID {}: 'atecoClassification' section is missing or invalid.", company.getId()); + return; + } + + // Extract 'ateco' section + Map atecoMap = Utils.extractMap(atecoClassificationMap, "ateco"); + if (atecoMap == null) { + log.warn("Company ID {}: 'ateco' section is missing or invalid.", company.getId()); + return; + } + + // Extract and set 'code' + String atecoCode = Utils.extractString(atecoMap, "code"); + if (atecoCode != null && !atecoCode.isEmpty()) { + company.setCodiceAteco(atecoCode); + logCodiceAtecoUpdate(company, atecoCode); + } else { + log.warn("Company ID {}: 'code' inside 'ateco' is empty or missing.", company.getId()); + } } } + + private static void logCodiceAtecoUpdate(CompanyEntity company, String atecoCode) { + + log.info("Company ID {}: codiceAteco updated to {}", company.getId(), atecoCode); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java b/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java index 702a3b44..598f6477 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/FormDao.java @@ -511,7 +511,7 @@ public class FormDao { // Map customData=null; try { // Map vatCheckResponse = vatCheckDao.checkVatNumberApi(value); - vatCheckDao.checkVatNumberApi(value); + vatCheckDao.checkVatNumber(value); // 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 073224dd..1c6869ad 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/VatCheckDao.java @@ -1,14 +1,15 @@ package net.gepafin.tendermanagement.dao; import feign.FeignException; -import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; -import net.gepafin.tendermanagement.entities.CompanyEntity; +import net.gepafin.tendermanagement.enums.VatCheckVersionTypeEnum; import net.gepafin.tendermanagement.model.response.VatCheckResponseBean; -import net.gepafin.tendermanagement.service.feignClient.VatCheckService; -import net.gepafin.tendermanagement.util.LoggingUtil; +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 org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -20,8 +21,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import java.net.URI; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -30,104 +31,103 @@ import java.util.Map; public class VatCheckDao { @Autowired - private VatCheckService vatCheckService; + private VatCheckV2Service vatCheckV2Service; - @Value("${vatCheckNewToken}") - public String vatCheckNewToken; + @Autowired + private VatCheckV1Service vatCheckV1Service; + + @Value("${vatCheckTokenV2}") + public String vatCheckTokenV2; + + @Value("${vatCheckTokenV1}") + public String vatCheckTokenV1; @Value("${isVatCheckGloballyDisabled}") public String isVatCheckGloballyDisabled; + @Autowired + private GlobalConfigRepository globalConfigRepository; + public final Logger log = LoggerFactory.getLogger(VatCheckDao.class); - @Autowired - private LoggingUtil loggingUtil; + public VatCheckResponseBean checkVatNumberV1(String vatNumber) { + VatCheckResponseBean vatCheckResponseBean = new VatCheckResponseBean(); + vatCheckResponseBean.setValid(false); + vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + if (Boolean.TRUE.equals(Boolean.parseBoolean(isVatCheckGloballyDisabled))) { + vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + return vatCheckResponseBean; + } + try { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set(GepafinConstant.AUTHORIZATION, "Bearer " + vatCheckTokenV1); + headers.add(org.apache.http.HttpHeaders.USER_AGENT, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0"); - @Autowired - private HttpServletRequest request; + URI baseUrl = URI.create(GepafinConstant.CHECK_VATNUMBER_URL_V1); + ResponseEntity> response = vatCheckV1Service.checkVatNumber(baseUrl, vatNumber, headers); -// public VatCheckResponseBean checkVatNumberApi(String vatNumber) { -// VatCheckResponseBean vatCheckResponseBean = new VatCheckResponseBean(); -// vatCheckResponseBean.setValid(false); -// vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); -// if (Boolean.TRUE.equals(Boolean.parseBoolean(isVatCheckGloballyDisabled))) { -// vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); -// return vatCheckResponseBean; -// } -// Map responseBody = new HashMap<>(); -// try { -// HttpHeaders headers = new HttpHeaders(); -// headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); -// headers.setContentType(MediaType.APPLICATION_JSON); -// headers.set(GepafinConstant.AUTHORIZATION, "Bearer " + vatCheckNewToken); -// headers.add(org.apache.http.HttpHeaders.USER_AGENT, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0"); -// -// URI baseUrl = URI.create(GepafinConstant.CHECK_VATNUMBER_V2_NEW_URL); -// ResponseEntity> response = vatCheckService.checkVatNumber(baseUrl, vatNumber, headers); -// -// -// if (response.getStatusCode() == HttpStatus.OK && response.hasBody()) { -// log.info("Successfully checked vat number"); -// Map responseMap = response.getBody(); -// processValidResponse(responseMap, vatCheckResponseBean); -// } -// } catch (FeignException ex) { -// if (ex.status() == 406) { -// try { -// Map errorResponse = Utils.parseErrorResponse(ex.contentUTF8()); -// processValidResponse(errorResponse, vatCheckResponseBean); -// } catch (Exception parseEx) { -// log.error("Failed to parse 406 error response: {0}", parseEx); -// } -// } else { -// log.error("Exception occurred while checking vat number: {0}", ex); -// Utils.callException(ex.status(), ex); -// } -// } -// return vatCheckResponseBean; -// } -// public static void processValidResponse(Map responseMap, VatCheckResponseBean vatCheckResponseBean) { -// if (responseMap != null && responseMap.containsKey("data")) { -// Map responseBody = (Map) responseMap.get("data"); -// -// if (responseBody != null) { -// responseBody.remove("timestamp_creation"); -// responseBody.remove("timestamp_last_update"); -// responseBody.remove("data_iscrizione"); -// responseBody.remove("id"); -// -// Map data = new LinkedHashMap<>(); -// data.put("data", responseBody); -// -// vatCheckResponseBean.setValid(true); -// vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.VALID_VATNUMBER_MSG)); -// vatCheckResponseBean.setVatCheckResponse(data); -// } else { -// vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); -// } -// } else { -// vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); -// } -// } -// -// public VatCheckResponseBean checkVatNumber(String vatNumber) { -// try { -// return checkVatNumberApi(vatNumber); -// } catch (Exception e) { -// log.error("Error in checkVatNumber: {}", e.getMessage()); -// VatCheckResponseBean vatCheckResponseBean = new VatCheckResponseBean(); -// vatCheckResponseBean.setValid(false); -// vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); -// return vatCheckResponseBean; -// } -// } + if (response.getStatusCode() == HttpStatus.OK && response.hasBody()) { + logSuccess(); + Map responseMap = response.getBody(); + if (responseMap != null) { + processValidResponseV1(responseMap, vatCheckResponseBean); + } else { + log.warn("Response map or vatCheckResponseBean is null."); + } + } + + } catch (FeignException ex) { + if (ex.status() == 406) { + try { + Map errorResponse = Utils.parseErrorResponse(ex.contentUTF8()); + processValidResponseV1(errorResponse, vatCheckResponseBean); + } catch (Exception parseEx) { + log.error("Failed to parse 406 error response: {0}", parseEx); + } + } else { + log.error("Exception occurred while checking vat number: {0}", ex); + Utils.callException(ex.status(), ex); + } + } + return vatCheckResponseBean; + } + + public static void processValidResponseV1(Map responseMap, VatCheckResponseBean vatCheckResponseBean) { + Object dataObj = responseMap.get("data"); + if (dataObj instanceof Map rawDataMap) { + Map responseBody = new LinkedHashMap<>(); + rawDataMap.forEach((k, v) -> { + if (k instanceof String strKey) { + responseBody.put(strKey, v); + } + }); + + List.of("timestamp_creation", "timestamp_last_update", "id", "data_iscrizione").forEach(responseBody.keySet()::remove); + + Map data = new LinkedHashMap<>(); + data.put("data", responseBody); + + vatCheckResponseBean.setValid(true); + vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.VALID_VATNUMBER_MSG)); + vatCheckResponseBean.setVatCheckResponse(data); + } else { + vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + } + + } public VatCheckResponseBean checkVatNumber(String vatNumber) { try { - return checkVatNumberApi(vatNumber); + String vatApiVersion = getVatCheckVersion(); + if(!isVatCheckApiV2(vatApiVersion)){ + return checkVatNumberV1(vatNumber); + } + return checkVatNumberV2(vatNumber); } catch (Exception e) { - log.error("Error in checkVatNumber: {}", e.getMessage()); + logErrorMessage(e); VatCheckResponseBean vatCheckResponseBean = new VatCheckResponseBean(); vatCheckResponseBean.setValid(false); vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); @@ -135,7 +135,7 @@ public class VatCheckDao { } } - public VatCheckResponseBean checkVatNumberApi(String vatNumber) { + public VatCheckResponseBean checkVatNumberV2(String vatNumber) { VatCheckResponseBean vatCheckResponseBean = new VatCheckResponseBean(); vatCheckResponseBean.setValid(false); @@ -147,13 +147,13 @@ public class VatCheckDao { try { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); - headers.set(GepafinConstant.AUTHORIZATION, "Bearer " + vatCheckNewToken); + headers.set(GepafinConstant.AUTHORIZATION, "Bearer " + vatCheckTokenV2); - URI baseUrl = URI.create(GepafinConstant.CHECK_VATNUMBER_V2_NEW_URL_IT_ADVANCE); - ResponseEntity> response = vatCheckService.checkVatNumber(baseUrl, vatNumber, headers); + URI baseUrl = URI.create(GepafinConstant.CHECK_VATNUMBER_URL_V2); + ResponseEntity> response = vatCheckV2Service.checkVatNumber(baseUrl, vatNumber, headers); if (response.getStatusCode() == HttpStatus.OK && response.hasBody()) { - log.info("Successfully checked vat number"); + logSuccess(); Map responseMap = response.getBody(); processValidResponse(responseMap, vatCheckResponseBean); } @@ -172,33 +172,65 @@ public class VatCheckDao { } return vatCheckResponseBean; } + public static void processValidResponse(Map responseMap, VatCheckResponseBean vatCheckResponseBean) { - if (responseMap != null && responseMap.containsKey("data")) { - Object dataObject = responseMap.get("data"); - - if (dataObject instanceof List && !((List) dataObject).isEmpty()) { - dataObject = ((List) dataObject).get(0); - } - - if (dataObject instanceof Map) { - Map responseBody = (Map) dataObject; - - responseBody.remove("creationTimestamp"); - responseBody.remove("lastUpdateTimestamp"); - responseBody.remove("id"); - - Map data = new LinkedHashMap<>(); - data.put("data", responseBody); - - vatCheckResponseBean.setValid(true); - vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.VALID_VATNUMBER_MSG)); - vatCheckResponseBean.setVatCheckResponse(data); - } else { - vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); - } - } else { + if (responseMap == null || !responseMap.containsKey("data")) { vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + return; } + + Object dataObject = responseMap.get("data"); + if (!(dataObject instanceof List dataList) || dataList.isEmpty()) { + vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + return; + } + + List> processedList = new ArrayList<>(); + + for (Object item : dataList) { + if (item instanceof Map mapItem) { + Map responseBody = new LinkedHashMap<>(); + mapItem.forEach((key, value) -> { + if (key instanceof String strKey) { + responseBody.put(strKey, value); + } + }); + + List.of("creationTimestamp", "lastUpdateTimestamp", "id").forEach(responseBody.keySet()::remove); + + processedList.add(responseBody); + } + } + + if (processedList.isEmpty()) { + vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.INVALID_VATNUMBER)); + return; + } + + vatCheckResponseBean.setValid(true); + vatCheckResponseBean.setMessage(Translator.toLocale(GepafinConstant.VALID_VATNUMBER_MSG)); + vatCheckResponseBean.setVatCheckResponse(Map.of("data", processedList)); + } + + private void logSuccess() { + + log.info("Successfully checked vat number"); + } + + private static boolean isVatCheckApiV2(String vatApiVersion) { + boolean isNotBlank = StringUtils.isNotBlank(vatApiVersion); + boolean isNotEmpty = StringUtils.isNotEmpty(vatApiVersion); + return isNotBlank && isNotEmpty && Boolean.TRUE.equals(vatApiVersion.equals(VatCheckVersionTypeEnum.V2.getValue())); + } + + private String getVatCheckVersion() { + + return globalConfigRepository.findContentByTypeAndIsDeletedFalse(GepafinConstant.VAT_CHECK_API_VERSION); + } + + private void logErrorMessage(Exception e) { + + log.error("Error in checkVatNumber: {}", e.getMessage()); } } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/GlobalConfigEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/GlobalConfigEntity.java new file mode 100644 index 00000000..3f55abdf --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/GlobalConfigEntity.java @@ -0,0 +1,21 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import lombok.Data; + +@Entity +@Data +@Table(name = "GLOBAL_CONFIG") +public class GlobalConfigEntity extends BaseEntity{ + + @Column(name = "CONTENT") + private String content; + + @Column(name = "TYPE") + private String type; + + @Column(name = "IS_DELETED") + private Boolean isDeleted = false; +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/VatCheckVersionTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/VatCheckVersionTypeEnum.java new file mode 100644 index 00000000..7d38f009 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/VatCheckVersionTypeEnum.java @@ -0,0 +1,19 @@ +package net.gepafin.tendermanagement.enums; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum VatCheckVersionTypeEnum { + V1("V1"), + V2("V2"); + private String value; + + VatCheckVersionTypeEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/GlobalConfigRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/GlobalConfigRepository.java new file mode 100644 index 00000000..1766884a --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/GlobalConfigRepository.java @@ -0,0 +1,11 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.GlobalConfigEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface GlobalConfigRepository extends JpaRepository { + + @Query("SELECT gc.content FROM GlobalConfigEntity gc WHERE gc.type = :vatCheckApiVersion AND gc.isDeleted = false") + String findContentByTypeAndIsDeletedFalse(String vatCheckApiVersion); +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java b/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java index ae752c04..74b6be0e 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java @@ -2,7 +2,6 @@ package net.gepafin.tendermanagement.service; import java.io.ByteArrayOutputStream; import java.util.List; -import java.util.Map; import net.gepafin.tendermanagement.model.request.LimitRequest; import net.gepafin.tendermanagement.model.response.VatCheckResponseBean; diff --git a/src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckService.java b/src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckV1Service.java similarity index 70% rename from src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckService.java rename to src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckV1Service.java index 84baa878..015beb70 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckV1Service.java @@ -11,13 +11,9 @@ import org.springframework.web.bind.annotation.RequestHeader; import java.net.URI; import java.util.Map; -@FeignClient(value = "vat-check-service", url = GepafinConstant.CHECK_VATNUMBER_V2_NEW_URL_IT_ADVANCE) -public interface VatCheckService { - +@FeignClient(value = "vat-check-v1-service", url = GepafinConstant.CHECK_VATNUMBER_URL_V1) +public interface VatCheckV1Service { @GetMapping("/{vatNumber}") - ResponseEntity> checkVatNumber(URI baseUrl, - @PathVariable("vatNumber") String vatNumber, - @RequestHeader HttpHeaders headers - ); + ResponseEntity> checkVatNumber(URI baseUrl, @PathVariable("vatNumber") String vatNumber, @RequestHeader HttpHeaders headers); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckV2Service.java b/src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckV2Service.java new file mode 100644 index 00000000..5dc07914 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/feignClient/VatCheckV2Service.java @@ -0,0 +1,19 @@ +package net.gepafin.tendermanagement.service.feignClient; + +import net.gepafin.tendermanagement.constants.GepafinConstant; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.net.URI; +import java.util.Map; + +@FeignClient(value = "vat-check-v2-service", url = GepafinConstant.CHECK_VATNUMBER_URL_V2) +public interface VatCheckV2Service { + + @GetMapping("/{vatNumber}") + ResponseEntity> checkVatNumber(URI baseUrl, @PathVariable("vatNumber") String vatNumber, @RequestHeader HttpHeaders headers); +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 54498aa1..9388e724 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -47,7 +47,8 @@ fe.base.url=https://bandi-staging.memento.credit spring.main.allow-circular-references=true isVatCheckGloballyDisabled = true -vatCheckNewToken: 671916c76c6e822f660774d4 +vatCheckTokenV1: 66026bd891a51044e90e08c4 +vatCheckTokenV2: 671916c76c6e822f660774d4 #SPID configuration spid.ipd.base.url=https://federatest.umbriadigitale.it 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 379e56e2..f4e71555 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 @@ -2695,4 +2695,31 @@ path="db/dump/create_application_amendment_request_view.sql"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + From b4b3720e33097ebc17ba883dc92ceae09d968a7a Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 7 Apr 2025 12:13:32 +0530 Subject: [PATCH 06/14] 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 db8e289f..bc453374 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -22,7 +22,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 0e5ea519..9cd21534 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -20,7 +20,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 0774a786..86ec0f29 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -29,7 +29,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 70239904..532deb3f 100644 --- a/src/main/resources/application-testing.properties +++ b/src/main/resources/application-testing.properties @@ -18,7 +18,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 9388e724..5373badb 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 d61787e96e0b879cf209c783187ae06af9e98c67 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Mon, 7 Apr 2025 12:15:08 +0530 Subject: [PATCH 07/14] 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 5373badb..9388e724 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 f379b954ed796b7d2d59a221bb09b17a6a2af374 Mon Sep 17 00:00:00 2001 From: piyushkag Date: Thu, 10 Apr 2025 14:55:08 +0530 Subject: [PATCH 08/14] 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 c34b63b3211ae4264dcead7b1cfaf350f460c50b Mon Sep 17 00:00:00 2001 From: piyushkag Date: Thu, 10 Apr 2025 18:07:21 +0530 Subject: [PATCH 09/14] Done Ticket GEPAFINBE-207 Updated the API to update the call status from Publish status to Draft. --- .../constants/GepafinConstant.java | 1 + .../gepafin/tendermanagement/dao/CallDao.java | 52 ++++++++++--------- .../repositories/ApplicationRepository.java | 1 + src/main/resources/message_en.properties | 3 +- src/main/resources/message_it.properties | 3 +- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 9ccfe7e5..edc85e28 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -101,6 +101,7 @@ public class GepafinConstant { public static final String STATUS_SAME_ERROR = "status.same.error"; public static final String INVALID_STATUS_CHANGE_FROM_DRAFT = "invalid.status.change.from.draft"; public static final String INVALID_STATUS_CHANGE_FROM_PUBLISH = "invalid.status.change.from.publish"; + public static final String INVALID_STATUS_CHANGE_FROM_PUBLISH_TO_DRAFT = "invalid.status.change.from.publish.to.draft"; public static final String STATUS_CANNOT_BE_CHANGED = "status.cannot.be.changed"; public static final String PUBLISHED_CALL_NOT_UPDATE = "published.call.not.update"; public static final String INVALID_USER = "invalid_user"; diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index 94c586b9..fa02eac1 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -124,6 +124,9 @@ public class CallDao { @Autowired private EvaluationFormDao evalualtionFormDao; + @Autowired + private ApplicationRepository applicationRepository; + public CallResponse createCallStep1(CreateCallRequestStep1 createCallRequest, UserEntity userEntity) { createCallRequest.setRegionId(userEntity.getRoleEntity().getRegion().getId()); CallEntity callEntity = convertToCallEntity(createCallRequest, userEntity); @@ -902,7 +905,7 @@ public class CallDao { public CallResponse updateCallStatus(CallEntity callEntity, CallStatusEnum statusReq) { CallEntity oldCallEntity = Utils.getClonedEntityForData(callEntity); CallStatusEnum currentStatus = CallStatusEnum.valueOf(callEntity.getStatus()); - validateStatusChange(currentStatus, statusReq); + validateStatusChange(currentStatus, statusReq, callEntity.getId()); callEntity.setStatus(statusReq.getValue()); callEntity = callRepository.save(callEntity); @@ -922,36 +925,37 @@ public class CallDao { return convertToCallResponseBean(callEntity); } - private void validateStatusChange(CallStatusEnum currentStatus, CallStatusEnum newStatus) { + private void validateStatusChange(CallStatusEnum currentStatus, CallStatusEnum newStatus, Long callId) { + if (currentStatus == newStatus) { - throw new CustomValidationException(Status.VALIDATION_ERROR, - Translator.toLocale(GepafinConstant.STATUS_SAME_ERROR)); + 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) { - throw new CustomValidationException(Status.VALIDATION_ERROR, - Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_DRAFT)); - } - break; - case PUBLISH: - if (newStatus == CallStatusEnum.READY_TO_PUBLISH || newStatus == CallStatusEnum.DRAFT) { - throw new CustomValidationException(Status.VALIDATION_ERROR, - Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_PUBLISH)); - } - break; + case DRAFT: + if (newStatus == CallStatusEnum.READY_TO_PUBLISH || newStatus == CallStatusEnum.PUBLISH) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_DRAFT)); + } + break; - case EXPIRED: - throw new CustomValidationException(Status.VALIDATION_ERROR, - Translator.toLocale(GepafinConstant.STATUS_CANNOT_BE_CHANGED)); - case READY_TO_PUBLISH: - break; - default: - break; + case PUBLISH: + if (newStatus == CallStatusEnum.READY_TO_PUBLISH) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_PUBLISH)); + } + if (newStatus == CallStatusEnum.DRAFT && Boolean.TRUE.equals(applicationRepository.existsByCallId(callId))) { + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.INVALID_STATUS_CHANGE_FROM_PUBLISH_TO_DRAFT)); + } + break; + case EXPIRED: + throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.STATUS_CANNOT_BE_CHANGED)); + + case READY_TO_PUBLISH: + break; + default: + break; } } + public CallEntity validatePublishedCall(Long callId, Long hubId) { CallEntity callEntity= callRepository .findByIdAndStatusAndHubId(callId, CallStatusEnum.PUBLISH.getValue(), hubId); diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java index b4fdfcaf..b5cf7fb9 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationRepository.java @@ -177,4 +177,5 @@ public interface ApplicationRepository extends JpaRepository Date: Fri, 11 Apr 2025 12:19:33 +0530 Subject: [PATCH 10/14] Fixed the message issue in response. --- src/main/resources/message_it.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index cbad9fd9..6e2352b7 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -61,8 +61,7 @@ invalid.status.change.from.draft=Lo stato non pu? essere cambiato in READY_TO_PU status.cannot.be.changed=Lo stato non pu? essere cambiato. published.call.not.update=Il bando pubblicato non pu? essere aggiornato. invalid.status.change.from.publish=Lo stato non pu? essere modificato in READY_TO_PUBLISH da PUBLISH. -invalid.status.change.from.publish.to.draft=Lo stato non può essere modificato da PUBLISH a DRAFT poiché sono già state create applicazioni per questa CALL. - +invalid.status.change.from.publish.to.draft=Lo stato non pu essere modificato da PUBLISH a DRAFT poich sono gi state create applicazioni per questa CALL. # Login-related messages login.successfully=Accesso effettuato con successo. From e2c19ccafb99bee72f6977fbbd82e2dbb0855664 Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 11 Apr 2025 12:21:25 +0530 Subject: [PATCH 11/14] 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 12/14] 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 13/14] 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 14/14] 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