package net.gepafin.tendermanagement.dao; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.CallStatusEnum; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; import net.gepafin.tendermanagement.model.request.*; import net.gepafin.tendermanagement.model.response.ContentResponseBean; import net.gepafin.tendermanagement.model.response.FormResponseBean; import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.EvaluationCriteriaService; 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.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.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.text.MessageFormat; import java.time.LocalDateTime; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @Component public class FormDao { private final Logger log = LoggerFactory.getLogger(FormDao.class); @Autowired private FormRepository formRepository; @Autowired private ApplicationFormRepository applicationFormRepository; @Autowired private CallDao callDao; @Autowired private FlowDataRepository flowDataRepository; @Autowired private FlowEdgesRepository flowEdgesRepository; @Autowired private VatCheckDao vatCheckDao; @Autowired private CallRepository callRepository; @Autowired private Validator validator; @Autowired private CriteriaFormFieldRepository criteriaFormFieldRepository; @Autowired private EvaluationCriteriaService evaluationCriteriaService; @Autowired private LoggingUtil loggingUtil; @Autowired private HttpServletRequest request; @Autowired private ApplicationDao applicationDao; public FormEntity saveFormEntity(FormEntity formEntity){ formEntity=formRepository.save(formEntity); return formEntity; } public FormEntity convertFormRequestToFormEntity(CallEntity callEntity, FormRequest formRequest) { FormEntity formEntity = new FormEntity(); formEntity.setCall(callEntity); formEntity.setLabel(formRequest.getLabel()); formEntity.setContent(setContentResponseBean(formRequest.getContent())); formEntity = saveFormEntity(formEntity); /** This code is responsible for adding a version history log for the "Create form" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(formEntity).build()); return formEntity; } public FormResponseBean convertFormEntityToFormResponseBean(FormEntity formEntity) { FormResponseBean formResponseBean=new FormResponseBean(); formResponseBean.setId(formEntity.getId()); formResponseBean.setContent(setContent(formEntity)); formResponseBean.setLabel(formEntity.getLabel()); formResponseBean.setCallId(formEntity.getCall().getId()); formResponseBean.setCallStatus(formEntity.getCall().getStatus()); return formResponseBean; } private List setContent(FormEntity formEntity) { List contentList = Utils.convertJsonStringToList(formEntity.getContent(), ContentResponseBean.class); contentList.forEach(data -> { List criteriaIds = criteriaFormFieldRepository .findByCallIdAndFormIdAndFormFieldIdAndIsDeletedFalse(formEntity.getCall().getId(), formEntity.getId(), data.getId()) .stream().map(CriteriaFormFieldEntity::getEvaluationCriteriaId).toList(); data.setCriteria(criteriaIds); }); return contentList; } public FormResponseBean createForm(CallEntity callEntity, FormRequest formRequest) { validateForm(formRequest); //cloned entity for old call data. CallEntity oldCallData = Utils.getClonedEntityForData(callEntity); if(callEntity.getStatus().equals(CallStatusEnum.PUBLISH.getValue())) { throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PUBLISHED_CALL_NOT_UPDATE)); } List flowDataEntities = flowDataRepository.findByCallId(callEntity.getId()); List flowEdgesEntities = flowEdgesRepository.findByCallId(callEntity.getId()); if (Boolean.FALSE.equals(flowDataEntities.isEmpty() || flowDataEntities == null) || Boolean.FALSE.equals(flowEdgesEntities.isEmpty() || flowEdgesEntities == null)) { /** This code is responsible for adding a version history log for "delete all flow data" operation. **/ flowDataEntities.stream().forEach(data -> loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(data).newData(null).build())); /** This code is responsible for adding a version history log for "delete all flow edges" operation. **/ flowEdgesEntities.stream().forEach(edge -> loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(edge).newData(null).build())); flowDataRepository.deleteAll(flowDataEntities); flowEdgesRepository.deleteAll(flowEdgesEntities); callEntity.setInitialForm(null); callEntity.setFinalForm(null); callRepository.save(callEntity); /** This code is responsible for adding a version history log for "update call" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCallData).newData(callEntity).build()); } FormEntity formEntity = convertFormRequestToFormEntity(callEntity, formRequest); validateAndSaveCriteriaFormField(callEntity, formEntity, formRequest.getContent()); return convertFormEntityToFormResponseBean(formEntity); } private void validateAndSaveCriteriaFormField(CallEntity callEntity, FormEntity formEntity, List contentResponseBeans) { contentResponseBeans.forEach(content -> { // Fetch existing records from the repository based on the call, form, and field ID List existingCriteriaFields = criteriaFormFieldRepository .findByCallIdAndFormIdAndFormFieldIdAndIsDeletedFalse(callEntity.getId(), formEntity.getId(), content.getId()); // Extract existing evaluation criteria IDs into a set for quick lookup Set existingEvaluationCriteriaIds = existingCriteriaFields.stream() .map(CriteriaFormFieldEntity::getEvaluationCriteriaId) .collect(Collectors.toSet()); // Get the criteria list (handling null as an empty list for uniformity) List criteriaList = Optional.ofNullable(content.getCriteria()).orElse(Collections.emptyList()); // Filter and create new entries for criteria that are not already present criteriaList.stream() .filter(criteriaId -> !existingEvaluationCriteriaIds.contains(criteriaId)) .forEach(criteriaId -> createCriteriaFormField(callEntity, formEntity, content.getId(), criteriaId)); // Prepare entities to be marked as deleted List toBeDeleted = existingCriteriaFields.stream() .filter(criteriaFormField -> !criteriaList.contains(criteriaFormField.getEvaluationCriteriaId())) .peek(data -> { // Clone the entity before modification CriteriaFormFieldEntity clonedData = Utils.getClonedEntityForData(data); data.setIsDeleted(Boolean.TRUE); /** This code is responsible for adding a version history log for the "soft deleting criteria from field" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder() .request(request) .actionType(VersionActionTypeEnum.SOFT_DELETE) .oldData(clonedData) .newData(data) .build() ); }) .collect(Collectors.toList()); if (!toBeDeleted.isEmpty()) { criteriaFormFieldRepository.saveAll(toBeDeleted); } }); } private void createCriteriaFormField(CallEntity callEntity, FormEntity formEntity, String formFieldId,Long evaluationCriteriaId) { EvaluationCriteriaEntity evaluationCriteria = evaluationCriteriaService.validateEvaluationCriteria(evaluationCriteriaId); if (Boolean.FALSE.equals(evaluationCriteria.getCall().getId().equals(callEntity.getId()))) { log.info("This evaluation criterion does not belong to the current call. Expected Call ID = {}, Found Call ID = {}", callEntity.getId(), evaluationCriteria.getCall().getId()); return; } CriteriaFormFieldEntity criteriaFormField = new CriteriaFormFieldEntity(); criteriaFormField.setCallId(callEntity.getId()); criteriaFormField.setFormId(formEntity.getId()); criteriaFormField.setFormFieldId(formFieldId); criteriaFormField.setIsDeleted(Boolean.FALSE); criteriaFormField.setEvaluationCriteriaId(evaluationCriteriaId); criteriaFormFieldRepository.save(criteriaFormField); /** This code is responsible for adding a version history log for the "creating criteria form field" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(criteriaFormField).build()); } public void validateForm(FormRequest formRequest){ if(formRequest.getContent()==null || formRequest.getLabel()==null ){ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.REQUIRED_PARAMETER_NOT_FOUND_FOR_FORM)); } } public FormResponseBean updateForm(UserEntity user, Long formId, FormRequest formRequest, Boolean forceDeleteFlow) { ContentRequestBean contentRequestBean2 = null; String choosenField = null; FormEntity formEntity = validateForm(formId); //cloned for old form data FormEntity oldFormData = Utils.getClonedEntityForData(formEntity); validator.validateUserWithCall(user, formEntity.getCall().getId()); // callDao.validateUpdate(formEntity.getCall()); List contentRequestBean = Utils.convertJsonStringToList(formEntity.getContent(), ContentRequestBean.class); for (ContentRequestBean contentRequestBean1 : contentRequestBean) { FlowDataEntity flowDataEntity = flowDataRepository.findByFormIdAndChoosenField(formEntity.getId(), contentRequestBean1.getId()); if (flowDataEntity != null) { choosenField = flowDataEntity.getChoosenField(); if (Boolean.TRUE.equals(contentRequestBean1.getId().equals(choosenField))) { contentRequestBean2 = contentRequestBean1; break; } } } if (contentRequestBean2 != null) { List settingRequestBeansDB = contentRequestBean2.getSettings(); for (ContentRequestBean contentRequestBeanRequest : formRequest.getContent()) { if (contentRequestBeanRequest.getId().equals(contentRequestBean2.getId())) { for (SettingRequestBean settingRequestBeanRequest : contentRequestBeanRequest.getSettings()) { for (SettingRequestBean settingRequestBeanDB : settingRequestBeansDB) { if (settingRequestBeanRequest.getName().equals(settingRequestBeanDB.getName())) { if (!settingRequestBeanRequest.getValue().equals(settingRequestBeanDB.getValue())) { if (Boolean.TRUE.equals(forceDeleteFlow)) { Utils.setIfUpdated(formEntity::getLabel, formEntity::setLabel, formRequest.getLabel()); Utils.setIfUpdated(formEntity::getContent, formEntity::setContent, setContentResponseBean(formRequest.getContent())); formEntity.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); formEntity = saveFormEntity(formEntity); /** This code is responsible for adding a version history log for the "update from" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldFormData).newData(formEntity) .build()); List flowDataEntities = flowDataRepository.findByCallId(formEntity.getCall().getId()); List flowEdgesEntities = flowEdgesRepository.findByCallId(formEntity.getCall().getId()); /** This code is responsible for adding a version history log for "delete all flow data" operation. **/ flowDataEntities.stream().forEach(data -> loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(data).newData(null).build())); /** This code is responsible for adding a version history log for "delete all flow edges" operation. **/ flowEdgesEntities.stream().forEach(edge -> loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(edge).newData(null).build())); flowDataRepository.deleteAll(flowDataEntities); flowEdgesRepository.deleteAll(flowEdgesEntities); CallEntity callEntity = formEntity.getCall(); //cloned for oldCall data CallEntity oldCallData = Utils.getClonedEntityForData(callEntity); callEntity.setInitialForm(null); callEntity.setFinalForm(null); callRepository.save(callEntity); /** This code is responsible for adding a version history log for the "update call" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCallData).newData(callEntity) .build()); return convertFormEntityToFormResponseBean(formEntity); } else { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.UPDATING_FORM_VALUE_IMPACT_ON_FLOW, choosenField)); } } else { Utils.setIfUpdated(formEntity::getLabel, formEntity::setLabel, formRequest.getLabel()); Utils.setIfUpdated(formEntity::getContent, formEntity::setContent, setContentResponseBean(formRequest.getContent())); formEntity.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); formEntity = saveFormEntity(formEntity); /** This code is responsible for adding a version history log for the "update from" operation. **/ loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldFormData).newData(formEntity) .build()); return convertFormEntityToFormResponseBean(formEntity); } } } } } } } else { Utils.setIfUpdated(formEntity::getLabel, formEntity::setLabel, formRequest.getLabel()); Utils.setIfUpdated(formEntity::getContent, formEntity::setContent, setContentResponseBean(formRequest.getContent())); formEntity.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); formEntity = saveFormEntity(formEntity); /** This code is responsible for adding a version history log for the "Update form data" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldFormData).newData(formEntity).build()); validateAndSaveCriteriaFormField(formEntity.getCall(), formEntity, formRequest.getContent()); return convertFormEntityToFormResponseBean(formEntity); } return convertFormEntityToFormResponseBean(formEntity); } public FormEntity validateForm(Long formId) { FormEntity formEntity = formRepository.findById(formId) .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.FORM_NOT_FOUND))); return formEntity; } public FormResponseBean getFormEntityById(UserEntity user, Long formId) { FormEntity formEntity = validateForm(formId); validator.validateUserWithCall(user, formEntity.getCall().getId()); return convertFormEntityToFormResponseBean(formEntity); } public void deleteFormById(UserEntity user, Long formId){ FormEntity formEntity = validateForm(formId); validator.validateUserWithCall(user, formEntity.getCall().getId()); List flowDataEntities=flowDataRepository.findByCallId(formEntity.getCall().getId()); List flowEdgesEntities=flowEdgesRepository.findByCallId(formEntity.getCall().getId()); /** This code is responsible for adding a version history log for "delete all flow data" operation. **/ flowDataEntities.stream().forEach(data -> loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(data).newData(null).build())); /** This code is responsible for adding a version history log for "delete all flow edges" operation. **/ flowEdgesEntities.stream().forEach(edge -> loggingUtil.addVersionHistory( VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.DELETE).oldData(edge).newData(null).build())); flowDataRepository.deleteAll(flowDataEntities); flowEdgesRepository.deleteAll(flowEdgesEntities); CallEntity callEntity=formEntity.getCall(); //cloned for getting old call data CallEntity oldCallData = Utils.getClonedEntityForData(callEntity); callEntity.setFinalForm(null); callEntity.setInitialForm(null); callRepository.save(callEntity); /** This code is responsible for adding a version history log for the "Create Call" operation. **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.INSERT).oldData(null).newData(callEntity).build()); formRepository.delete(formEntity); } public List getFormsByCallId(CallEntity callEntity){ if(callEntity== null){ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.CALL_NOT_FOUND)); } List formEntities=formRepository.findByCallId(callEntity.getId()); List formResponseBeanList = formEntities.stream() .map(req -> convertFormEntityToFormResponseBean(req)) .collect(Collectors.toList()); return formResponseBeanList; } public String setContentResponseBean(List contentRequestBeans){ String stringContentRequest = Utils.convertListToJsonString(contentRequestBeans); List cloneContentRequestBeans = Utils.convertJsonStringToList(stringContentRequest, ContentRequestBean.class); cloneContentRequestBeans.forEach(data->data.setCriteria(null)); return Utils.convertListToJsonString(cloneContentRequestBeans); } public void validateFormField(List applicationFormFieldRequestList, ApplicationEntity applicationEntity, FormEntity formEntity) { Map formFieldMap = new LinkedHashMap(); for(ApplicationFormFieldRequestBean applicationFormFieldRequestBean:applicationFormFieldRequestList) { if(applicationFormFieldRequestBean.getFieldValue()==null ) continue; if (applicationFormFieldRequestBean.getFieldValue() != null ) { Object fieldValue = applicationFormFieldRequestBean.getFieldValue(); checkObjectData(applicationFormFieldRequestBean.getFieldId(), fieldValue, formFieldMap); }} FormResponseBean formResponseBean = convertFormEntityToFormResponseBean(formEntity); ApplicationFormEntity applicationFormEntity=applicationFormRepository.findByApplicationIdAndFormId(applicationEntity.getId(),formEntity.getId()); Boolean isApplicationFormExist= getApplicationFormExist(applicationFormEntity); FieldValidator validator = FieldValidator.create(); formResponseBean.getContent().forEach(contentResponseBean -> { String fieldId = contentResponseBean.getId(); String fieldLabel=contentResponseBean.getLabel(); Object object=formFieldMap.get(fieldId); String value =Utils.convertToStringForFormFieldValue(object); if(value == null && isApplicationFormExist) { return; } FieldValidatorBean fieldValidatorBean = Utils.convertSourceObjectToDestinationObject(contentResponseBean.getValidators(), FieldValidatorBean.class); validator .minLength(value, fieldValidatorBean.getMinLength(), fieldLabel,fieldValidatorBean.getMin(),contentResponseBean) // Only applies if minLength is not null .maxLength(value, fieldValidatorBean.getMaxLength(), fieldLabel,fieldValidatorBean.getMax(),contentResponseBean) // Only applies if maxLength is not null .matchesPattern(value, fieldValidatorBean.getPattern(), fieldLabel) // Only applies if pattern is present .validateCustom(value, fieldValidatorBean.getCustom(), fieldLabel,contentResponseBean); // Add the custom validation here // applicationDao.calculationProcessForFormula(applicationFormEntity,formResponseBean.getContent(),fieldId,value,validator); if (fieldValidatorBean.getCustom() != null && fieldValidatorBean.getCustom().equals(GepafinConstant.IS_PIVA)) { Long hubId = applicationEntity.getHubId(); String error = validateVatNumber(value, fieldLabel,hubId); if(error != null) { validator.addError(error); } } }); validator.validate(); } public void checkObjectData(String fieldId, Object fieldValue, Map formFieldMap) { if (fieldValue instanceof List) { List list = (List) fieldValue; // Only map if the list is not empty and contains Strings if (list.stream().allMatch(item -> item instanceof String)) { formFieldMap.put(fieldId, list); } else if (!list.isEmpty() && list.get(0) instanceof String) { for (Object value : list) { setFormFieldMap(fieldId, formFieldMap, value); } } else if (list.stream().allMatch(item -> item instanceof Map map && map.keySet().stream().allMatch(String.class::isInstance))) { if (fieldValue != null) { formFieldMap.put(fieldId, fieldValue); } } else setFormFieldMap(fieldId, formFieldMap, fieldValue); } else setFormFieldMap(fieldId, formFieldMap, fieldValue); } public void setFormFieldMap(String fieldId, Map formFieldMap, Object value) { if(value !=null){ String fieldValue= String.valueOf(value); if(Boolean.FALSE.equals(StringUtils.isEmpty(fieldValue))) { formFieldMap.put(fieldId, value); } } } private Boolean getApplicationFormExist(ApplicationFormEntity applicationFormEntity) { if(applicationFormEntity !=null) { return true; } return false; } public Boolean validateCompletedSteps(List applicationFormFieldEntityList, ApplicationEntity applicationEntity, FormEntity formEntity, Boolean isSendValidationError) { Map formFieldMap = new LinkedHashMap(); for(ApplicationFormFieldEntity applicationFormFieldEntity:applicationFormFieldEntityList) { formFieldMap.put(applicationFormFieldEntity.getFieldId(),applicationFormFieldEntity.getFieldValue()); } FormResponseBean formResponseBean = convertFormEntityToFormResponseBean(formEntity); FieldValidator validator = FieldValidator.create(); formResponseBean.getContent().forEach(contentResponseBean -> { String fieldId = contentResponseBean.getId(); String value = (String) formFieldMap.get(fieldId); FieldValidatorBean fieldValidatorBean = Utils.convertSourceObjectToDestinationObject(contentResponseBean.getValidators(), FieldValidatorBean.class); String fieldValue = getFieldValue(contentResponseBean); validator.isRequired(value, fieldValidatorBean.getIsRequired(), fieldValue) .validateCustomTableValidation(value,fieldValidatorBean.getCustom(),fieldValue,contentResponseBean); }); if (Boolean.TRUE.equals(isSendValidationError)) { validator.validate(); } return !validator.hasErrors(); } private String getFieldValue(ContentResponseBean contentResponseBean) { // Use Optional with pattern matching for type checks return contentResponseBean.getSettings().stream().filter(setting -> "label".equals(setting.getName()) && setting.getValue() != null) .map(setting -> { if (setting.getValue() instanceof String value) { return value.trim(); } else { return String.valueOf(setting.getValue()).trim(); } }).filter(value -> !value.isEmpty()).findFirst().orElse(contentResponseBean.getId()); } public String validateVatNumber(String value,String fieldId, Long hubId){ String error=null; if (value!=null && value.matches("^\\d{1,11}$")) { // Map customData=null; try { // Map vatCheckResponse = vatCheckDao.checkVatNumberApi(value); vatCheckDao.checkVatNumber(value, hubId); // if (Boolean.FALSE.equals(CollectionUtils.isEmpty(vatCheckResponse))) { // customData = vatCheckResponse; // } } catch (Exception e) { error=(MessageFormat.format(Translator.toLocale(GepafinConstant.VALIDATION_VALID_PIVA), fieldId)); } } return error; } }