Merge pull request #228 from Kitzanos/feature/GEPAFINBE-173

GEPAFINBE-173 ( Apply search filter for application pagination endpoint )
This commit is contained in:
Rinaldo
2025-02-27 08:37:37 +01:00
committed by GitHub
6 changed files with 170 additions and 7 deletions

View File

@@ -465,6 +465,16 @@ 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 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 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 SWITCH="switch";
public static final String IS_CHECK_LIST_ITEM="isChecklistItem";
public static final String VALIDATION_FAILED_FOR_CHECKLIST="validation.failed.checklist";

View File

@@ -1,9 +1,7 @@
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;
import net.gepafin.tendermanagement.entities.*;
import net.gepafin.tendermanagement.entities.SystemEmailTemplatesEntity.SystemEmailTemplatesEntityTypeEnum;
@@ -42,19 +40,21 @@ 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;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -64,6 +64,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.hibernate.validator.internal.engine.messageinterpolation.el.RootResolver.FORMATTER;
@Component
public class ApplicationDao {
@@ -1444,7 +1445,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 +1456,7 @@ public class ApplicationDao {
if (pageNo == null || pageNo <= 0) {
pageNo = GepafinConstant.DEFAULT_PAGE;
}
Specification<ApplicationEntity> spec = search(callId,companyId, userWithCompany.getId(), applicationPageableRequestBean, userEntity);
Specification<ApplicationEntity> spec = search(callId,companyId, userWithCompanyId, applicationPageableRequestBean, userEntity);
Page<ApplicationEntity> entityPage = applicationRepository.findAll(spec, PageRequest.of(pageNo - 1, pageLimit));
// Prepare the response
@@ -1510,11 +1511,15 @@ public class ApplicationDao {
Integer year = null;
String search = null;
Integer daysRange = null;
Map<String, FilterCriteria> 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<Predicate> predicates = new ArrayList<>();
Boolean isBeneficiary = validator.checkIsBeneficiary();
@@ -1583,6 +1588,8 @@ public class ApplicationDao {
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()));
@@ -1590,6 +1597,95 @@ public class ApplicationDao {
return predicates;
}
private void applyFilters(Root<?> root, CriteriaBuilder criteriaBuilder, List<Predicate> predicates, Map<String, FilterCriteria> filters) {
if (Boolean.FALSE.equals(filters.isEmpty())) {
for (Map.Entry<String, FilterCriteria> 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 = getFieldPath(root, fieldName);
if (fieldPath != null) {
applyStringFilter(fieldPath, criteriaBuilder, predicates, value, matchMode);
applyNumberFilter(fieldPath, criteriaBuilder, predicates, value, matchMode);
applyDateFilter(fieldPath, criteriaBuilder, predicates, value, matchMode,root);
}
}
}
}
}
private void applyStringFilter(Path<?> fieldPath, CriteriaBuilder criteriaBuilder, List<Predicate> predicates, Object value, MatchModeEnum matchMode) {
if (value instanceof String) {
String valueStr = (String) value;
if (fieldPath.getJavaType().equals(String.class)) {
MatchModeEnum mode = MatchModeEnum.fromObject(matchMode.getValue());
switch (mode) {
case CONTAINS ->
predicates.add(criteriaBuilder.like(criteriaBuilder.lower(fieldPath.as(String.class)), "%" + valueStr.toLowerCase() + "%"));
case EQUALS -> predicates.add(criteriaBuilder.equal(fieldPath, valueStr));
case STARTSWITH ->
predicates.add(criteriaBuilder.like(criteriaBuilder.lower(fieldPath.as(String.class)), valueStr.toLowerCase() + "%"));
case ENDSWITH ->
predicates.add(criteriaBuilder.like(criteriaBuilder.lower(fieldPath.as(String.class)), "%" + valueStr.toLowerCase()));
}
}
}
}
private void applyNumberFilter(Path<?> fieldPath, CriteriaBuilder criteriaBuilder, List<Predicate> predicates, Object value, MatchModeEnum matchMode) {
if (Number.class.isAssignableFrom(fieldPath.getJavaType())) {
Number numberValue = null;
if (value instanceof Number) {
numberValue = (Number) value;
}
MatchModeEnum mode = MatchModeEnum.fromObject(matchMode.getValue());
switch (mode) {
case EQUALS -> predicates.add(criteriaBuilder.equal(fieldPath, numberValue));
}
}
}
private void applyDateFilter(Path<?> fieldPath, CriteriaBuilder criteriaBuilder, List<Predicate> predicates, Object value, MatchModeEnum matchMode, Root<?> root) {
if (fieldPath.getJavaType().equals(LocalDateTime.class)) {
LocalDateTime testDateTime = DateTimeUtil.parseStringToLocalDateTime(value.toString());
MatchModeEnum mode = MatchModeEnum.fromObject(matchMode.getValue());
switch (mode) {
// case DATEIS -> predicates.add(criteriaBuilder.equal(fieldPath.as(Timestamp.class), Timestamp.valueOf(testDateTime)));
case DATEISNOT -> predicates.add(criteriaBuilder.notEqual(fieldPath.as(Timestamp.class), Timestamp.valueOf(testDateTime)));
case BEFORE -> predicates.add(criteriaBuilder.lessThan(fieldPath.as(Timestamp.class), Timestamp.valueOf(testDateTime)));
case AFTER -> predicates.add(criteriaBuilder.greaterThan(fieldPath.as(Timestamp.class), Timestamp.valueOf(testDateTime)));
}
}
}
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());

View File

@@ -0,0 +1,39 @@
package net.gepafin.tendermanagement.enums;
import com.fasterxml.jackson.annotation.JsonValue;
public enum MatchModeEnum {
STARTSWITH("Starts with"),
ENDSWITH("Ends with"),
CONTAINS("Contains"),
EQUALS("Equals"),
DATEIS("Date is"),
DATEISNOT("Date is not"),
BEFORE("Date is before"),
AFTER("Date is after");
private String value;
MatchModeEnum(String value) {
this.value = value;
}
public static MatchModeEnum fromObject(Object value) {
if (value instanceof String) {
String strValue = ((String) value).trim();
for (MatchModeEnum mode : MatchModeEnum.values()) {
if (mode.getValue().equalsIgnoreCase(strValue)) {
return mode;
}
}
}
throw new IllegalArgumentException("Invalid MatchModeEnum: " + value);
}
@JsonValue
public String getValue() {
return value;
}
}

View File

@@ -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<ApplicationStatusTypeEnum> status;
private Map<String, FilterCriteria> filters;
}

View File

@@ -0,0 +1,11 @@
package net.gepafin.tendermanagement.model.request;
import lombok.Data;
import net.gepafin.tendermanagement.enums.MatchModeEnum;
@Data
public class FilterCriteria {
private Object value;
private MatchModeEnum matchMode;
}

View File

@@ -92,6 +92,10 @@ public class DateTimeUtil {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(dateTimeStr, formatter);
}
public static LocalDateTime parseStringToLocalDateTime(String timestampStr) {
// Use ISO_LOCAL_DATE_TIME to parse the input string
return LocalDateTime.parse(timestampStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
public static String parseLocalTimeToString(LocalTime time, String format) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);