{
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- return false;
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public boolean isDone() {
- return false;
- }
-
- @Override
- public RecordMetadata get() throws InterruptedException, ExecutionException {
- return null;
- }
-
- @Override
- public RecordMetadata get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- return null;
- }
- }
-}
diff --git a/clearing-parent/balance-service/src/main/java/ru/spcex/clearing/balance/errors/BalanceError.java b/clearing-parent/balance-service/src/main/java/ru/spcex/clearing/balance/errors/BalanceError.java
index 773623c19..e933afed2 100644
--- a/clearing-parent/balance-service/src/main/java/ru/spcex/clearing/balance/errors/BalanceError.java
+++ b/clearing-parent/balance-service/src/main/java/ru/spcex/clearing/balance/errors/BalanceError.java
@@ -1,8 +1,8 @@
package ru.spcex.clearing.balance.errors;
-import ru.spcex.platform.utils.enumeration.IEnumId;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
-public enum BalanceError implements IEnumId {
+public enum BalanceError implements IErrorEnumId {
CompanyNotFound(5211L),
CurrencyNotFound(5213L),
CurrentDateOnly(5214L),
diff --git a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/ImdgTestConfig.java b/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/ImdgTestConfig.java
index c629b65d7..b1eaa9bc0 100644
--- a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/ImdgTestConfig.java
+++ b/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/ImdgTestConfig.java
@@ -58,7 +58,7 @@ public class ImdgTestConfig {
networkConfig.setJoin(joinConfig);
cfg.setNetworkConfig(networkConfig);
hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance(cfg);
- HazelcastHelper.otcSystem_setStorageState(true, hazelcastInstance);
+ HazelcastHelper.imdgSystem_setStorageState(true, hazelcastInstance);
return new HazelcastService(taskExecutorHazelcastClientInitializer, taskExecutorIdGeneratorAwaiter, params);
}
diff --git a/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/Security.java b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/Security.java
index d9d153dc2..b962fd9a8 100644
--- a/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/Security.java
+++ b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/Security.java
@@ -2,13 +2,15 @@ package ru.clearing.classes.statics.data.security;
import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.objects.BusinessObject;
+import ru.spcex.platform.classes.base.interfaces.WithInstrumentType;
+import ru.spcex.platform.classes.base.interfaces.WithWorkflowStatus;
/**
* Инструменты
*
* DB table: SECURITY
**/
-public class Security extends BusinessObject {
+public class Security extends BusinessObject implements WithWorkflowStatus, WithInstrumentType {
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private String instrumentType;
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java
index dfeee61f9..f7052004c 100644
--- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java
@@ -1,11 +1,11 @@
package ru.spcex.clearing.error;
-import ru.spcex.platform.utils.enumeration.IEnumId;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
-public enum ClearingErrorInternal implements IEnumId {
+public enum ClearingErrorInternal implements IErrorEnumId {
ClearingNotAllowed(1L),
- AccountNotActive(2L),
- CompanyNotActive(3L),
+ AccountNotActive(5415L),
+ CompanyNotActive(5411L),
FinancialObligationNotSatisfied(4L),
;
private final Long id;
diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java
index 6fa6dea43..6611b764d 100644
--- a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java
+++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java
@@ -44,7 +44,7 @@ public class HazelcastServiceTestConfiguration {
networkConfig.setJoin(joinConfig);
cfg.setNetworkConfig(networkConfig);
hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance(cfg);
- HazelcastHelper.otcSystem_setStorageState(true, hazelcastInstance);
+ HazelcastHelper.imdgSystem_setStorageState(true, hazelcastInstance);
return new HazelcastService(taskExecutorHazelcastClientInitializer, taskExecutorIdGeneratorAwaiter, params);
}
diff --git a/clearing-parent/clearing-validation/pom.xml b/clearing-parent/clearing-validation/pom.xml
new file mode 100644
index 000000000..60ad3b00b
--- /dev/null
+++ b/clearing-parent/clearing-validation/pom.xml
@@ -0,0 +1,95 @@
+
+
+ 4.0.0
+
+ clearing-validation
+ clearing-validation
+ Clearing-module, dependency version of platform-utils
+ jar
+ SPCEX-1.0.0.0
+
+
+ clearing-parent
+ ru.spcex.clearing
+ SPCEX-1.0.0.0
+
+
+
+ 17
+ 17
+
+
+
+
+ org.springframework
+ spring-core
+ provided
+
+
+ org.springframework
+ spring-context
+ provided
+
+
+ ru.spcex.clearing
+ classes
+ SPCEX-1.0.0.0
+ compile
+
+
+ ru.spcex.clearing
+ dictionary
+ SPCEX-1.0.0.0
+ compile
+
+
+ ru.spcex.platform
+ platform-enum
+
+
+ ru.spcex.platform
+ platform-utils
+
+
+
+
+ ru.spcex.platform
+ platform-imdg-api
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.33
+ provided
+
+
+
+
+ org.springframework
+ spring-test
+ test
+
+
+ org.skyscreamer
+ jsonassert
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+ ru.spcex.platform
+ platform-messaging
+
+
+
\ No newline at end of file
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/package-info.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/package-info.java
new file mode 100644
index 000000000..4077b07c4
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Утилиты с зависимостями от множества модулей clearing-*
+ */
+package ru.spcex.clearing.util;
\ No newline at end of file
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java
new file mode 100644
index 000000000..f8aef7bf6
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java
@@ -0,0 +1,66 @@
+package ru.spcex.clearing.util.services.exchangers;
+
+import org.apache.kafka.clients.consumer.Consumer;
+import org.apache.kafka.clients.producer.Producer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
+import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
+
+/**
+ * Синхронный обмен сообщениями с ассинхронным сервисом.
+ * Метод exchange() отправляет сообщение в очередь и дожидается ответа из другой очереди
+ */
+public class BiDirectionQueueExchanger> extends QueueConsumer implements InitializingBean, DisposableBean {
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ protected final Object sync = new Object();
+ protected String outQueue;
+ protected String inQueue;
+ protected Class listenClass;
+ protected long timeout;
+
+ /**
+ * Синхронно-ассинхронный обмен сообщениями
+ *
+ * @param kafkaQueue
+ * @param kafkaProducer
+ * @param outQueue отправляет в очередь
+ * @param inQueue слушает очередь, ожидает ответов
+ * @param listenClass типы объектов из inQueue
+ * @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено
+ */
+ public BiDirectionQueueExchanger(Consumer kafkaQueue, Producer kafkaProducer,
+ String outQueue,
+ String inQueue, Class listenClass,
+ long timeout) {
+ super(kafkaQueue, kafkaProducer);
+ this.outQueue = outQueue;
+ this.inQueue = inQueue;
+ this.listenClass = listenClass;
+ this.timeout = timeout;
+ }
+
+ /**
+ * Отправить сообщение message в outQueue и дождаться ответа из очереди inQueue
+ *
+ * @param message
+ * @return
+ * @throws InterruptedException
+ */
+ public TOut exchange(TIn message) throws InterruptedException {
+ //todo impl BiDirectionQueueExchanger
+ return null;
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ log.debug("Listener {} for async exchange {}-{} close", this, outQueue, inQueue);
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ log.debug("Listener {} for async exchange {}-{} ready", this, outQueue, inQueue);
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/ValidationHelper.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/ValidationHelper.java
new file mode 100644
index 000000000..9a3ad0c24
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/ValidationHelper.java
@@ -0,0 +1,58 @@
+package ru.spcex.clearing.validation.common;
+
+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 ru.spcex.platform.utils.validation.IValidator;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+public class ValidationHelper {
+ private final static Logger log = LoggerFactory.getLogger(ValidationHelper.class);
+
+ private IMessageResolver messageResolver;
+
+ public ValidationHelper(IMessageResolver messageResolver) {
+ Objects.requireNonNull(messageResolver);
+ this.messageResolver = messageResolver;
+ }
+
+ /**
+ * Валидация запроса до первой ошибки
+ *
+ * @param Класс проверяемого запроса
+ * @return null если ошибок нет
+ */
+ public RequestInfoUpdate validateTillFirstError(BaseRequest userRequest,
+ Function validatorBuilder) {
+ 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.warn("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;
+ }
+
+
+ public IMessageResolver getMessageResolver() {
+ return messageResolver;
+ }
+
+ public void setMessageResolver(IMessageResolver messageResolver) {
+ this.messageResolver = messageResolver;
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java
new file mode 100644
index 000000000..a22834156
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java
@@ -0,0 +1,62 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+import java.time.LocalDate;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка поля с LocalDate. Условие проверки: поверяемая дата >= текущая дата
+ * @param Класс проверяемого объекта
+ */
+public record DateNotBeforeRule(
+ String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorTaskForPastDate,
+ boolean required
+) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемой даты
+ * @param required Флаг обязательности поля
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorTaskForPastDate Ошибка, которая будет возвращена, если проверяемая дата меньше текущей
+ * @param Класс проверяемого объекта
+ */
+ public static DateNotBeforeRule instance(String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId 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,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId 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-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java
new file mode 100644
index 000000000..30c25318b
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java
@@ -0,0 +1,123 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.clearing.platform.dictionary.AbstractDictionary;
+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.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+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,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorWrongDictionaryValue,
+ boolean required,
+ Function[] additionalChecks) implements IValidationRule> {
+
+
+ /**
+ * @param fieldName Название поля
+ * @param getter Метод получения проверяемого значения
+ * @param dictionaryName Название словаря (см. IMDGDistributedNames)
+ * @param dictionaryClass Класс словаря (классы *Dictionary.class)
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorWrongDictionaryValue Ошибка, которая будет возвращена, если поле не найдено в словаре
+ * @param required Флаг обязательности
+ * @param additionalChecks Дополнительные проверки, связанные с этим полем
+ * @param Класс проверяемого объекта
+ * @param Класс словаря
+ */
+ @SafeVarargs
+ public static DictionaryPresentRule instance(String fieldName,
+ Function getter,
+ String dictionaryName,
+ Class dictionaryClass,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorWrongDictionaryValue,
+ boolean required,
+ Function... additionalChecks) {
+ return new DictionaryPresentRule<>(fieldName,
+ getter,
+ dictionaryName,
+ dictionaryClass,
+ errorEmptyRequiredValue,
+ errorWrongDictionaryValue,
+ required,
+ additionalChecks);
+ }
+
+ /**
+ * @param fieldName Название поля
+ * @param getter Метод получения проверяемого значения
+ * @param dictionaryName Название словаря (см. IMDGDistributedNames)
+ * @param dictionaryClass Класс словаря (классы *Dictionary.class)
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorWrongDictionaryValue Ошибка, которая будет возвращена, если поле не найдено в словаре
+ * @param additionalChecks Дополнительные проверки, связанные с этим полем
+ * @param Класс проверяемого объекта
+ * @param Класс словаря
+ */
+ @SafeVarargs
+ public static DictionaryPresentRule instance(String fieldName,
+ Function getter,
+ String dictionaryName,
+ Class dictionaryClass,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorWrongDictionaryValue,
+ Function... additionalChecks) {
+ return new DictionaryPresentRule<>(fieldName,
+ getter,
+ dictionaryName,
+ dictionaryClass,
+ errorEmptyRequiredValue,
+ errorWrongDictionaryValue,
+ true,
+ additionalChecks);
+ }
+
+ @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);
+ }
+ D dictionaryFromMap = fromMap.iterator().next();
+ if (dictionaryFromMap == null) {
+ return of(errorWrongDictionaryValue, fieldName);
+ }
+ for (Function additionalCheck : additionalChecks) {
+ IErrorEnumId validationError = additionalCheck.apply(dictionaryFromMap);
+ if (validationError != null)
+ return of(validationError, fieldName);
+ }
+ return empty();
+ }
+
+ @Override
+ public String ruleName() {
+ return getClass().getSimpleName() + "{" + fieldName + " - " + dictionaryName + "}";
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EndDtAfterStartDtRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EndDtAfterStartDtRule.java
new file mode 100644
index 000000000..169e5589f
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EndDtAfterStartDtRule.java
@@ -0,0 +1,86 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+import java.time.LocalDate;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка EndDt < StartDt
+ * @param Класс проверяемого объекта
+ */
+public record EndDtAfterStartDtRule(
+ String endDtFieldName,
+ String startDtFieldName,
+ Function getterEndDt,
+ Function getterStartDt,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorEndDtAfterStartDt,
+ boolean required
+) implements IValidationRule> {
+
+ /**
+ * @param endDtFieldName Название поля класса, содержащий EndDt
+ * @param startDtFieldName Название поля класса, содержащий StartDt
+ * @param getterEndDt Метод получения проверяемой EndDt
+ * @param getterStartDt Метод получения проверяемой StartDt
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если одна из дат пустая
+ * @param errorEndDtAfterStartDt Ошибка, которая будет возвращена, если EndDt > StartDt
+ * @param required Флаг обязательности поля
+ * @param Класс проверяемого объекта
+ */
+ public static EndDtAfterStartDtRule instance(String endDtFieldName,
+ String startDtFieldName,
+ Function getterEndDt,
+ Function getterStartDt,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorEndDtAfterStartDt,
+ boolean required) {
+ return new EndDtAfterStartDtRule<>(endDtFieldName,
+ startDtFieldName,
+ getterEndDt,
+ getterStartDt,
+ errorEmptyRequiredValue,
+ errorEndDtAfterStartDt,
+ required);
+ }
+
+ /**
+ * @param endDtFieldName Название поля класса, содержащий EndDt
+ * @param startDtFieldName Название поля класса, содержащий StartDt
+ * @param getterEndDt Метод получения проверяемой EndDt
+ * @param getterStartDt Метод получения проверяемой StartDt
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если одна из дат пустая
+ * @param errorEndDtAfterStartDt Ошибка, которая будет возвращена, если EndDt > StartDt
+ * @param Класс проверяемого объекта
+ */
+ public static EndDtAfterStartDtRule instance(String endDtFieldName,
+ String startDtFieldName,
+ Function getterEndDt,
+ Function getterStartDt,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorEndDtAfterStartDt) {
+ return new EndDtAfterStartDtRule<>(endDtFieldName,
+ startDtFieldName,
+ getterEndDt,
+ getterStartDt,
+ errorEmptyRequiredValue,
+ errorEndDtAfterStartDt,
+ true);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ LocalDate endDt = getterEndDt.apply(validatedObject);
+ LocalDate startDt = getterStartDt.apply(validatedObject);
+ if (endDt == null) return required ? of(errorEmptyRequiredValue, endDtFieldName) : Optional.empty();
+ if (startDt == null) return required ? of(errorEmptyRequiredValue, startDtFieldName) : Optional.empty();
+ if (endDt.isAfter(startDt)) return of(errorEndDtAfterStartDt, startDtFieldName, endDtFieldName);
+ return Optional.empty();
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java
new file mode 100644
index 000000000..5b503aedf
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java
@@ -0,0 +1,77 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IEnumKey;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка поля со значением из множества (enum)
+ * @param Класс проверяемого объекта
+ * @param Enum
+ */
+public record EnumPresentRule(String fieldName,
+ Function getter,
+ E[] enumValues,
+ boolean required,
+ IErrorEnumId errorWrongEnumValue,
+ IErrorEnumId errorEmptyRequiredValue) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля
+ * @param getter Метод получения проверяемого значения
+ * @param enumValues Значения из проверяемого множества (Enum.values())
+ * @param errorWrongEnumValue Ошибка, которая будет возвращена, если поле не найдено в Enum
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param required Флаг обязательности
+ * @param Класс проверяемого объекта
+ * @param Enum
+ */
+ public static EnumPresentRule instance(String fieldName,
+ Function getter,
+ E[] enumValues,
+ boolean required,
+ IErrorEnumId errorWrongEnumValue,
+ IErrorEnumId errorEmptyRequiredValue) {
+ if (errorWrongEnumValue == null) throw new IllegalArgumentException("Empty errorWrongEnumValue");
+ if (required && errorEmptyRequiredValue == null) throw new IllegalArgumentException("Empty errorEmptyRequiredValue");
+ return new EnumPresentRule<>(fieldName, getter, enumValues, required, errorWrongEnumValue, errorEmptyRequiredValue);
+ }
+
+ /**
+ * @param fieldName Название поля
+ * @param getter Метод получения проверяемого значения
+ * @param enumValues Значения из проверяемого множества (Enum.values())
+ * @param errorWrongEnumValue Ошибка, которая будет возвращена, если поле не найдено в Enum
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param Класс проверяемого объекта
+ * @param Enum
+ */
+ public static EnumPresentRule instance(String fieldName,
+ Function getter,
+ E[] enumValues,
+ IErrorEnumId errorWrongEnumValue,
+ IErrorEnumId errorEmptyRequiredValue) {
+ return new EnumPresentRule<>(fieldName, getter, enumValues, true, errorWrongEnumValue, errorEmptyRequiredValue);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ String enumCode = getter.apply(validatedObject);
+ if (enumCode == null) return required ? of(errorEmptyRequiredValue, fieldName) : empty();
+ for (E enumValue : enumValues) {
+ if (enumValue.getKey().equals(enumCode)) return empty();
+ }
+ return of(errorWrongEnumValue, fieldName);
+ }
+
+ @Override
+ public String ruleName() {
+ return getClass().getSimpleName() + "{" + fieldName + "}";
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java
new file mode 100644
index 000000000..eaa468190
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java
@@ -0,0 +1,63 @@
+package ru.spcex.clearing.validation.common.rules;
+
+
+import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка обязательности поля (not null)
+ *
+ * @param fieldName Название поля
+ * @param getter Метод получения значения
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param additionalChecks Дополнительные проверки, связанные с этим полем
+ * @param Класс проверяемого объекта
+ * @param Класс проверяемого значения
+ */
+public record FieldRequiredRule(
+ String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredValue,
+ Function[] additionalChecks
+) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля
+ * @param getter Метод получения значения
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param additionalChecks Дополнительные проверки, связанные с этим полем
+ * @param Класс проверяемого объекта
+ * @param Класс проверяемого значения
+ */
+ @SafeVarargs
+ public static FieldRequiredRule instance(String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredValue,
+ Function... additionalChecks) {
+ if (errorEmptyRequiredValue == null) throw new IllegalArgumentException("Empty errorEmptyRequiredValue");
+ return new FieldRequiredRule<>(fieldName, getter, errorEmptyRequiredValue, additionalChecks);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ V value = getter.apply(validatedObject);
+ if (value == null) return of(errorEmptyRequiredValue, fieldName);
+ for (Function additionalCheck : additionalChecks) {
+ IErrorEnumId validationError = additionalCheck.apply(value);
+ if (validationError != null)
+ return of(validationError, fieldName);
+ }
+ return empty();
+ }
+
+ @Override
+ public String ruleName() {
+ return getClass().getSimpleName() + "{" + fieldName + "}";
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java
new file mode 100644
index 000000000..1c6abcfaf
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java
@@ -0,0 +1,111 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.platform.classes.base.SpcexObjectBase;
+import ru.spcex.platform.imdg.api.Imdg;
+import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка наличия связанного по Id объекта в базе
+ * @param Класс проверяемого объекта
+ * @param Класс связанного объекта
+ */
+public record IdPresentRule(
+ String fieldName,
+ Function idGetter,
+ String mapName,
+ Class mapClass,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId 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,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId 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,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId 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) {
+ IErrorEnumId validationError = additionalCheck.apply(fromMap);
+ if (validationError != null)
+ return of(validationError, fieldName);
+ }
+ return empty();
+ }
+
+ @Override
+ public String ruleName() {
+ return getClass().getSimpleName() + "{" + fieldName + "}";
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IsLongValueRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IsLongValueRule.java
new file mode 100644
index 000000000..a5dcdd328
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IsLongValueRule.java
@@ -0,0 +1,66 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка поля типа String на возможность преобразования в Long
+ *
+ * @param Класс проверяемого объекта
+ */
+public record IsLongValueRule(
+ String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredField,
+ IErrorEnumId errorWrongFieldValue,
+ boolean required
+) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемого поля
+ * @param errorEmptyRequiredField Ошибка, которая будет возвращена, если поле пустое
+ * @param errorWrongFieldValue Ошибка, которая будет возвращена, если поле нельзя преобразовать в Long
+ * @param required Флаг обязательности поля
+ * @param Класс проверяемого объекта
+ */
+ public static IsLongValueRule instance(String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredField,
+ IErrorEnumId errorWrongFieldValue,
+ boolean required) {
+ return new IsLongValueRule<>(fieldName, getter, errorEmptyRequiredField, errorWrongFieldValue, required);
+ }
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемого поля
+ * @param errorEmptyRequiredField Ошибка, которая будет возвращена, если поле пустое
+ * @param errorWrongFieldValue Ошибка, которая будет возвращена, если поле нельзя преобразовать в Long
+ * @param Класс проверяемого объекта
+ */
+ public static IsLongValueRule instance(String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredField,
+ IErrorEnumId errorWrongFieldValue) {
+ return new IsLongValueRule<>(fieldName, getter, errorEmptyRequiredField, errorWrongFieldValue, true);
+ }
+
+ @Override
+ public Optional validate(ImdgValidationContext context) {
+ R validatedObject = context.getValidatedObject();
+ String longValueStr = getter.apply(validatedObject);
+ if (longValueStr == null) return required ? of(errorEmptyRequiredField, fieldName) : Optional.empty();
+ try {
+ Long longValue = Long.valueOf(longValueStr);
+ } catch (NumberFormatException e) {
+ return of(errorWrongFieldValue, fieldName);
+ }
+ return Optional.empty();
+ }
+}
diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java
new file mode 100644
index 000000000..7ab42a96c
--- /dev/null
+++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java
@@ -0,0 +1,62 @@
+package ru.spcex.clearing.validation.common.rules;
+
+import ru.spcex.platform.imdg.validation.ImdgValidationContext;
+import ru.spcex.platform.utils.enumeration.EnumMessage;
+import ru.spcex.platform.utils.enumeration.IErrorEnumId;
+import ru.spcex.platform.utils.validation.IValidationRule;
+
+import java.time.LocalTime;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Проверка поля с LocalTime. Условие проверки: проверяемое время >= текущее время
+ * @param Класс проверяемого объекта
+ */
+public record TimeNotBeforeRule(
+ String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId errorTaskForPastTime,
+ boolean required
+) implements IValidationRule> {
+
+ /**
+ * @param fieldName Название поля класса, используется для передачи ошибки
+ * @param getter Метод получения проверяемого времени
+ * @param errorEmptyRequiredValue Ошибка, которая будет возвращена, если поле пустое
+ * @param errorTaskForPastTime Ошибка, которая будет возвращена, если проверяемое время меньше текущего
+ * @param required Флаг обязательности поля
+ * @param Класс проверяемого объекта
+ */
+ public static TimeNotBeforeRule instance(String fieldName,
+ Function getter,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId 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,
+ IErrorEnumId errorEmptyRequiredValue,
+ IErrorEnumId 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/company-service/pom.xml b/clearing-parent/company-service/pom.xml
index a34291ee8..3143aecaa 100644
--- a/clearing-parent/company-service/pom.xml
+++ b/clearing-parent/company-service/pom.xml
@@ -28,6 +28,18 @@
ru.spcex.clearing
classes