package net.gepafin.tendermanagement.dao; import jakarta.persistence.criteria.Predicate; import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity; import net.gepafin.tendermanagement.entities.AssignedApplicationsEntity; import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.AssignedApplicationEnum; import net.gepafin.tendermanagement.enums.EvaluationVersionEnum; import net.gepafin.tendermanagement.model.request.ApplicationEvaluationRequest; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; 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.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.jpa.domain.Specification; import org.springframework.stereotype.Component; import java.time.LocalDateTime; 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; @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())); 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.OPEN.getValue()); if (assignedApplicationsRequest.getStatus() != null) { assignApplication.setStatus(assignedApplicationsRequest.getStatus().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()); } 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) { 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); List assignedApplicationsEntityList = assignedApplicationsRepository.findAll(spec); return assignedApplicationsEntityList.stream() .map(entity -> convertEntityToResponse(entity)) .collect(Collectors.toList()); } private Specification search(Long hubId, Long userId) { return (root, query, builder) -> { Predicate predicate = builder.isFalse(root.get("isDeleted")); if (userId != null) { predicate = builder.and(predicate, builder.equal(root.get("userId"), userId)); } 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; } }