package net.gepafin.tendermanagement.dao; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.enums.*; 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.AssignedApplicationsResponse; import net.gepafin.tendermanagement.model.response.PageableResponseBean; 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.service.ApplicationService; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.LoggingUtil; 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.ResourceNotFoundException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import static net.gepafin.tendermanagement.util.Utils.log; import static net.gepafin.tendermanagement.util.Utils.setIfUpdated; import static org.apache.commons.lang3.StringUtils.isEmpty; @Component public class AssignedApplicationsDao { @Autowired private ApplicationService applicationService; @Autowired private ApplicationRepository applicationRepository; @Autowired private AssignedApplicationsRepository assignedApplicationsRepository; @Autowired private UserService userService; @Autowired private Validator validator; @Autowired private ApplicationEvaluationDao applicationEvaluationDao; @Autowired private CompanyService companyService; @Autowired private LoggingUtil loggingUtil; @Autowired private HttpServletRequest request; @Autowired private ApplicationEvaluationRepository applicationEvaluationRepository; public AssignedApplicationsResponse createAssignedApplications(Long applicationId, Long userId, UserEntity assignedByUser, AssignedApplicationsRequest assignedApplicationsRequest) { log.info("Assigning application to pre-Instructor with details: {}", applicationId, userId); AssignedApplicationsEntity assignedApplications = assignedApplicationsRepository.findByApplicationIdAndIsDeletedFalse(applicationId).orElse(null); if (assignedApplications != null && assignedApplications.getUserId().equals(userId)) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_ASSIGNED)); } else if(assignedApplications != null) { assignedApplications = reassignApplication(userId, assignedByUser, assignedApplications); AssignedApplicationsResponse assignApplicationToInstructorResponse = convertEntityToResponse(assignedApplications); log.info("Application re-assigned succesfully {}", assignApplicationToInstructorResponse); return assignApplicationToInstructorResponse; } ApplicationEntity application = applicationService.validateApplication(applicationId); if (Boolean.FALSE.equals(ApplicationStatusTypeEnum.SUBMIT.getValue().equals(application.getStatus()))) { throw new CustomValidationException( Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.INVALID_APPLICATION_STATUS) ); } ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(application); application.setStatus(ApplicationStatusTypeEnum.EVALUATION.getValue()); applicationRepository.save(application); /** This code is responsible for adding a version history log for the "Update Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEntity).newData(application).build()); UserEntity user = userService.validateUser(userId); AssignedApplicationsEntity assignment = createAssignmentEntity(application, user.getId(), assignedByUser, assignedApplicationsRequest); applicationEvaluationDao.createOrUpdateApplicationEvaluation(user, new ApplicationEvaluationRequest(), assignment.getId()); AssignedApplicationsResponse assignApplicationToInstructorResponse = convertEntityToResponse(assignment); log.info("Application assigned succesfully {}", assignApplicationToInstructorResponse); return assignApplicationToInstructorResponse; } private AssignedApplicationsEntity reassignApplication(Long userId, UserEntity assignedByUser, AssignedApplicationsEntity assignedApplication) { AssignedApplicationsEntity oldAssignedApplicationEntity = Utils.getClonedEntityForData(assignedApplication); setIfUpdated(assignedApplication::getAssignedBy, assignedApplication::setAssignedBy, assignedByUser.getId()); setIfUpdated(assignedApplication::getUserId, assignedApplication::setUserId, userId); assignedApplication.setAssignedAt(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); assignedApplication.setStatus(AssignedApplicationEnum.AWAITING.getValue()); Optional entityOptional = applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse(assignedApplication.getId()); if(entityOptional.isPresent()) { ApplicationEvaluationEntity oldApplicationEvaluationEntity = Utils.getClonedEntityForData(entityOptional.get()); setIfUpdated(entityOptional.get()::getUserId, entityOptional.get()::setUserId, userId); applicationEvaluationRepository.save(entityOptional.get()); /** This code is responsible for adding a version history log for the "Create Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationEvaluationEntity).newData(entityOptional.get()).build()); }; assignedApplication = assignedApplicationsRepository.save(assignedApplication); /** This code is responsible for adding a version history log for the "Create Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldAssignedApplicationEntity).newData(assignedApplication).build()); return assignedApplication; } public AssignedApplicationsEntity createAssignmentEntity(ApplicationEntity application, Long userId, UserEntity assignedByUser, AssignedApplicationsRequest assignedApplicationsRequest) { AssignedApplicationsEntity assignApplication = new AssignedApplicationsEntity(); assignApplication.setApplication(application); assignApplication.setAssignedBy(assignedByUser.getId()); assignApplication.setUserId(userId); assignApplication.setStatus(AssignedApplicationEnum.AWAITING.getValue()); assignApplication.setNote(assignedApplicationsRequest.getNote()); assignApplication.setIsDeleted(false); assignApplication.setAssignedAt(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); AssignedApplicationsEntity assignedApplicationsEntity = saveAssignedApplication(assignApplication, null, VersionActionTypeEnum.INSERT); return assignedApplicationsEntity; } public AssignedApplicationsEntity saveAssignedApplication(AssignedApplicationsEntity assignedApplicationsEntity, AssignedApplicationsEntity oldAssignedApplicationEntity, VersionActionTypeEnum actionTypeEnum) { AssignedApplicationsEntity assignedApplication = assignedApplicationsRepository.save(assignedApplicationsEntity); /** This code is responsible for adding a version history log for the "Create Application" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(actionTypeEnum).oldData(oldAssignedApplicationEntity).newData(assignedApplication).build()); return assignedApplication; } public AssignedApplicationsResponse convertEntityToResponse(AssignedApplicationsEntity assignedApplications) { AssignedApplicationsResponse assignedApplicationsResponse = new AssignedApplicationsResponse(); assignedApplicationsResponse.setId(assignedApplications.getId()); assignedApplicationsResponse.setApplicationId(assignedApplications.getApplication().getId()); ApplicationEntity application = applicationService.validateApplication(assignedApplications.getApplication().getId()); String callName = application.getCall() != null ? application.getCall().getName() : ""; Optional applicationEvaluationEntity=applicationEvaluationRepository.findByApplicationIdAndIsDeletedFalse(application.getId()); LocalDateTime callEndDate = application.getCall().getEndDate(); LocalDateTime callStartDate = application.getCall().getStartDate(); Long protocolNumber = (application.getProtocol() != null && application.getProtocol().getProtocolNumber() != null) ? application.getProtocol().getProtocolNumber() : 0; LocalDateTime submissionDate = application.getSubmissionDate(); UserEntity userEntity = userService.validateUser(application.getUserId()); String firstName = userEntity.getBeneficiary() != null ? userEntity.getBeneficiary().getFirstName() : null; String lastName = userEntity.getBeneficiary() != null ? userEntity.getBeneficiary().getLastName() : null; String beneficiaryName = (firstName != null && !firstName.isBlank() ? firstName : "") + (lastName != null && !lastName.isBlank() ? " " + lastName : ""); beneficiaryName = beneficiaryName.isBlank() ? "" : beneficiaryName; assignedApplicationsResponse.setAssignedBy(assignedApplications.getAssignedBy()); assignedApplicationsResponse.setUserId(assignedApplications.getUserId()); assignedApplicationsResponse.setCreatedDate(assignedApplications.getCreatedDate()); assignedApplicationsResponse.setUpdatedDate(assignedApplications.getUpdatedDate()); assignedApplicationsResponse.setNote(assignedApplications.getNote()); assignedApplicationsResponse.setStatus(AssignedApplicationEnum.valueOf(assignedApplications.getStatus())); assignedApplicationsResponse.setAssignedAt(assignedApplications.getAssignedAt()); assignedApplicationsResponse.setProtocolNumber(protocolNumber); assignedApplicationsResponse.setCallName(callName); CompanyEntity company=companyService.validateCompany(application.getCompanyId()); assignedApplicationsResponse.setCompanyName(company.getCompanyName()); assignedApplicationsResponse.setBeneficiaryName(beneficiaryName); assignedApplicationsResponse.setSubmissionDate(submissionDate); assignedApplicationsResponse.setCallEndDate(callEndDate); assignedApplicationsResponse.setCallStartDate(callStartDate); assignedApplicationsResponse.setEvaluationVersion(EvaluationVersionEnum.valueOf(application.getCall().getEvaluationVersion())); if(applicationEvaluationEntity.isPresent()){ assignedApplicationsResponse.setEvaluationEndDate(applicationEvaluationEntity.get().getEndDate()); } assignedApplicationsResponse.setNumberOfCheck(application.getCall().getNumberOfCheck()); assignedApplicationsResponse.setAppointmentTemplateId(application.getCall().getAppointmentTemplateId()); assignedApplicationsResponse.setNdg(application.getNdg()); assignedApplicationsResponse.setAppointmentId(application.getAppointmentId()); return assignedApplicationsResponse; } public AssignedApplicationsEntity validateAssignedApplication(Long id) { AssignedApplicationsEntity assignedApplication = assignedApplicationsRepository.findByIdAndIsDeletedFalse(id).orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.ASSIGNED_APPLICATION_NOT_FOUND_MSG))); return assignedApplication; } public void deleteById(HttpServletRequest request, Long id) { log.info("Deleting assigned application with ID: {}", id); AssignedApplicationsEntity assignedApplicationsEntity = validateAssignedApplication(id); validator.validatePreInstructor(request, assignedApplicationsEntity.getUserId()); AssignedApplicationsEntity oldAssignedApplicationEntity = Utils.getClonedEntityForData(assignedApplicationsEntity); assignedApplicationsEntity.setIsDeleted(true); assignedApplicationsEntity = saveAssignedApplication(assignedApplicationsEntity, oldAssignedApplicationEntity, VersionActionTypeEnum.SOFT_DELETE); log.info("Assigned Application deleted with ID: {}", id); } public List getAllAssignedApplications(HttpServletRequest request, Long userId,List statusList) { UserEntity user = validator.validateUser(request); if(validator.checkIsPreInstructor() && userId == null) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.USER_ID_NOT_NULL_MSG)); } if(userId != null) { validator.validatePreInstructor(request, userId); } Specification spec = search(user.getHub().getId() ,userId,statusList); List assignedApplicationsEntityList = assignedApplicationsRepository.findAll(spec); return assignedApplicationsEntityList.stream() .map(entity -> convertEntityToResponse(entity)) .collect(Collectors.toList()); } private Specification search(Long hubId, Long userId,List statusList) { return (root, query, builder) -> { Predicate predicate = builder.isFalse(root.get("isDeleted")); if (userId != null) { predicate = builder.and(predicate, builder.equal(root.get("userId"), userId)); } if (statusList != null && !statusList.isEmpty()) { List statusNames = statusList.stream() .map(Enum::name) .collect(Collectors.toList()); predicate = builder.and(predicate, root.get("status").in(statusNames)); } query.orderBy( builder.desc(builder.isNotNull(root.get(GepafinConstant.ASSIGNED_AT))), builder.desc(root.get(GepafinConstant.ASSIGNED_AT)) ); predicate = builder.and(predicate, builder.equal(root.get("application").get("hubId"), hubId)); return predicate; }; } public AssignedApplicationsResponse updateAssignedApplication(HttpServletRequest request, Long id, UpdateAssignedApplicationRequest updateRequest) { UserEntity updatedByUser = validator.validateUser(request); log.info("Updating assigned application with ID: {}", id); AssignedApplicationsEntity existingAssignment = validateAssignedApplication(id); validator.validatePreInstructor(request, existingAssignment.getUserId()); AssignedApplicationsEntity oldAssignedApplicationEntity = Utils.getClonedEntityForData(existingAssignment); setIfUpdated(existingAssignment::getNote, existingAssignment::setNote, updateRequest.getNote()); setIfUpdated(existingAssignment::getStatus, existingAssignment::setStatus, updateRequest.getStatus().name()); setIfUpdated(existingAssignment::getAssignedBy, existingAssignment::setAssignedBy, updatedByUser.getId()); setIfUpdated(existingAssignment::getUserId, existingAssignment::setUserId, updateRequest.getUserId()); Optional entityOptional = applicationEvaluationRepository.findByAssignedApplicationsEntity_IdAndIsDeletedFalse(id); entityOptional.ifPresent(applicationEvaluationEntity -> setIfUpdated(applicationEvaluationEntity::getUserId, applicationEvaluationEntity::setUserId, updateRequest.getUserId())); existingAssignment.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); AssignedApplicationsEntity updatedAssignment = saveAssignedApplication(existingAssignment, oldAssignedApplicationEntity, VersionActionTypeEnum.UPDATE); AssignedApplicationsResponse response = convertEntityToResponse(updatedAssignment); log.info("Assigned application updated successfully: {}", response); return response; } public AssignedApplicationsResponse getAssignedApplicationById(HttpServletRequest request, Long id) { log.info("Fetching assigned application with ID: {}", id); AssignedApplicationsEntity assignedApplication = validateAssignedApplication(id); validator.validatePreInstructor(request, assignedApplication.getUserId()); AssignedApplicationsResponse response = convertEntityToResponse(assignedApplication); log.info("Assigned application fetched successfully: {}", response); return response; } public PageableResponseBean> getAllAssignedApplicationsByPagination(UserEntity user, AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean,Long userId) { Integer pageNo = null; Integer pageLimit = null; if (assignedApplicationPageableRequestBean.getGlobalFilters() != null) { pageNo = assignedApplicationPageableRequestBean.getGlobalFilters().getPage(); pageLimit = assignedApplicationPageableRequestBean.getGlobalFilters().getLimit(); } if (pageLimit == null || pageLimit <= 0) { pageLimit = GepafinConstant.DEFAULT_PAGE_LIMIT; } 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)); // Prepare the response List assignedApplicationsResponses = entityPage.getContent().stream() .map(application -> { AssignedApplicationsResponse response = convertEntityToResponse(application); return response; }) .collect(Collectors.toList()); PageableResponseBean> pageableResponseBean = new PageableResponseBean<>(); pageableResponseBean.setBody(assignedApplicationsResponses); pageableResponseBean.setCurrentPage(entityPage.getNumber() + 1); pageableResponseBean.setTotalPages(entityPage.getTotalPages()); pageableResponseBean.setTotalRecords(entityPage.getTotalElements()); pageableResponseBean.setPageSize(entityPage.getSize()); return pageableResponseBean; } public Specification searchByPagination(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, UserEntity userEntity,Long userId) { return (root, query, criteriaBuilder) -> { List predicates = getPredicates(assignedApplicationPageableRequestBean, criteriaBuilder, root, userEntity,userId); SortBy sortBy = new SortBy(GepafinConstant.CREATED_DATE, true); if (assignedApplicationPageableRequestBean.getGlobalFilters() != null && assignedApplicationPageableRequestBean.getGlobalFilters().getSortBy() != null && assignedApplicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName() != null && Boolean.FALSE.equals( isEmpty(assignedApplicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName()))) { sortBy.setColumnName(assignedApplicationPageableRequestBean.getGlobalFilters().getSortBy().getColumnName()); sortBy.setSortDesc(true); if (assignedApplicationPageableRequestBean.getGlobalFilters().getSortBy().getSortDesc() != null) { sortBy.setSortDesc(assignedApplicationPageableRequestBean.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(AssignedApplicationPageableRequestBean assignedApplicationPageableRequestBean, CriteriaBuilder criteriaBuilder, Root root, UserEntity userEntity,Long userId) { Integer year = null; String search = null; if (assignedApplicationPageableRequestBean.getGlobalFilters() != null) { year = assignedApplicationPageableRequestBean.getGlobalFilters().getYear(); search = assignedApplicationPageableRequestBean.getGlobalFilters().getSearch(); } List predicates = new ArrayList<>(); Boolean isBeneficiary = validator.checkIsBeneficiary(); if (userId!=null) { predicates.add(criteriaBuilder.equal(root.get(GepafinConstant.USER_ID), userId)); } if (year != null && year > 0) { int filterYear = assignedApplicationPageableRequestBean.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.NOTE)), "%" + search.toUpperCase() + "%" ); predicates.add(criteriaBuilder.or(titlePredicate)); } // Filter by `status` (if status list is provided) if (assignedApplicationPageableRequestBean.getStatus() != null && !assignedApplicationPageableRequestBean.getStatus().isEmpty()) { List statusValues = assignedApplicationPageableRequestBean.getStatus().stream() .map(AssignedApplicationEnum::name) // Convert enum to string .toList(); predicates.add(root.get(GepafinConstant.STATUS).in(statusValues)); } predicates.add(criteriaBuilder.isFalse(root.get(GepafinConstant.IS_DELETED))); return predicates; } public AssignedApplicationsResponse updateAssignedApplicationStatus(HttpServletRequest request, Long assignedApplicationId, AssignedApplicationEnum status) { AssignedApplicationsEntity assignedApplication = validateAssignedApplication(assignedApplicationId); validator.validatePreInstructor(request, assignedApplication.getUserId()); AssignedApplicationsEntity oldAssignedApplicationEntity = Utils.getClonedEntityForData(assignedApplication); assignedApplication.setStatus(status.getValue()); AssignedApplicationsEntity updatedAssignment = saveAssignedApplication(assignedApplication, oldAssignedApplicationEntity, VersionActionTypeEnum.UPDATE); return convertEntityToResponse(updatedAssignment); } }