diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 8e469734..1c31a2c7 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -426,7 +426,24 @@ public class GepafinConstant { public static final String APPOINTMENT_CANNOT_BE_CREATED = "appointment.cannot.be.created"; public static final String APPOINTMENT_NOT_CREATED = "appointment.not.created"; -} + public static final String CONTAINS = "contains"; + public static final String EQUALS = "equals"; + public static final String STARTS_WITH = "starts_with"; + public static final String ENDS_WITH = "ends_with"; + public static final String CALL_TITLE = "callTitle"; + public static final String CALL_ID="callId"; + public static final String CALL_END_DATE="callEndDate"; + public static final String END_DATE="endDate"; + public static final String PROTOCOL="protocol"; + public static final String PROTOCOL_NUMBER="protocolNumber"; + public static final String MODIFIED_DATE="modifiedDate"; + public static final String CALL_END_TIME="callEndTime"; + public static final String END_TIME="endTime"; + public static final String UPDATED_DATE="updatedDate"; + public static final String BEFORE="before"; + public static final String AFTER="after"; + + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index a8e1ca8d..d749897b 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -1,7 +1,6 @@ package net.gepafin.tendermanagement.dao; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.Root; +import jakarta.persistence.criteria.*; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.config.jwt.TokenProvider; import net.gepafin.tendermanagement.constants.GepafinConstant; @@ -42,7 +41,6 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; -import jakarta.persistence.criteria.Predicate; import jakarta.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; @@ -55,6 +53,7 @@ import java.text.ParseException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1444,7 +1443,7 @@ public class ApplicationDao { 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(); @@ -1455,7 +1454,7 @@ public class ApplicationDao { if (pageNo == null || pageNo <= 0) { pageNo = GepafinConstant.DEFAULT_PAGE; } - Specification spec = search(callId,companyId, userWithCompany.getId(), applicationPageableRequestBean, userEntity); + Specification spec = search(callId,companyId, userWithCompanyId, applicationPageableRequestBean, userEntity); Page entityPage = applicationRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit)); // Prepare the response @@ -1510,11 +1509,15 @@ public class ApplicationDao { 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(); @@ -1567,13 +1570,98 @@ public class ApplicationDao { LocalDateTime pastDate = today.minusDays(daysRange); predicates.add(criteriaBuilder.between(root.get(GepafinConstant.CREATED_DATE), pastDate, today)); } - predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); + 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(); + String matchMode = filterCriteria.getMatchMode(); + + if (value != null && matchMode != null) { + Path fieldPath = getFieldPath(root, fieldName); + if (fieldPath != null) { + applyStringFilter(fieldPath, criteriaBuilder, predicates, value, matchMode); + applyNumberFilter(fieldPath, criteriaBuilder, predicates, value, matchMode); + // applyDateFilter(fieldPath, criteriaBuilder, predicates, value, matchMode); // Date filter is commented + } + } + } + } + } + + private void applyStringFilter(Path fieldPath, CriteriaBuilder criteriaBuilder, List predicates, Object value, String matchMode) { + if (value instanceof String) { + String valueStr = (String) value; + if (fieldPath.getJavaType().equals(String.class)) { + switch (matchMode.toLowerCase()) { + case GepafinConstant.CONTAINS -> + predicates.add(criteriaBuilder.like(criteriaBuilder.lower(fieldPath.as(String.class)), "%" + valueStr.toLowerCase() + "%")); + case GepafinConstant.EQUALS -> predicates.add(criteriaBuilder.equal(fieldPath, valueStr)); + case GepafinConstant.STARTS_WITH -> + predicates.add(criteriaBuilder.like(criteriaBuilder.lower(fieldPath.as(String.class)), valueStr.toLowerCase() + "%")); + case GepafinConstant.ENDS_WITH -> + predicates.add(criteriaBuilder.like(criteriaBuilder.lower(fieldPath.as(String.class)), "%" + valueStr.toLowerCase())); + } + } + } + } + + private void applyNumberFilter(Path fieldPath, CriteriaBuilder criteriaBuilder, List predicates, Object value, String matchMode) { + if (Number.class.isAssignableFrom(fieldPath.getJavaType())) { + Number numberValue = null; + if (value instanceof Number) { + numberValue = (Number) value; + } + switch (matchMode.toLowerCase()) { + case GepafinConstant.EQUALS -> predicates.add(criteriaBuilder.equal(fieldPath, numberValue)); + } + } + } + +/* +private void applyDateFilter(Path fieldPath, CriteriaBuilder criteriaBuilder, List predicates, Object value, String matchMode) { + if (fieldPath.getJavaType().equals(LocalDateTime.class)) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + LocalDateTime dateValue = LocalDateTime.parse(value.toString(), formatter); + + Expression fieldAsString = criteriaBuilder.function("TO_CHAR", String.class, fieldPath, criteriaBuilder.literal("YYYY-MM-DD HH24:MI:SS.MS")); + + switch (matchMode.toLowerCase()) { + case GepafinConstant.EQUALS -> predicates.add(criteriaBuilder.equal(fieldAsString, value.toString())); + case GepafinConstant.BEFORE -> predicates.add(criteriaBuilder.lessThan(fieldPath.as(LocalDateTime.class), dateValue)); + case GepafinConstant.AFTER -> predicates.add(criteriaBuilder.greaterThan(fieldPath.as(LocalDateTime.class), dateValue)); + } + } +} +*/ + + private Path getFieldPath(Root root, String fieldName) { + try { + return switch (fieldName) { + case GepafinConstant.CALL_ID -> root.get(GepafinConstant.CALL).get(GepafinConstant.ID); + case GepafinConstant.CALL_TITLE -> root.get(GepafinConstant.CALL).get(GepafinConstant.NAME); + case GepafinConstant.CALL_END_DATE -> root.get(GepafinConstant.CALL).get(GepafinConstant.END_DATE); + case GepafinConstant.CALL_END_TIME -> root.get(GepafinConstant.CALL).get(GepafinConstant.END_TIME); + case GepafinConstant.MODIFIED_DATE -> root.get(GepafinConstant.CALL).get(GepafinConstant.UPDATED_DATE); + case GepafinConstant.PROTOCOL_NUMBER-> root.get(GepafinConstant.PROTOCOL).get(GepafinConstant.PROTOCOL_NUMBER); + default -> root.get(fieldName); + }; + } catch (IllegalArgumentException e) { + return null; + } + } + + public void checkCallEndDate(CallEntity call) { LocalDateTime now = DateTimeUtil.DateServerToUTC(LocalDateTime.now()); diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationPageableRequestBean.java b/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationPageableRequestBean.java index 153164d6..d6468973 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationPageableRequestBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/ApplicationPageableRequestBean.java @@ -4,6 +4,7 @@ import lombok.Data; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import java.util.List; +import java.util.Map; @Data public class ApplicationPageableRequestBean { @@ -13,4 +14,6 @@ public class ApplicationPageableRequestBean { private Integer daysRange; private List status; + + private Map filters; } diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/FilterCriteria.java b/src/main/java/net/gepafin/tendermanagement/model/request/FilterCriteria.java new file mode 100644 index 00000000..df7eaf69 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/request/FilterCriteria.java @@ -0,0 +1,10 @@ +package net.gepafin.tendermanagement.model.request; + +import lombok.Data; + +@Data +public class FilterCriteria { + + private Object value; + private String matchMode; +}