diff --git a/clearing-parent/clearing-utils/pom.xml b/clearing-parent/clearing-utils/pom.xml
index e0e9bbd67..59e076a6b 100644
--- a/clearing-parent/clearing-utils/pom.xml
+++ b/clearing-parent/clearing-utils/pom.xml
@@ -86,6 +86,10 @@
assertj-core
test
+
+ ru.spcex.platform
+ platform-messaging
+
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/context/IValidatorContext.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/context/IValidatorContext.java
new file mode 100644
index 000000000..d1003c026
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/context/IValidatorContext.java
@@ -0,0 +1,7 @@
+package ru.spcex.clearing.validation.common.context;
+
+public interface IValidatorContext {
+ default S getStoredObject(Enum> storedObject) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/context/ImdgValidationContext.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/context/ImdgValidationContext.java
new file mode 100644
index 000000000..6e205e4eb
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/context/ImdgValidationContext.java
@@ -0,0 +1,54 @@
+package ru.spcex.clearing.validation.common.context;
+
+import ru.spcex.platform.classes.base.SpcexObjectBase;
+import ru.spcex.platform.imdg.api.Imdg;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class ImdgValidationContext implements IValidatorContext {
+ private final Map> imdgs;
+ private final Map, Object> storedObjects;
+ private T validatedObject;
+
+ public ImdgValidationContext() {
+ this.imdgs = new HashMap<>();
+ this.storedObjects = new HashMap<>();
+ }
+
+ public void addImdg(String key, Imdg> imdg) {
+ imdgs.put(key, imdg);
+ }
+
+ public void setValidatedObject(T validatedObject) {
+ this.validatedObject = validatedObject;
+ }
+
+ public T getValidatedObject() {
+ return validatedObject;
+ }
+
+ /**
+ * !!!не использовать один Enum в разных местах
+ */
+ public void storeObject(Enum> storedObject, Object anyObject) {
+ storedObjects.put(storedObject, anyObject);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public S getStoredObject(Enum> storedObject) {
+ Object o = storedObjects.get(storedObject);
+ return (S) o;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Imdg obtainMap(String mapName, Class clazz) {
+ Imdg> imdg = imdgs.get(mapName);
+ if (imdg == null) {
+ throw new IllegalStateException(mapName + " imdg wasn't added to validation context");
+ }
+ return (Imdg) imdg;
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java
new file mode 100644
index 000000000..154275358
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java
@@ -0,0 +1,61 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IEnumId;
+
+import java.time.LocalDate;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка поля с LocalDate. Условие проверки: поверяемая дата >= текущая дата
+ * @param Класс проверяемого объекта
+ */
+public record DateNotBeforeRule(
+ String fieldName,
+ Function getter,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorTaskForPastDate,
+ boolean required
+) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемой даты
+ * @param required Флаг обязательности поля
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorTaskForPastDate Ошибка, которая будет возвращена, если проверяемая дата меньше текущей
+ * @param Класс проверяемого объекта
+ */
+ public static DateNotBeforeRule instance(String fieldName,
+ Function getter,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorTaskForPastDate,
+ boolean required) {
+ return new DateNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastDate, required);
+ }
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемой даты
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorTaskForPastDate Ошибка, которая будет возвращена, если проверяемая дата меньше текущей
+ * @param Класс проверяемого объекта
+ */
+ public static DateNotBeforeRule instance(String fieldName,
+ Function getter,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorTaskForPastDate) {
+ return new DateNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastDate, true);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ LocalDate date = getter.apply(validatedObject);
+ if (date == null) return required ? of(errorEmptyRequiredValue, fieldName) : Optional.empty();
+ if (date.isBefore(LocalDate.now())) return of(errorTaskForPastDate, fieldName);
+ return Optional.empty();
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java
new file mode 100644
index 000000000..11d2bc0c0
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java
@@ -0,0 +1,102 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.clearing.platform.dictionary.AbstractDictionary;
+import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
+import ru.spcex.platform.imdg.api.Imdg;
+import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
+import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IEnumId;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка поля с кодом из словаря (таблицы *_dictionary)
+ * @param Класс проверяемого объекта
+ * @param Класс словаря
+ */
+public record DictionaryPresentRule(String fieldName,
+ Function getter,
+ String dictionaryName,
+ Class dictionaryClass,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorWrongDictionaryValue,
+ boolean required) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля
+ * @param getter Метод получения проверяемого значения
+ * @param dictionaryName Название словаря (см. IMDGDistributedNames)
+ * @param dictionaryClass Класс словаря (классы *Dictionary.class)
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorWrongDictionaryValue Ошибка, которая будет возвращена, если поле не найдено в словаре
+ * @param required Флаг обязательности
+ * @param Класс проверяемого объекта
+ * @param Класс словаря
+ */
+ public static DictionaryPresentRule instance(String fieldName,
+ Function getter,
+ String dictionaryName,
+ Class dictionaryClass,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorWrongDictionaryValue,
+ boolean required) {
+ return new DictionaryPresentRule<>(fieldName,
+ getter,
+ dictionaryName,
+ dictionaryClass,
+ errorWrongDictionaryValue,
+ errorEmptyRequiredValue,
+ required);
+ }
+
+ /**
+ * @param fieldName Название поля
+ * @param getter Метод получения проверяемого значения
+ * @param dictionaryName Название словаря (см. IMDGDistributedNames)
+ * @param dictionaryClass Класс словаря (классы *Dictionary.class)
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorWrongDictionaryValue Ошибка, которая будет возвращена, если поле не найдено в словаре
+ * @param Класс проверяемого объекта
+ * @param Класс словаря
+ */
+ public static DictionaryPresentRule instance(String fieldName,
+ Function getter,
+ String dictionaryName,
+ Class dictionaryClass,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorWrongDictionaryValue) {
+ return new DictionaryPresentRule<>(fieldName,
+ getter,
+ dictionaryName,
+ dictionaryClass,
+ errorEmptyRequiredValue,
+ errorWrongDictionaryValue,
+ true);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ String enumCode = getter.apply(validatedObject);
+ if (enumCode == null) return required ? of(errorEmptyRequiredValue, fieldName) : empty();
+ Imdg dictImdg = context.obtainMap(
+ dictionaryName,
+ dictionaryClass
+ );
+ ImdgPredicateBuilder imdgPredicateBuilder = dictImdg.predicateBuilder();
+ ImdgPredicate imdgPredicate = imdgPredicateBuilder.equals("code", enumCode);
+ Collection fromMap = dictImdg.getCollectionObjectsByPredicate(imdgPredicate);
+ if (fromMap.isEmpty()) {
+ return of(errorWrongDictionaryValue, fieldName);
+ }
+ assert fromMap.size() == 1;
+ D dictionaryFromMap = fromMap.iterator().next();
+ if (dictionaryFromMap == null) {
+ return of(errorWrongDictionaryValue, fieldName);
+ }
+ return empty();
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/EnumPresentRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java
similarity index 84%
rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/EnumPresentRule.java
rename to clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java
index ae05b8f70..f32366483 100644
--- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/EnumPresentRule.java
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java
@@ -1,10 +1,9 @@
-package ru.spcex.clearing.validation.common;
+package ru.spcex.clearing.validation.common.rules;
-import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import ru.spcex.platform.utils.enumeration.IEnumKey;
-import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Optional;
import java.util.function.Function;
@@ -25,6 +24,8 @@ public record EnumPresentRule(String fieldName,
* @param fieldName Название поля
* @param getter Метод получения проверяемого значения
* @param enumValues Значения из проверяемого множества (Enum.values())
+ * @param errorWrongEnumValue Ошибка, которая будет возвращена, если поле не найдено в Enum
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param required Флаг обязательности
* @param Класс проверяемого объекта
* @param Enum
@@ -44,6 +45,8 @@ public record EnumPresentRule(String fieldName,
* @param fieldName Название поля
* @param getter Метод получения проверяемого значения
* @param enumValues Значения из проверяемого множества (Enum.values())
+ * @param errorWrongEnumValue Ошибка, которая будет возвращена, если поле не найдено в Enum
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param Класс проверяемого объекта
* @param Enum
*/
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/FieldRequiredRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java
similarity index 69%
rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/FieldRequiredRule.java
rename to clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java
index 358df8caa..61cfd4913 100644
--- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/FieldRequiredRule.java
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java
@@ -1,24 +1,29 @@
-package ru.spcex.clearing.validation.common;
+package ru.spcex.clearing.validation.common.rules;
-import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
-import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Optional;
import java.util.function.Function;
/**
* Проверка обязательности поля (not null)
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param Класс проверяемого объекта
* @param Класс проверяемого значения
*/
-public record FieldRequiredRule(String fieldName, Function getter, IEnumId errorEmptyRequiredValue) implements IValidationRule> {
+public record FieldRequiredRule(
+ String fieldName,
+ Function getter,
+ IEnumId errorEmptyRequiredValue
+) implements IValidationRule> {
/**
* @param fieldName Название поля
* @param getter Метод получения значения
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
* @param Класс проверяемого объекта
* @param Класс проверяемого значения
*/
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IValidationRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IValidationRule.java
new file mode 100644
index 000000000..93720b21b
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IValidationRule.java
@@ -0,0 +1,44 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.clearing.validation.common.context.IValidatorContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IEnumId;
+
+import java.util.Optional;
+
+/**
+ * Правило валидации, описывающее какую ошибку возвращать и при каких условиях
+ * Все необходимые данные берет из контекста
+ * @param контекст
+ */
+public interface IValidationRule {
+ Optional validate(C context);
+
+ /**
+ * для логов
+ */
+ default String ruleName() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * если у валидатора был вызван метод проверить все, этот метод может использоваться для более тонкой настройки
+ * по дефолту - выполнять проверку даже если предыдущие выполнены с ошибками
+ */
+ default boolean runIfErrorsPresent() {
+ return true;
+ }
+
+ //*************** методы для сокращения кода ***************
+ default Optional of(IEnumId error) {
+ return Optional.of(new EnumMessage(error));
+ }
+
+ default Optional of(IEnumId error, Object... args) {
+ return Optional.of(new EnumMessage(error, args));
+ }
+
+ default Optional empty() {
+ return Optional.empty();
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java
new file mode 100644
index 000000000..c5d118461
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java
@@ -0,0 +1,105 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
+import ru.spcex.platform.classes.base.SpcexObjectBase;
+import ru.spcex.platform.imdg.api.Imdg;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IEnumId;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка наличия связанного по Id объекта в базе
+ * @param Класс проверяемого объекта
+ * @param Класс связанного объекта
+ */
+public record IdPresentRule(
+ String fieldName,
+ Function idGetter,
+ String mapName,
+ Class mapClass,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorIdNotPresent,
+ boolean required,
+ Function[] additionalChecks
+) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля, содержащего Id
+ * @param idGetter Метод получения Id
+ * @param mapName Название мапы связанного объекта (см. IMDGDistributedNames)
+ * @param mapClass Класс связанного объекта
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorIdNotPresent Ошибка, которая будет возвращена, если Id не найден
+ * @param required Флаг обязательности
+ * @param additionalChecks Дополнительные проверки, которые можно провести со связанным объектом
+ * @param Класс проверяемого объекта
+ * @param Класс связанного объекта
+ */
+ @SafeVarargs
+ public static IdPresentRule instance(String fieldName,
+ Function idGetter,
+ String mapName,
+ Class mapClass,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorIdNotPresent,
+ boolean required,
+ Function ... additionalChecks) {
+ return new IdPresentRule<>(fieldName,
+ idGetter,
+ mapName,
+ mapClass,
+ errorEmptyRequiredValue,
+ errorIdNotPresent,
+ required,
+ additionalChecks);
+ }
+
+ /**
+ * @param fieldName Название поля, содержащего Id
+ * @param idGetter Метод получения Id
+ * @param mapName Название мапы связанного объекта (см. IMDGDistributedNames)
+ * @param mapClass Класс связанного объекта
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorIdNotPresent Ошибка, которая будет возвращена, если Id не найден
+ * @param additionalChecks Дополнительные проверки, которые можно провести со связанным объектом
+ * @param Класс проверяемого объекта
+ * @param Класс связанного объекта
+ */
+ @SafeVarargs
+ public static IdPresentRule instance(String fieldName,
+ Function idGetter,
+ String mapName,
+ Class mapClass,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorIdNotPresent,
+ Function ... additionalChecks) {
+ return new IdPresentRule<>(fieldName,
+ idGetter,
+ mapName,
+ mapClass,
+ errorEmptyRequiredValue,
+ errorIdNotPresent,
+ true,
+ additionalChecks);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ Long id = idGetter.apply(validatedObject);
+ if (id == null) return required ? of(errorEmptyRequiredValue, fieldName) : empty();
+ Imdg imdg = context.obtainMap(mapName, mapClass);
+ V fromMap = imdg.getSingleObjectByID(id);
+ if (fromMap == null) {
+ return of(errorIdNotPresent, fieldName);
+ }
+ for (Function additionalCheck : additionalChecks) {
+ IEnumId validationError = additionalCheck.apply(fromMap);
+ if (validationError != null)
+ return of(validationError, fieldName);
+ }
+ return empty();
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java
new file mode 100644
index 000000000..2e76dda1b
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java
@@ -0,0 +1,61 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IEnumId;
+
+import java.time.LocalTime;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка поля с LocalTime. Условие проверки: проверяемое время >= текущее время
+ * @param Класс проверяемого объекта
+ */
+public record TimeNotBeforeRule(
+ String fieldName,
+ Function getter,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorTaskForPastTime,
+ boolean required
+) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемого времени
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorTaskForPastTime Ошибка, которая будет возвращена, если проверяемое время меньше текущего
+ * @param required Флаг обязательности поля
+ * @param Класс проверяемого объекта
+ */
+ public static TimeNotBeforeRule instance(String fieldName,
+ Function getter,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorTaskForPastTime,
+ boolean required) {
+ return new TimeNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastTime, required);
+ }
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемого времени
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorTaskForPastTime Ошибка, которая будет возвращена, если проверяемое время меньше текущего
+ * @param Класс проверяемого объекта
+ */
+ public static TimeNotBeforeRule instance(String fieldName,
+ Function getter,
+ IEnumId errorEmptyRequiredValue,
+ IEnumId errorTaskForPastTime) {
+ return new TimeNotBeforeRule<>(fieldName, getter, errorEmptyRequiredValue, errorTaskForPastTime, true);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ LocalTime date = getter.apply(validatedObject);
+ if (date == null) return required ? of(errorEmptyRequiredValue, fieldName) : Optional.empty();
+ if (date.isBefore(LocalTime.now())) return of(errorTaskForPastTime, fieldName);
+ return Optional.empty();
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/IValidator.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/IValidator.java
new file mode 100644
index 000000000..c5a9b7322
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/IValidator.java
@@ -0,0 +1,46 @@
+package ru.spcex.clearing.validation.common.validator;
+
+
+import ru.spcex.clearing.validation.common.rules.IValidationRule;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Валидатор, в который можно добавлять правила проверок.
+ * Будет выполнять их в том порядке, в котором их добавляли
+ */
+public interface IValidator {
+ /**
+ * метод для добавления правил валидации
+ * если положить правило с некорректными типами, при вызове validate будет ClassCastException
+ */
+ void addRule(IValidationRule> rule);
+
+ /**
+ * если хотим добавить проверки другого валидатора
+ * они будут выполняться только если проверки этого успешно пройдены
+ * возвращает себя
+ */
+ IValidator chain(IValidator anotherValidator);
+
+ /**
+ * валидирует все (подходит для случаев когда проверки не полагаются на то что предыдущие проверки прошли нормально)
+ */
+ Collection validateAll();
+
+ /**
+ * валидирует до первой ошибки
+ */
+ Optional tillFirstError();
+
+ /**
+ * валидирует все, возвращает первую ошибку - для совместимости
+ */
+ Optional validateAllReturnFirst();
+
+ default S getStored(Enum> storedObject) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/ValidationHelper.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/ValidationHelper.java
new file mode 100644
index 000000000..9b75f02f8
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/ValidationHelper.java
@@ -0,0 +1,36 @@
+package ru.spcex.clearing.validation.common.validator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
+import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
+import ru.spcex.clearing.platform.messaging.service.Status;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IMessageResolver;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+public class ValidationHelper {
+ private final static Logger log = LoggerFactory.getLogger(ValidationHelper.class);
+
+ public static RequestInfoUpdate validate(BaseRequest userRequest,
+ Function validatorBuilder,
+ IMessageResolver messageResolver) {
+ if (validatorBuilder != null) {
+ R req = userRequest.getRequestPayload();
+ IValidator validator = validatorBuilder.apply(req);
+ Optional validationError = validator.tillFirstError();
+ if (validationError.isPresent()) {
+ String errorMsg = messageResolver.resolve(validationError.get());
+ log.error("validation error for {} error={}, id={}: {}", req.getClass().getSimpleName(), validationError.get().getSubject(), userRequest.getId(), errorMsg);
+ return new RequestInfoUpdate()
+ .setId(userRequest.getId())
+ .setStatus(Status.Error)
+ .setMessage(errorMsg);
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/ValidatorImpl.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/ValidatorImpl.java
new file mode 100644
index 000000000..f647dc909
--- /dev/null
+++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/validator/ValidatorImpl.java
@@ -0,0 +1,113 @@
+package ru.spcex.clearing.validation.common.validator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import ru.spcex.clearing.validation.common.context.IValidatorContext;
+import ru.spcex.clearing.validation.common.rules.IValidationRule;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Валидатор, предназначенный для правил у которых есть "контекст" валидации
+ */
+public class ValidatorImpl implements IValidator {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private List> rules = new ArrayList<>();
+ private C context;
+ private IValidator chainedValidator;
+
+ public ValidatorImpl(C context) {this.context = context;}
+
+ public ValidatorImpl(C context, IValidationRule>... rules) { //
+ this.context = context;
+ for (IValidationRule> rule : rules) {
+ addRule(rule);
+ }
+ }
+
+ public void setContext(C context) {
+ this.context = context;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void addRule(IValidationRule> rule) {
+ rules.add((IValidationRule) rule);
+ }
+
+ @Override
+ public IValidator chain(IValidator anotherValidator) {
+ if (chainedValidator == null) {
+ chainedValidator = anotherValidator;
+ } else {
+ chainedValidator.chain(anotherValidator);
+ }
+ return this;
+ }
+
+ @Override
+ public Collection validateAll() {
+ List errors = new ArrayList<>();
+ Instant begin = Instant.now();
+ for (IValidationRule rule : rules) {
+ if (rule.runIfErrorsPresent() || errors.size() == 0) {
+ Optional validationError;
+ validationError = rule.validate(context);
+ validationError.ifPresent(errors::add);
+ if (validationError.isPresent()) {
+ log.debug("validating stage: {} error", rule.ruleName());
+ } else {
+ log.debug("validating stage: {} complete", rule.ruleName());
+ }
+ }
+ }
+ log.debug("validation {} in {} ms",
+ errors.size() == 0 ? "successfully completed" : "completed with errors",
+ Instant.now().toEpochMilli() - begin.toEpochMilli());
+ if (chainedValidator != null && errors.size() == 0) errors.addAll(chainedValidator.validateAll());
+ return errors;
+ }
+
+ @Override
+ public Optional tillFirstError() {
+ Instant begin = Instant.now();
+ for (IValidationRule rule : rules) {
+ log.debug("validating stage: {}", rule.ruleName());
+ Optional validationError;
+ validationError = rule.validate(context);
+ if (validationError.isPresent()) {
+ log.debug("validation stage: {} completed with error {} in {} ms",
+ rule.ruleName(), validationError.get().getSubject().getId(),
+ Instant.now().toEpochMilli() - begin.toEpochMilli());
+ return validationError;
+ }
+ }
+ log.debug("validation successfully completed in {} ms", Instant.now().toEpochMilli() - begin.toEpochMilli());
+ if (chainedValidator != null) return chainedValidator.tillFirstError();
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional validateAllReturnFirst() {
+ Collection allErrors = validateAll();
+ if (allErrors.size() > 0) {
+ EnumMessage error = allErrors.iterator().next();
+ return Optional.of(error);
+ } else
+ return Optional.empty();
+ }
+
+ @Override
+ public S getStored(Enum> storedObject) {
+ return context.getStoredObject(storedObject);
+ }
+
+ public C getContext() {
+ return context;
+ }
+}
diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClearingMemberCategoryValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClearingMemberCategoryValidationConfig.java
new file mode 100644
index 000000000..f338757e8
--- /dev/null
+++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClearingMemberCategoryValidationConfig.java
@@ -0,0 +1,114 @@
+//package ru.spcex.clearing.company.config.validation;
+//
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import ru.clearing.classes.statics.data.company.Company;
+//import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
+//import ru.clearing.platform.dictionary.ClearingCategoryDictionary;
+//import ru.spcex.clearing.company.error.CompanyErrors;
+//import ru.spcex.clearing.imdg.IMDGDistributedNames;
+//import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
+//import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryNewRequest;
+//import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryUpdateRequest;
+//import ru.spcex.clearing.validation.common.context.ImdgValidationContext;
+//import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
+//import ru.spcex.clearing.validation.common.rules.EnumPresentRule;
+//import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
+//import ru.spcex.clearing.validation.common.rules.IdPresentRule;
+//import ru.spcex.clearing.validation.common.validator.IValidator;
+//import ru.spcex.clearing.validation.common.validator.ValidatorImpl;
+//import ru.spcex.platform.classes.base.SpcexObjectBase;
+//import ru.spcex.platform.enumeration.ClearingCategory;
+//import ru.spcex.platform.enumeration.WorkflowStatus;
+//import ru.spcex.platform.imdg.api.Imdg;
+//
+//import java.util.Map;
+//import java.util.function.Consumer;
+//import java.util.function.Function;
+//
+//@Configuration
+//public class ClearingMemberCategoryValidationConfig {
+//
+// @Bean("clearingMemberCategoryNewRequestValidator")
+// public Function clearingMemberCategoryNewRequestValidator(
+// Map> imdgForValidation
+// ) {
+// return clearingMemberCategoryNewRequest -> {
+// ImdgValidationContext context = new ImdgValidationContext<>();
+// context.setValidatedObject(clearingMemberCategoryNewRequest);
+// Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
+// addImdg.accept(IMDGDistributedNames.Map_Company);
+// return new ValidatorImpl<>(context,
+// IdPresentRule.instance("companyId",
+// ClearingMemberCategoryNewRequest::getCompanyId,
+// IMDGDistributedNames.Map_Company,
+// Company.class,
+// CompanyErrors.RequiredFieldEmpty,
+// CompanyErrors.CompanyNotFound,
+// company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled),
+// FieldRequiredRule.instance("clearingMemberCategory",
+// ClearingMemberCategoryNewRequest::getClearingMemberCategory,
+// CompanyErrors.RequiredFieldEmpty));
+// };
+// }
+//
+// @Bean("clearingMemberCategoryUpdateRequestValidator")
+// public Function clearingMemberCategoryUpdateRequestValidator(
+// Map> imdgForValidation
+// ) {
+// return clearingMemberCategoryUpdateRequest -> {
+// ImdgValidationContext context = new ImdgValidationContext<>();
+// context.setValidatedObject(clearingMemberCategoryUpdateRequest);
+// Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
+// addImdg.accept(IMDGDistributedNames.Map_Company);
+// addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory);
+// return new ValidatorImpl<>(context,
+// IdPresentRule.instance("id",
+// ClearingMemberCategoryUpdateRequest::getId,
+// IMDGDistributedNames.Map_ClearingMemberCategory,
+// ClearingMemberCategory.class,
+// CompanyErrors.RequiredFieldEmpty,
+// CompanyErrors.CategoryNotFound,
+// clearingMemberCategory -> {
+// Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
+// Company company = companyImdg.getSingleObjectByID(clearingMemberCategory.getCompanyId());
+// if (company == null) return CompanyErrors.CompanyNotFound;
+// if (!WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()))
+// return CompanyErrors.CompanyDisabled;
+// return null;
+// }),
+// EnumPresentRule.instance("clearingMemberCategory",
+// ClearingMemberCategoryUpdateRequest::getClearingMemberCategory,
+// ClearingCategory.values(),
+// CompanyErrors.WrongFieldValue,
+// CompanyErrors.RequiredFieldEmpty),
+// DictionaryPresentRule.instance("clearingMemberCategory",
+// ClearingMemberCategoryUpdateRequest::getClearingMemberCategory,
+// IMDGDistributedNames.Map_ClearingCategoryDictionary,
+// ClearingCategoryDictionary.class,
+// CompanyErrors.RequiredFieldEmpty,
+// CompanyErrors.WrongFieldValue));
+// };
+// }
+//
+// @Bean("clearingMemberCategoryDeleteRequestValidator")
+// public Function clearingMemberCategoryDeleteRequestValidator(
+// Map> imdgForValidation
+// ) {
+// return clearingMemberCategoryDeleteRequest -> {
+// ImdgValidationContext context = new ImdgValidationContext<>();
+// context.setValidatedObject(clearingMemberCategoryDeleteRequest);
+// Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
+// addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory);
+// return new ValidatorImpl<>(context,
+// IdPresentRule.instance("id",
+// CommonDeleteRequest::getId,
+// IMDGDistributedNames.Map_ClearingMemberCategory,
+// ClearingMemberCategory.class,
+// CompanyErrors.RequiredFieldEmpty,
+// CompanyErrors.CategoryNotFound)
+// );
+// };
+// }
+//
+//}
diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ValidationConfig.java
new file mode 100644
index 000000000..e39ce71e4
--- /dev/null
+++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ValidationConfig.java
@@ -0,0 +1,30 @@
+//package ru.spcex.clearing.company.config.validation;
+//
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import ru.clearing.classes.statics.data.company.Company;
+//import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
+//import ru.spcex.clearing.imdg.IMDGDistributedNames;
+//import ru.spcex.platform.classes.base.SpcexObjectBase;
+//import ru.spcex.platform.imdg.api.Imdg;
+//import ru.spcex.platform.imdg.api.ImdgProvider;
+//
+//import java.util.HashMap;
+//import java.util.Map;
+//import java.util.function.BiConsumer;
+//
+//@Configuration
+//public class ValidationConfig {
+//
+// @Bean("imdgForValidation")
+// public Map> imdgForValidation(ImdgProvider imdgProvider) {
+// final Map> imdg = new HashMap<>();
+// BiConsumer> addImdg = (s, aClass) -> imdg.put(s, imdgProvider.getImdg(s, aClass));
+//
+// addImdg.accept(IMDGDistributedNames.Map_Company, Company.class);
+// addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
+//
+// return imdg;
+// }
+//
+//}
diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java
index 1784b0f5c..ca3edbd16 100644
--- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java
+++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java
@@ -8,7 +8,7 @@ public enum CompanyErrors implements IEnumId {
RequiredFieldEmpty(3002L), // Не заданы обязательные поля %s.
DictionaryNotFound(3003L), // Запись с идентификатором %s в справочнике %s не найдена.
- VrongFieldValue(3004L), // Неверное значение поля %s.
+ WrongFieldValue(3004L), // Неверное значение поля %s.
RecordAlreadyExist(3005L), // Запись с идентификатором %s уже существует.
RecordNotFound(3006L), // Запись с идентификатором %s не найдена.
CompanyALreadyExist(3010L), // Компания %s уже существует
diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClearingMemberCategoryService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClearingMemberCategoryService.java
index 869049fe8..6ca00b196 100644
--- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClearingMemberCategoryService.java
+++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClearingMemberCategoryService.java
@@ -15,19 +15,40 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques
import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
+import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
+import ru.spcex.platform.utils.enumeration.IMessageResolver;
@Service
public class ClearingMemberCategoryService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg clearingMemberCategoryMap;
+ private final IMessageResolver messageResolver;
+
+ /*
+ private final Function clearingMemberCategoryNewRequestValidator;
+ private final Function clearingMemberCategoryUpdateRequestValidator;
+ private final Function clearingMemberCategoryDeleteRequestValidator;
+ */
+
@Autowired
- public ClearingMemberCategoryService(Consumer kafkaQueue, Producer kafkaProducer,
- ImdgProvider imdgProvider) {
+ public ClearingMemberCategoryService(Consumer kafkaQueue,
+ Producer kafkaProducer,
+ ImdgProvider imdgProvider,
+ IMessageResolver messageResolver /*,
+ @Qualifier("clearingMemberCategoryNewRequestValidator") Function clearingMemberCategoryNewRequestValidator,
+ @Qualifier("clearingMemberCategoryUpdateRequestValidator") Function clearingMemberCategoryUpdateRequestValidator,
+ @Qualifier("clearingMemberCategoryDeleteRequestValidator") Function clearingMemberCategoryDeleteRequestValidator */) {
super(kafkaQueue, kafkaProducer);
this.clearingMemberCategoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
+ this.messageResolver = messageResolver;
+ /*
+ this.clearingMemberCategoryNewRequestValidator = clearingMemberCategoryNewRequestValidator;
+ this.clearingMemberCategoryUpdateRequestValidator = clearingMemberCategoryUpdateRequestValidator;
+ this.clearingMemberCategoryDeleteRequestValidator = clearingMemberCategoryDeleteRequestValidator;
+ */
}
@Override
@@ -44,19 +65,29 @@ public class ClearingMemberCategoryService extends QueueConsumer implements Init
init();
}
- private void clearingMemberCategoryNew(BaseRequest userRequest) {
+ private RequestInfoUpdate clearingMemberCategoryNew(BaseRequest userRequest) {
ClearingMemberCategoryNewRequest req = userRequest.getRequestPayload();
+
+// RequestInfoUpdate requestInfoUpdate = ValidationHelper.validate(userRequest, clearingMemberCategoryNewRequestValidator, messageResolver);
+// if (requestInfoUpdate != null) return requestInfoUpdate;
+
log.debug("ClearingMemberCategoryUpdateRequest received {}", userRequest.getId());
ClearingMemberCategory newCategory = new ClearingMemberCategory();
newCategory.setCompanyId(req.getCompanyId());
newCategory.setClearingMemberCategory(req.getClearingMemberCategory());
clearingMemberCategoryMap.insert(newCategory);
log.debug("successfully processed, new category id {}", newCategory.getId());
+
+ return null;
}
- public void clearingMemberCategoryUpdate(BaseRequest userRequest) {
+ public RequestInfoUpdate clearingMemberCategoryUpdate(BaseRequest userRequest) {
ClearingMemberCategoryUpdateRequest req = userRequest.getRequestPayload();
+
+// RequestInfoUpdate requestInfoUpdate = ValidationHelper.validate(userRequest, clearingMemberCategoryUpdateRequestValidator, messageResolver);
+// if (requestInfoUpdate != null) return requestInfoUpdate;
+
log.debug("ClearingMemberCategoryUpdateRequest received");
ClearingMemberCategory clearingMemberCategory = clearingMemberCategoryMap.getSingleObjectByID(req.getId());
@@ -64,12 +95,19 @@ public class ClearingMemberCategoryService extends QueueConsumer implements Init
clearingMemberCategoryMap.update(clearingMemberCategory);
log.debug("successfully processed, id {}", clearingMemberCategory.getId());
+ return null;
}
- private void clearingMemberCategoryDelete(BaseRequest userRequest) {
+ private RequestInfoUpdate clearingMemberCategoryDelete(BaseRequest userRequest) {
CommonDeleteRequest req = userRequest.getRequestPayload();
+
+// RequestInfoUpdate requestInfoUpdate = ValidationHelper.validate(userRequest, clearingMemberCategoryDeleteRequestValidator, messageResolver);
+// if (requestInfoUpdate != null) return requestInfoUpdate;
+
log.debug("CommonDeleteRequest received id = {}", req.getId());
ClearingMemberCategory clearingMemberCategory = clearingMemberCategoryMap.getSingleObjectByID(req.getId());
clearingMemberCategoryMap.delete(clearingMemberCategory);
+
+ return null;
}
}
diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/common/CommonDeleteRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/common/CommonDeleteRequest.java
index 5ad1de612..320c4d796 100644
--- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/common/CommonDeleteRequest.java
+++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/common/CommonDeleteRequest.java
@@ -7,6 +7,7 @@ public class CommonDeleteRequest implements WithId {
@JsonProperty
public Long id;
+ @Override
public Long getId() {
return id;
}
diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java
index ad10ca627..706b50f36 100644
--- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java
+++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java
@@ -171,6 +171,7 @@ public class QueueConsumer implements AutoCloseable {
* @param Класс проверяемого запроса
* @return null если ошибок нет
*/
+ @Deprecated
public RequestInfoUpdate validate(BaseRequest userRequest,
Function validatorBuilder,
IMessageResolver messageResolver) {
diff --git a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java
index 3ad88a3f1..707751089 100644
--- a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java
+++ b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/validation/IValidationRule.java
@@ -10,6 +10,7 @@ import java.util.Optional;
* Все необходимые данные берет из контекста
* @param контекст
*/
+// todo move this to clearing-utils (or move clearing-utils
public interface IValidationRule {
Optional validate(C context);