Done ticket GEPAFINBE-162
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -245,6 +245,12 @@
|
||||
<artifactId>reactor-netty</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.objecthunter</groupId>
|
||||
<artifactId>exp4j</artifactId>
|
||||
<version>0.4.8</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
|
||||
@@ -407,5 +407,6 @@ public class GepafinConstant {
|
||||
public static final String ASSIGNED_APPLICATION_STATUS_UPDATED_SUCCESSFULLY = "assigned.application.status.updated.successfully";
|
||||
|
||||
public static final String REQUIRED_REQUESTED_AMOUNT_MSG = "validation.required.requested.amount";
|
||||
public static final String FORMULA_AMOUNT_NOT_MATCHED="formula.amount.not.matches.requested.amount";
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundExceptio
|
||||
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
|
||||
|
||||
import org.h2.util.IOUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -49,11 +50,16 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
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.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@@ -183,6 +189,7 @@ public class ApplicationDao {
|
||||
@Autowired
|
||||
private ApplicationEvaluationRepository applicationEvaluationRepository;
|
||||
|
||||
|
||||
public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean, Long formId, Long applicationId) {
|
||||
FormEntity formEntity = formService.validateForm(formId);
|
||||
// callService.validatePublishedCall(formEntity.getCall().getId());
|
||||
@@ -482,15 +489,18 @@ public class ApplicationDao {
|
||||
|
||||
public List<ApplicationFormFieldEntity> createOrUpdateMultipleFormFields(List<ApplicationFormFieldRequestBean> formFieldResponseBeans,
|
||||
ApplicationFormEntity applicationFormEntity, FormEntity formEntity) {
|
||||
FieldValidator fieldValidator = FieldValidator.create();
|
||||
|
||||
List<ApplicationFormFieldEntity> existingFields = applicationFormFieldRepository.findByApplicationFormId(applicationFormEntity.getId());
|
||||
|
||||
return formFieldResponseBeans.stream().map(requestBean -> createOrUpdateApplicationFormField(requestBean, applicationFormEntity, existingFields, formEntity))
|
||||
List<ApplicationFormFieldEntity> applicationFormFieldEntities=formFieldResponseBeans.stream().map(requestBean -> createOrUpdateApplicationFormField(requestBean, applicationFormEntity, existingFields, formEntity,fieldValidator))
|
||||
.collect(Collectors.toList());
|
||||
fieldValidator.validate();
|
||||
return applicationFormFieldEntities;
|
||||
}
|
||||
|
||||
public ApplicationFormFieldEntity createOrUpdateApplicationFormField(ApplicationFormFieldRequestBean applicationFormFieldRequestBean,
|
||||
ApplicationFormEntity applicationFormEntity, List<ApplicationFormFieldEntity> applicationFormFieldEntities, FormEntity formEntity) {
|
||||
ApplicationFormEntity applicationFormEntity, List<ApplicationFormFieldEntity> applicationFormFieldEntities, FormEntity formEntity,FieldValidator fieldValidator) {
|
||||
|
||||
ApplicationFormFieldEntity applicationFormFieldEntity = new ApplicationFormFieldEntity();
|
||||
|
||||
@@ -538,6 +548,7 @@ public class ApplicationDao {
|
||||
}
|
||||
}
|
||||
}
|
||||
calculationProcessForFormula(applicationFormEntity,contentResponseBeans,applicationFormFieldRequestBean,fieldValidator);
|
||||
Utils.setIfUpdated(applicationFormFieldEntity::getFieldId, applicationFormFieldEntity::setFieldId, applicationFormFieldRequestBean.getFieldId());
|
||||
|
||||
if (applicationFormFieldRequestBean.getFieldValue() != null) {
|
||||
@@ -560,7 +571,6 @@ public class ApplicationDao {
|
||||
VersionHistoryRequest.builder().request(request).actionType(actionType).oldData(oldApplicationFormFieldData).newData(applicationFormField).build());
|
||||
|
||||
log.info("Version history logged for action: {}, Field ID: {}", actionType, applicationFormFieldEntity.getFieldId());
|
||||
|
||||
return applicationFormField;
|
||||
}
|
||||
|
||||
@@ -1539,5 +1549,135 @@ public class ApplicationDao {
|
||||
}
|
||||
}
|
||||
|
||||
public void calculationProcessForFormula(ApplicationFormEntity applicationFormEntity, List<ContentResponseBean> contentResponseBeans, ApplicationFormFieldRequestBean applicationFormFieldRequestBean,FieldValidator fieldValidator) {
|
||||
List<String> formulaValue = new ArrayList<>();
|
||||
String formulaValueOpt=null;
|
||||
String label=null;
|
||||
for (ContentResponseBean contentResponseBean:contentResponseBeans){
|
||||
if(contentResponseBean.getId().equals(applicationFormFieldRequestBean.getFieldId())){
|
||||
for (SettingResponseBean settingResponseBean:contentResponseBean.getSettings()){
|
||||
if (settingResponseBean.getName().equals("label")){
|
||||
label= String.valueOf(settingResponseBean.getValue());
|
||||
}
|
||||
if(settingResponseBean.getName().equals("formula")){
|
||||
String value= (String) settingResponseBean.getValue();
|
||||
formulaValueOpt=value;
|
||||
formulaValue=Utils.extractValues(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, String> mappedFormulaValue = new HashMap<>();
|
||||
Object fieldValue = applicationFormFieldRequestBean.getFieldValue();
|
||||
if (formulaValueOpt != null && fieldValue==null) {
|
||||
fieldValue=0;
|
||||
}
|
||||
|
||||
for (ContentResponseBean contentResponseBean : contentResponseBeans) {
|
||||
String contentId = contentResponseBean.getId();
|
||||
|
||||
// Extract variable values once per contentResponseBean to avoid repeated stream operations
|
||||
Set<String> variableValues = contentResponseBean.getSettings().stream()
|
||||
.filter(setting -> "variable".equals(setting.getName()))
|
||||
.flatMap(setting -> {
|
||||
Object value = setting.getValue(); // Get the raw value
|
||||
if (value instanceof String) {
|
||||
return Stream.of((String) value); // Handle single String case
|
||||
} else if (value instanceof List) {
|
||||
return ((List<?>) value).stream()
|
||||
.filter(item -> item instanceof String) // Ensure it's a String
|
||||
.map(item -> (String) item); // Convert to String
|
||||
} else {
|
||||
return Stream.empty(); // Ignore unexpected types
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toSet()); // Collect into a Set for uniqueness
|
||||
|
||||
for (String formula : formulaValue) {
|
||||
if (variableValues.contains(formula)) { // O(1) lookup instead of O(n)
|
||||
mappedFormulaValue.put(formula, contentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, String> updatedMappedFormulaValue = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, String> entry : mappedFormulaValue.entrySet()) {
|
||||
String variable = entry.getKey();
|
||||
String contentId = entry.getValue();
|
||||
|
||||
// Repository call using contentId
|
||||
Optional<ApplicationFormFieldEntity> optionalEntity = applicationFormFieldRepository.findByApplicationFormIdAndFieldId(applicationFormEntity.getId(),contentId);
|
||||
// If entity is found, extract fieldValue and fieldId
|
||||
optionalEntity.ifPresent(entity -> {
|
||||
String entityFieldValue = entity.getFieldValue(); // Assuming getter method exists
|
||||
String fieldId = entity.getFieldId(); // Assuming getter method exists
|
||||
String tableType = contentResponseBeans.stream()
|
||||
.filter(content -> content.getId().equals(fieldId)) // Match Content ID with fieldId
|
||||
.flatMap(content -> content.getSettings().stream()) // Extract settings
|
||||
.filter(setting -> "criteria_table_columns".equals(setting.getName())) // Match name
|
||||
.map(setting -> setting.getName()) // Return the name of the setting
|
||||
.findFirst() // Get the first match
|
||||
.orElse(null); // Default to null if no match
|
||||
|
||||
if(tableType!=null){
|
||||
JSONObject jsonObject = new JSONObject(entityFieldValue);
|
||||
|
||||
// Extract the value of total
|
||||
entityFieldValue = jsonObject.getString("total");
|
||||
|
||||
}
|
||||
|
||||
updatedMappedFormulaValue.put(fieldId, entityFieldValue);
|
||||
});
|
||||
}
|
||||
if(formulaValueOpt==null || formulaValueOpt.isEmpty()){
|
||||
return;
|
||||
}
|
||||
double finalValue = evaluateFormula(formulaValueOpt, mappedFormulaValue, updatedMappedFormulaValue);
|
||||
|
||||
fieldValidator.formulaValidation(fieldValue, finalValue, label);
|
||||
}
|
||||
|
||||
|
||||
public static double evaluateFormula(String formula, Map<String, String> mappedFormulaValue, Map<String, String> updatedMappedFormulaValue) {
|
||||
// Step 1: Extract all placeholders (variables) like {rest}, {another_var}, etc.
|
||||
Pattern pattern = Pattern.compile("\\{(.*?)\\}");
|
||||
Matcher matcher = pattern.matcher(formula);
|
||||
List<String> variables = new ArrayList<>();
|
||||
|
||||
while (matcher.find()) {
|
||||
variables.add(matcher.group(1)); // Extract variable names inside the curly braces
|
||||
}
|
||||
|
||||
// Step 2: Replace placeholders with corresponding fieldValue
|
||||
Map<String, Double> variableValues = new HashMap<>();
|
||||
|
||||
for (String variable : variables) {
|
||||
String fieldId = mappedFormulaValue.get(variable);
|
||||
if (fieldId != null && updatedMappedFormulaValue.containsKey(fieldId)) {
|
||||
String fieldValueStr = updatedMappedFormulaValue.get(fieldId);
|
||||
try {
|
||||
double fieldValue = Double.parseDouble(fieldValueStr); // Assuming fieldValue is numeric
|
||||
variableValues.put(variable, fieldValue);
|
||||
} catch (NumberFormatException e) {
|
||||
// Handle invalid number format gracefully (e.g., log an error or default to 0)
|
||||
variableValues.put(variable, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Replace variables in the formula with their corresponding values
|
||||
String expression = formula;
|
||||
for (String variable : variables) {
|
||||
Double value = variableValues.get(variable);
|
||||
if (value != null) {
|
||||
// Replace {variable} with its corresponding value in the formula
|
||||
expression = expression.replace("{" + variable + "}", String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Evaluate the mathematical expression
|
||||
return Utils.evaluateExpression(expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ package net.gepafin.tendermanagement.util;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -9,12 +13,18 @@ import net.gepafin.tendermanagement.config.Translator;
|
||||
import net.gepafin.tendermanagement.constants.GepafinConstant;
|
||||
import net.gepafin.tendermanagement.dao.FormDao;
|
||||
import net.gepafin.tendermanagement.dao.VatCheckDao;
|
||||
import net.gepafin.tendermanagement.entities.ApplicationFormEntity;
|
||||
import net.gepafin.tendermanagement.entities.ApplicationFormFieldEntity;
|
||||
import net.gepafin.tendermanagement.model.request.ApplicationFormFieldRequestBean;
|
||||
import net.gepafin.tendermanagement.model.request.ContentRequestBean;
|
||||
import net.gepafin.tendermanagement.model.response.ContentResponseBean;
|
||||
import net.gepafin.tendermanagement.model.response.SettingResponseBean;
|
||||
import net.gepafin.tendermanagement.repositories.ApplicationFormFieldRepository;
|
||||
import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
|
||||
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
|
||||
import net.gepafin.tendermanagement.web.rest.api.errors.ValidationException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -232,5 +242,17 @@ public class FieldValidator {
|
||||
// Now contentRequestBean is populated with the data from the JSON
|
||||
return contentRequestBean;
|
||||
}
|
||||
|
||||
public FieldValidator formulaValidation(Object fieldValue, double finalValue, String label) {
|
||||
if (fieldValue != null) {
|
||||
try {
|
||||
double fieldValueAsDouble = Double.parseDouble(fieldValue.toString()); // Convert fieldValue to double
|
||||
if (Double.compare(finalValue, fieldValueAsDouble) != 0) { // Compare doubles safely
|
||||
errors.add(MessageFormat.format(Translator.toLocale(GepafinConstant.FORMULA_AMOUNT_NOT_MATCHED), label));
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, "Invalid field value: " + fieldValue);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -27,6 +28,8 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import net.gepafin.tendermanagement.config.Translator;
|
||||
import net.gepafin.tendermanagement.constants.GepafinConstant;
|
||||
import net.gepafin.tendermanagement.model.request.GlobalFilters;
|
||||
import net.objecthunter.exp4j.Expression;
|
||||
import net.objecthunter.exp4j.ExpressionBuilder;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -54,6 +57,9 @@ import javax.crypto.Cipher;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||
|
||||
@@ -753,6 +759,23 @@ public class Utils {
|
||||
private static Map<String, Object> defaultErrorResponse() {
|
||||
return Collections.singletonMap("message", Translator.toLocale(GepafinConstant.INVALID_VATNUMBER));
|
||||
}
|
||||
public static List<String> extractValues(String input) {
|
||||
List<String> extractedValues = new ArrayList<>();
|
||||
Pattern pattern = Pattern.compile("\\{(.*?)\\}"); // Regex to match {value}
|
||||
Matcher matcher = pattern.matcher(input);
|
||||
|
||||
|
||||
while (matcher.find()) {
|
||||
extractedValues.add(matcher.group(1)); // Extract value inside {}
|
||||
}
|
||||
return extractedValues;
|
||||
}
|
||||
public static double evaluateExpression(String expression) {
|
||||
try {
|
||||
Expression exp = new ExpressionBuilder(expression).build();
|
||||
return exp.evaluate();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Double.NaN; // Return NaN if the expression is invalid
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -367,5 +367,6 @@ either.applicationId.or.assignedApplicationId.must.be.provided=Either applicatio
|
||||
assigned.application.status.updated.successfully=Assigned application status updated successfully.
|
||||
|
||||
validation.required.requested.amount=The Requested Amount configuration should be mandatory.
|
||||
formula.amount.not.matches.requested.amount= The {0} does not matches to calculated amount.
|
||||
|
||||
|
||||
|
||||
@@ -358,6 +358,5 @@ either.applicationId.or.assignedApplicationId.must.be.provided = "<22> necessario
|
||||
assigned.application.status.updated.successfully=Stato dell'applicazione assegnata aggiornato con successo.
|
||||
|
||||
validation.required.requested.amount=La configurazione dell'importo richiesto <20> obbligatoria.
|
||||
|
||||
|
||||
formula.amount.not.matches.requested.amount=Il {0} non corrisponde all'importo calcolato.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user