From ae1c39f8b44624be17e20d36cdb957e1df98d80f Mon Sep 17 00:00:00 2001 From: AKurakin Date: Thu, 27 Apr 2023 18:55:14 +0300 Subject: [PATCH 01/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-272?= =?UTF-8?q?=20=20ClientCodeService,=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB=20BiDirectionQueueExchanger.=20=D0=9D=D0=B5=D0=BE=D0=B1?= =?UTF-8?q?=D1=85=D0=BE=D0=B4=D0=B8=D0=BC=D0=BE=20=D1=8D=D1=82=D0=BE=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D1=8C=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D0=BC=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exchangers/BiDirectionQueueExchanger.java | 180 +++++++- .../ClientCodeValidationConfig.java | 184 ++++++++ .../config/validation/ValidationConfig.java | 7 + .../clearing/company/error/CompanyErrors.java | 4 +- .../company/service/ClientCodeService.java | 416 ++++++++++++++++++ .../platform/messaging/domain/Consts.java | 2 + .../TradingClearingRegistryNewRequest.java | 10 + 7 files changed, 784 insertions(+), 19 deletions(-) create mode 100644 clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java create mode 100644 clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java 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 index f8aef7bf6..1439927b8 100644 --- 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 @@ -1,25 +1,56 @@ package ru.spcex.clearing.util.services.exchangers; +import org.apache.commons.lang3.StringUtils; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; 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.ActionType; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.balance.AccountBalanceClearingRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.clearing.Sdf04Request; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.platform.messaging.service.Status; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.utils.log.ExceptionUtils; + +import java.io.Closeable; +import java.util.Objects; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; /** * Синхронный обмен сообщениями с ассинхронным сервисом. - * Метод exchange() отправляет сообщение в очередь и дожидается ответа из другой очереди + * Метод exchange() отправляет сообщение в очередь и дожидается ответа из другой очереди. + * Использовать с осторожностью, т.к. нет возобновления ожидания в случае нештатного выключения модуля при ожидании ответа из kafka. + *

+ *

+ * Ожидает из очереди (CommonIdRequest) + * + * @param отправляется в очередь */ -public class BiDirectionQueueExchanger> extends QueueConsumer implements InitializingBean, DisposableBean { +public class BiDirectionQueueExchanger> extends QueueConsumer implements Closeable { 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; + private Producer producer; + + protected volatile boolean isTerminated; + protected Object syncObject; + protected Long lastSentRequestId; + protected volatile Long lastResponseId; + protected boolean ignoreOtherResponse = true; // Пропускать другие ID, пока не получит lastResponseId==lastSentRequestId /** * Синхронно-ассинхронный обмен сообщениями @@ -27,40 +58,153 @@ public class BiDirectionQueueExchanger> extends * @param kafkaQueue * @param kafkaProducer * @param outQueue отправляет в очередь - * @param inQueue слушает очередь, ожидает ответов - * @param listenClass типы объектов из inQueue - * @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено + * @param inQueue слушает очередь/топик, ожидает ответов. Пример: Consts.CONTINUE_CLEARING + * @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено */ public BiDirectionQueueExchanger(Consumer kafkaQueue, Producer kafkaProducer, String outQueue, - String inQueue, Class listenClass, + String inQueue, long timeout) { - super(kafkaQueue, kafkaProducer); + super(kafkaQueue); + this.producer = kafkaProducer; + if (kafkaQueue == null) { + throw new IllegalArgumentException("kafkaQueue is empty"); + } + if (kafkaProducer == null) { + throw new IllegalArgumentException("kafkaProducer is empty"); + } + if (StringUtils.isEmpty(outQueue)) { + throw new IllegalArgumentException("outQueue is empty"); + } this.outQueue = outQueue; + if (StringUtils.isEmpty(inQueue)) { + throw new IllegalArgumentException("inQueue is empty"); + } this.inQueue = inQueue; - this.listenClass = listenClass; + if (timeout < 0) { + timeout = 0; + } this.timeout = timeout; + + init(); } /** * Отправить сообщение message в outQueue и дождаться ответа из очереди inQueue * * @param message - * @return - * @throws InterruptedException + * @return request/reply id + * @throws InterruptedException или когда поток прерывают, или когда BiDirectionQueueExchanger.close() */ - public TOut exchange(TIn message) throws InterruptedException { - //todo impl BiDirectionQueueExchanger - return null; + public Long exchange(TOut message) throws InterruptedException { + if (syncObject == null) + throw new IllegalStateException("Listener queue not initialized"); + if (message.getId() == null) { + throw new IllegalArgumentException("Required message " + message.getClass().getSimpleName() + ".id is null"); + } + + //send request to kafka, wait for a reply + try { + synchronized (syncObject) { + Long sentRequestId = sendMessage(message); + log.trace("sent request to kafka, requestId: {}", sentRequestId); + this.lastSentRequestId = sentRequestId; + + long waitStart = System.currentTimeMillis(); + long waitTime = timeout; + do { + try { + if (timeout > 0) { + syncObject.wait(waitTime); + } else { + syncObject.wait(); + } + //если на этом месте произошла ошибка - непонятно как обрабатывать + //т.к. request на самом деле могла быть проблема с сетью/недоступностью кафки etc. + } catch (InterruptedException e) { + log.error(ExceptionUtils.getStackTrace(e)); + throw e; +// Thread.currentThread().interrupt(); +// throw new RuntimeException(e); + } + waitTime = timeout - (System.currentTimeMillis() - waitStart); + if (isTerminated && lastResponseId == null) { + log.warn("Terminated waiter {} kafka at thread {}", this, Thread.currentThread().getName()); + throw new InterruptedException(getClass().getSimpleName() + " closed"); + } + } while (ignoreOtherResponse && !sentRequestId.equals(lastResponseId) && (timeout > 0 && waitTime > 0)); + if (!sentRequestId.equals(lastResponseId)) { + log.error("FATAL: last response from {} update from Kafka ID was {}, but sent ID was {}", + inQueue, lastResponseId, sentRequestId); + throw new IllegalStateException("Expected wait till requestId=" + sentRequestId + " but catch lastResponseId=" + lastResponseId); + } + return sentRequestId; + + } + } finally { + this.lastSentRequestId = null; + } } @Override - public void destroy() throws Exception { + public void close() { + isTerminated = true; + if (lastSentRequestId != null) { + log.warn("Finished before wait, lastSentRequestId={}", lastSentRequestId); + if (syncObject != null) { + synchronized (syncObject) { + lastResponseId = null; + syncObject.notifyAll(); + } + } + } + syncObject = null; log.debug("Listener {} for async exchange {}-{} close", this, outQueue, inQueue); } - @Override - public void afterPropertiesSet() throws Exception { + public void init() { + if (syncObject != null) { + throw new IllegalStateException("Already initialized"); + } + callback(CommonIdRequest.class) + .setConsumer(this::continueWaiting) + .forDestination(inQueue, callbacks::put); + init(); + + syncObject = new Object(); + isTerminated = false; + log.debug("Listener {} for async exchange {}-{} ready", this, outQueue, inQueue); } + + protected Long sendMessage(TOut message) throws InterruptedException { + Long sentRequestId = message.getId(); + if (sentRequestId == null) { + throw new IllegalArgumentException("Message " + message.getClass().getSimpleName() + " required id."); + } + try { + Future send = producer.send(new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, message)); + send.get(); + return sentRequestId; + } catch (InterruptedException e) { + log.error("Interrupt when send message, {}", ExceptionUtils.getStackTrace(e)); + Thread.currentThread().interrupt(); + throw e; + } catch (ExecutionException e) { + log.error("Error at send message, {} cause: {}", e.toString(), ExceptionUtils.getStackTrace(e.getCause())); + throw new RuntimeException("Send message error", e.getCause()); + } catch (Exception e) { + log.error("Unexpected exception when send message: {}", ExceptionUtils.getStackTrace(e)); + } + return null; + } + + protected void continueWaiting(BaseRequest event) { + synchronized (syncObject) { + CommonIdRequest requestPayload = event.getRequestPayload(); + log.debug("continueWaiting {} for id={}", inQueue, requestPayload.getId()); + lastResponseId = requestPayload.getId(); + syncObject.notifyAll(); + } + } } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java new file mode 100644 index 000000000..296b3b103 --- /dev/null +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java @@ -0,0 +1,184 @@ +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.account.Account; +import ru.clearing.classes.statics.data.account.ClientCode; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.platform.dictionary.ClearingCategoryDictionary; +import ru.clearing.platform.dictionary.WorkflowStatusDictionary; +import ru.spcex.clearing.company.error.CompanyErrors; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest; +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.CompanySymbolUpdateRequest; +import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule; +import ru.spcex.clearing.validation.common.rules.FieldRequiredRule; +import ru.spcex.clearing.validation.common.rules.IdPresentRule; +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.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; + +@Configuration +public class ClientCodeValidationConfig { + + @Bean("clientCodeNewRequestValidator") + public Function clientCodeNewRequestValidator(Map> imdgForValidation) { + return clientCodeUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clientCodeUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Account); + addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry); + addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary); + return new ValidatorImpl<>(context, + FieldRequiredRule.instance("companyId", CompanySymbolUpdateRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), + IdPresentRule.instance("companyId", + ClientCodeNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.CompanyNotFound), + + IdPresentRule.instance("moneyAccountId", + ClientCodeNewRequest::getMoneyAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.AccountNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : CompanyErrors.AccountNotFound + ), + IdPresentRule.instance("depoAccountId", + ClientCodeNewRequest::getDepoAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.AccountNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : CompanyErrors.AccountNotFound + ), + IdPresentRule.instance("tradingClearingRegistryId", + ClientCodeNewRequest::getTradingClearingRegistryId, + IMDGDistributedNames.Map_TradingClearingRegistry, + Account.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.TradingClearingRegistryNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : CompanyErrors.TradingClearingRegistryNotFound + ), + + + DictionaryPresentRule.instance("stauts", + ClientCodeNewRequest::getStatus, + IMDGDistributedNames.Map_WorkflowStatusDictionary, + WorkflowStatusDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.DictionaryNotFound, + false) + ); + }; + } + + @Bean("clientCodeUpdateRequestValidator") + public Function clientCodeUpdateRequestValidator(Map> imdgForValidation) { + return clientCodeUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clientCodeUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_ClientCode); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Account); + addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry); + addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary); + return new ValidatorImpl>(context, + IdPresentRule.instance("id", + ClientCodeUpdateRequest::getId, + IMDGDistributedNames.Map_ClientCode, + ClientCode.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.RecordNotFound + ), + + FieldRequiredRule.instance("companyId", CompanySymbolUpdateRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), + IdPresentRule.instance("companyId", + ClientCodeUpdateRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.CompanyNotFound), + + IdPresentRule.instance("moneyAccountId", + ClientCodeUpdateRequest::getMoneyAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.AccountNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : CompanyErrors.AccountNotFound + ), + IdPresentRule.instance("depoAccountId", + ClientCodeUpdateRequest::getDepoAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.AccountNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : CompanyErrors.AccountNotFound + ), + IdPresentRule.instance("tradingClearingRegistryId", + ClientCodeUpdateRequest::getTradingClearingRegistryId, + IMDGDistributedNames.Map_TradingClearingRegistry, + Account.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.TradingClearingRegistryNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : CompanyErrors.TradingClearingRegistryNotFound + ), + + DictionaryPresentRule.instance("stauts", + ClientCodeUpdateRequest::getStatus, + IMDGDistributedNames.Map_WorkflowStatusDictionary, + WorkflowStatusDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.DictionaryNotFound, + false) + ); + }; + } + + @Bean("clientCodeDeleteRequestValidator") + public Function clientCodeDeleteRequestValidator(Map> imdgForValidation) { + return companyDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(companyDeleteRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + return new ValidatorImpl<>(context, +// FieldRequiredRule.instance("id", CommonDeleteRequest::getId, CompanyErrors.RequiredFieldEmpty), + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_ClientCode, + ClientCode.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.RecordNotFound) + ); + }; + } +} 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 index 597365270..cd6671cf1 100644 --- 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 @@ -2,11 +2,14 @@ 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.account.Account; +import ru.clearing.classes.statics.data.account.ClientCode; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.CompanySymbols; import ru.clearing.classes.statics.data.company.ClearingMemberCategory; import ru.clearing.classes.statics.data.profile.Contact; import ru.clearing.classes.statics.data.profile.ProfileDocument; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; import ru.clearing.platform.dictionary.*; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.validation.common.ValidationHelper; @@ -44,6 +47,10 @@ public class ValidationConfig { addImdg.accept(IMDGDistributedNames.Map_LegalKindDictionary, LegalKindDictionary.class); addImdg.accept(IMDGDistributedNames.Map_OrganizationTypeDictionary, OrganizationTypeDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_ClientCode, ClientCode.class); + addImdg.accept(IMDGDistributedNames.Map_Account, Account.class); + addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.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 d36d2104f..3979ab8b9 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 @@ -22,7 +22,9 @@ public enum CompanyErrors implements IErrorEnumId { CompanyAlreadyHasLiabilities(3018L), // У компании %s присутствуют обязательства. CompanyWithCompanySymbolAlreadyExist(3019L), // Компания с %s = %s уже создана" (где первый %s - companySymbol, второй %s - companySymbolValue) EditCompanySymbols(3020L), // Тип реквизита компании %s не может быть изменен. - EditContactType(3021L) // Тип контакта компании %s не может быть изменен. + EditContactType(3021L), // Тип контакта компании %s не может быть изменен. + TradingClearingRegistryNotFound(3022L), // ТКР с %s не найден + AccountNotFound(3023L), // Счет %s не найден ; private final Long id; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java new file mode 100644 index 000000000..105ef2589 --- /dev/null +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java @@ -0,0 +1,416 @@ +package ru.spcex.clearing.company.service; + +import org.apache.kafka.clients.consumer.Consumer; +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.account.ClientCode; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.spcex.clearing.company.error.CompanyErrors; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.ActionType; +import ru.spcex.clearing.platform.messaging.domain.BaseRequest; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryUpdateRequest; +import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +import ru.spcex.clearing.util.security.UserRoleVerification; +import ru.spcex.clearing.util.services.exchangers.BiDirectionQueueExchanger; +import ru.spcex.clearing.validation.common.ValidationHelper; +import ru.spcex.platform.enumeration.TradingClearingRegistryType; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgId; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgIdGeneratorHazelcast; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.error.ClearingBaseException; +import ru.spcex.platform.utils.log.ExceptionUtils; +import ru.spcex.platform.utils.validation.IValidator; + +import java.time.Instant; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.function.Function; + +@Service +public class ClientCodeService extends QueueConsumer implements InitializingBean, DisposableBean { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Producer kafkaProducer; + private final ImdgId idGenerator; + private final Imdg clientCodeMap; + private final Imdg companyMap; + private final Imdg tradingClearingRegistryMap; + + + private final Function clientCodeNewRequestValidator; + private final Function clientCodeUpdateRequestValidator; + private final Function clientCodeDeleteRequestValidator; + private final ValidationHelper validationHelper; + private final UserRoleVerification userRoleVerification; + private final IMessageResolver messageResolver; + + BiDirectionQueueExchanger> accountServiceExchanger; + + @Autowired + public ClientCodeService(Consumer kafkaQueue, + Producer kafkaProducer, + ImdgProvider imdgProvider, + ValidationHelper validationHelper, + IMessageResolver messageResolver, + UserRoleVerification userRoleVerification, + @Qualifier("clientCodeNewRequestValidator") Function clientCodeNewRequestValidator, + @Qualifier("clientCodeUpdateRequestValidator") Function clientCodeUpdateRequestValidator, + @Qualifier("clientCodeDeleteRequestValidator") Function clientCodeDeleteRequestValidator) { + super(kafkaQueue, kafkaProducer); + this.kafkaProducer = kafkaProducer; + this.idGenerator = imdgProvider.getImdgIdGenerator(); + this.clientCodeMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class); + this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + this.tradingClearingRegistryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); + this.clientCodeNewRequestValidator = clientCodeNewRequestValidator; + this.clientCodeUpdateRequestValidator = clientCodeUpdateRequestValidator; + this.clientCodeDeleteRequestValidator = clientCodeDeleteRequestValidator; + this.validationHelper = validationHelper; + this.messageResolver = messageResolver; + this.userRoleVerification = userRoleVerification; + + this.accountServiceExchanger = new BiDirectionQueueExchanger<>(kafkaQueue, kafkaProducer, + Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW, + Consts.DESTINATION_TRADING_CLEARING_REGISTRY_REPLY, // todo naming + 60000 + ); + } + + @Override + public void afterPropertiesSet() { + callback(ClientCodeNewRequest.class) + .setConsumer(this::clientCodeNew) + .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW, callbacks::put); + callback(ClientCodeNewRequest.class) + .setConsumer(this::clientCodeNewFromApiUmCompany) + .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW_UM_COMPANY, callbacks::put); + + callback(ClientCodeUpdateRequest.class) + .setConsumer(this::clientCodeUpdate) + .forDestination(Consts.DESTINATION_CLIENT_CODE_UPDATE, callbacks::put); + callback(CommonDeleteRequest.class) + .setConsumer(this::clientCodeDelete) + .forDestination(Consts.DESTINATION_CLIENT_CODE_DELETE, callbacks::put); + init(); + + } + + @Override + public void destroy() { + accountServiceExchanger.close(); + } + + protected RequestInfoUpdate clientCodeNew(BaseRequest userRequest) { + log.debug("ClientCodeNewRequest received {}", userRequest.getId()); + + RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest); + if (requestInfoUpdate != null) return requestInfoUpdate; + + requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeNewRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + + ClientCodeNewRequest req = userRequest.getRequestPayload(); + + boolean doCreateTCR = checkNeedCreateTCR(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (doCreateTCR) { + try { + createAndWaitTCR(userRequest.getId(), null, + req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + } catch (ClearingBaseException e) { + log.error("Can not wait creation of TCR. request id={};CompanyId={}, MoneyAccountId={}, DepoAccountId={}; {}", + userRequest.getId(), req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId(), + e.toString()); + return makeErrorResponse(userRequest, CompanyErrors.GeneralError, "Can not create TCR at this moment"); + } + } + + if (req.getTradingClearingRegistryId() == null && req.getMoneyAccountId() != null) { + TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (tradingClearingRegistry == null) { + return makeErrorResponse(userRequest, CompanyErrors.TradingClearingRegistryNotFound); + } else { + req.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + } + } + ClientCode newClientCode = buildClientCode(req); + clientCodeMap.insert(newClientCode); + log.debug("successfully processed, new clientCode id {}", newClientCode.getId()); + + return null; + } + + + protected RequestInfoUpdate clientCodeNewFromApiUmCompany(BaseRequest userRequest) { + log.debug("ClientCodeNewRequest received {}", userRequest.getId()); + + RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest); + if (requestInfoUpdate != null) return requestInfoUpdate; + + requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeNewRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + + + ClientCodeNewRequest req = userRequest.getRequestPayload(); + + boolean doCreateTCR = checkNeedCreateTCR(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (doCreateTCR) { + try { + createAndWaitTCR(userRequest.getId(), null, + req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + } catch (ClearingBaseException e) { + log.error("Can not wait creation of TCR. request id={};CompanyId={}, MoneyAccountId={}, DepoAccountId={}; {}", + userRequest.getId(), req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId(), + e.toString()); + return makeErrorResponse(userRequest, CompanyErrors.GeneralError, "Can not create TCR at this moment"); + } + } + + if (req.getTradingClearingRegistryId() == null && req.getMoneyAccountId() != null) { + TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (tradingClearingRegistry == null) { + return makeErrorResponse(userRequest, CompanyErrors.TradingClearingRegistryNotFound); + } else { + req.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + } + } + ClientCode newClientCode = buildClientCode(req); + clientCodeMap.insert(newClientCode); + log.debug("successfully processed, new clientCode id {}", newClientCode.getId()); + + return null; + } + + + protected RequestInfoUpdate clientCodeUpdate(BaseRequest userRequest) { + ClientCodeUpdateRequest req = userRequest.getRequestPayload(); + + RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest); + if (requestInfoUpdate != null) return requestInfoUpdate; + + requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeUpdateRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + + + log.debug("ClientCodeUpdateRequest received, id={}", req.getId()); + ClientCode clientCode = clientCodeMap.getSingleObjectByID(req.getId()); + if (clientCode == null) { + return makeErrorResponse(userRequest, CompanyErrors.RecordNotFound, req.getId()); + } + + boolean doCreateTCR = checkNeedCreateTCR(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (doCreateTCR) { + try { + createAndWaitTCR(userRequest.getId(), clientCode.getId(), + req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + } catch (ClearingBaseException e) { + log.error("Can not wait creation of TCR. request id={};CompanyId={}, MoneyAccountId={}, DepoAccountId={}; {}", + userRequest.getId(), req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId(), + e.toString()); + return makeErrorResponse(userRequest, CompanyErrors.GeneralError, "Can not create TCR at this moment"); + } + } + + if (req.getTradingClearingRegistryId() == null && req.getMoneyAccountId() != null) { + TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (tradingClearingRegistry == null) { + return makeErrorResponse(userRequest, CompanyErrors.TradingClearingRegistryNotFound); + } else { + req.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + } + } + updateClientCode(clientCode, req); + + clientCodeMap.update(clientCode); + log.debug("successfully processed update, id {}", clientCode.getId()); + return null; + } + + private RequestInfoUpdate makeErrorResponse(BaseRequest req, CompanyErrors err, Object... arg) { + String errMsg = messageResolver.resolve(new EnumMessage(err, arg)); + return new RequestInfoUpdate() + .setId(req.getId()) + .setStatus(ru.spcex.clearing.platform.messaging.service.Status.Error) + .setMessage(errMsg); + + } + + protected RequestInfoUpdate clientCodeDelete(BaseRequest userRequest) { + log.debug("CommonDeleteRequest received id = {}", userRequest.getId()); + CommonDeleteRequest req = userRequest.getRequestPayload(); + + RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest); + if (requestInfoUpdate != null) return requestInfoUpdate; + + requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeDeleteRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + + ClientCode clientCode = clientCodeMap.getSingleObjectByID(req.getId()); + if (clientCode.getMoneyAccountId() != null) { + log.debug("Delete clientCode.id = {}: send message to account-service", clientCode.getId()); + sendBlockTCR(clientCode.getTradingClearingRegistryId(), clientCode.getMoneyAccountId()); + } + log.debug("Delete clientCode.id={}", clientCode.getId()); + clientCodeMap.delete(clientCode); + + return null; + } + + TradingClearingRegistry selectTradingClearingRegistry(Long companyId, Long moneyAccountId, Long depoAccountId) { + Map> query = new HashMap<>(); + query.put("companyId", companyId); + query.put("moneyAccountId", moneyAccountId); + query.put("tradingClearingRegistryType", TradingClearingRegistryType.Client_B.getKey()); + if (depoAccountId != null) { + query.put("depoAccountId", depoAccountId); + } + TradingClearingRegistry result = tradingClearingRegistryMap.getSingleObjectByFieldValues(query); + log.trace("TradingClearingRegistry by: {}; {}found", query, result == null ? "not " : ""); + return result; + } + + private boolean checkNeedCreateTCR(Long companyId, Long moneyAccountId, Long depoAccountId) { + // moneyAccountId обязателен, depoAccountId опционален + if (moneyAccountId == null) { + return false; + } + TradingClearingRegistry result = selectTradingClearingRegistry(companyId, moneyAccountId, depoAccountId); + if (result == null) { + return true; + } else { + return false; + } + } + + protected void createAndWaitTCR(Long reqId, Long clientCode, + Long companyId, Long moneyAccountId, Long depoAccountId) throws ClearingBaseException { + log.debug("For request {}, clientCode={} need create TCR: companyId={}, moneyAccountId={}, depoAccountId={}", + reqId, clientCode == null ? "new" : clientCode, + companyId, moneyAccountId, depoAccountId); + BaseRequest request = new BaseRequest<>(); + request.setId(idGenerator.nextId()); + request.setActionType(ActionType.NEW); + TradingClearingRegistryNewRequest requestPayload = new TradingClearingRegistryNewRequest(); + requestPayload.setCompanyId(companyId); + requestPayload.setMoneyAccountId(moneyAccountId); + requestPayload.setDepoAccountId(depoAccountId); +// requestPayload.setStatus(WorkflowStatus.Active.getKey()); + requestPayload.setTradingClearingRegistryType(TradingClearingRegistryType.Client_B.getKey()); + request.setRequestPayload(requestPayload); + try { + Long reply = accountServiceExchanger.exchange(request); + if (reply == null) { + throw new ClearingBaseException(CompanyErrors.GeneralError, "Waiting account-service timeout"); + } + // примечание: ошибка и сбой (непредвиденное завершение программы) не приведёт к необратимым последствиям, + // т.к. пользователь сможет повторить запрос, а созданный на предыдущем запросе ТКР уже будет создан и найдётся. + } catch (InterruptedException e) { + throw new ClearingBaseException(CompanyErrors.GeneralError, "Waiting account-service timeout"); + } + } + + protected void sendBlockTCR(Long tradingClearingRegistryId, Long moneyAccountId) { + if (tradingClearingRegistryId == null) { + throw new IllegalArgumentException("tradingClearingRegistryId was null"); + } + BaseRequest request = new BaseRequest<>(); + request.setId(idGenerator.nextId()); + request.setActionType(ActionType.UPDATE); + TradingClearingRegistryUpdateRequest requestPayload = new TradingClearingRegistryUpdateRequest(); + requestPayload.setId(tradingClearingRegistryId); + requestPayload.setStatus(WorkflowStatus.Blocked.getKey()); + request.setRequestPayload(requestPayload); + + try { + sendMessage(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE, request); + } catch (Exception e) { + log.error("Can not send block TCR message, {}", e.toString()); + throw e; + } + } + + + /** + * @param queue Consts.* + * @param message BaseRequest + * @return + */ + private Long sendMessage(String queue, BaseRequest message) { + Long sentRequestId = message.getId(); + if (sentRequestId == null) { + throw new IllegalArgumentException("Message " + message.getClass().getSimpleName() + " required id."); + } + log.debug("Send to \"{}\" message {} id={}", queue, message.getActionType(), sentRequestId); + try { + Future send = kafkaProducer.send(new ProducerRecord<>(queue, message)); + send.get(); + return sentRequestId; + } catch (InterruptedException e) { + log.error("Interrupt when send message, {}", ExceptionUtils.getStackTrace(e)); + Thread.currentThread().interrupt(); + throw new RuntimeException("Thread interrupted when send message to " + queue, e); + } catch (ExecutionException e) { + log.error("Error at send message, {} cause: {}", e.toString(), ExceptionUtils.getStackTrace(e.getCause())); + throw new RuntimeException("Send message error", e.getCause()); + } catch (Exception e) { + log.error("Unexpected exception when send message: {}", ExceptionUtils.getStackTrace(e)); + } + return null; + } + + /** + * @param req требуется заполнить tradingClearingRegistryId по tradingClearingRegistry.code + * @return + */ + private ClientCode buildClientCode(ClientCodeNewRequest req) { + ClientCode clientCode = new ClientCode(); +// clientCode.setId(idSequence.newId()); add in insert + clientCode.setCreated(Instant.now()); + clientCode.setUpdated(clientCode.getCreated()); + + clientCode.setCompanyId(req.getCompanyId()); + clientCode.setCode(req.getCode()); + clientCode.setTradingClearingRegistryId(req.getTradingClearingRegistryId()); + clientCode.setMoneyAccountId(req.getMoneyAccountId()); + clientCode.setDepoAccountId(req.getDepoAccountId()); + clientCode.setStatus(req.getStatus()); + + return clientCode; + } + + private void updateClientCode(ClientCode clientCode, ClientCodeUpdateRequest req) { + assert clientCode.getId() != null && clientCode.getId().equals(req.getId()); + + clientCode.setCompanyId(req.getCompanyId()); + clientCode.setCode(req.getCode()); + clientCode.setTradingClearingRegistryId(req.getTradingClearingRegistryId()); + clientCode.setMoneyAccountId(req.getMoneyAccountId()); + clientCode.setDepoAccountId(req.getDepoAccountId()); + clientCode.setStatus(req.getStatus()); + + clientCode.setUpdated(Instant.now()); + } + +} diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java index f07a3033e..95b708d0d 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java @@ -66,12 +66,14 @@ public interface Consts { String DESTINATION_PROFILE_DOCUMENT_DELETE = "profile-document-delete"; String DESTINATION_CLIENT_CODE_NEW = "client-code-new"; + String DESTINATION_CLIENT_CODE_NEW_UM_COMPANY = "client-code-new-from-api-um-company"; String DESTINATION_CLIENT_CODE_UPDATE = "client-code-update"; String DESTINATION_CLIENT_CODE_DELETE = "client-code-delete"; String DESTINATION_TRADING_CLEARING_REGISTRY_NEW = "trading-clearing-registry-new"; String DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE = "trading-clearing-registry-update"; String DESTINATION_TRADING_CLEARING_REGISTRY_DELETE = "trading-clearing-registry-delete"; + String DESTINATION_TRADING_CLEARING_REGISTRY_REPLY = "trading-clearing-registry"; String DESTINATION_SDF08_NEW = "s-df-08-new"; String DESTINATION_SDF02_NEW = "s-df-02-new"; diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/TradingClearingRegistryNewRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/TradingClearingRegistryNewRequest.java index 75041b81e..c68eed1ba 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/TradingClearingRegistryNewRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/TradingClearingRegistryNewRequest.java @@ -21,6 +21,8 @@ public class TradingClearingRegistryNewRequest { private Long depoAccountId; @JsonProperty private String status; + @JsonProperty + private String tradingClearingRegistryType; public Long getCompanyId() { return companyId; @@ -50,6 +52,14 @@ public class TradingClearingRegistryNewRequest { return status; } + public String getTradingClearingRegistryType() { + return tradingClearingRegistryType; + } + + public void setTradingClearingRegistryType(String tradingClearingRegistryType) { + this.tradingClearingRegistryType = tradingClearingRegistryType; + } + public void setStatus(String status) { this.status = status; } From a87f2ac0dcbe2ef4af6f9fe643e472abaea3b147 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Fri, 28 Apr 2023 19:50:30 +0300 Subject: [PATCH 02/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-272?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BA=D0=B8,=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=BB=20=D1=8E=D0=BD=D0=B8=D1=82=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=20(=D0=BF=D0=BE=D0=BA=D0=B0=20=D0=BD=D0=B5=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=85=D0=BE=D0=B4=D0=B8=D1=82)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exchangers/BiDirectionQueueExchanger.java | 4 +- .../company/service/ClientCodeService.java | 2 +- .../service/ClientCodeServiceTest.java | 309 ++++++++++++++++++ 3 files changed, 312 insertions(+), 3 deletions(-) create mode 100644 clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java 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 index 1439927b8..6a0444a4e 100644 --- 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 @@ -86,7 +86,7 @@ public class BiDirectionQueueExchanger> extends Queu } this.timeout = timeout; - init(); + initReplyListener(); } /** @@ -162,7 +162,7 @@ public class BiDirectionQueueExchanger> extends Queu log.debug("Listener {} for async exchange {}-{} close", this, outQueue, inQueue); } - public void init() { + protected void initReplyListener() { if (syncObject != null) { throw new IllegalStateException("Already initialized"); } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java index 105ef2589..a03d9c7a0 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java @@ -284,7 +284,7 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean query.put("moneyAccountId", moneyAccountId); query.put("tradingClearingRegistryType", TradingClearingRegistryType.Client_B.getKey()); if (depoAccountId != null) { - query.put("depoAccountId", depoAccountId); + query.put("depoAaccountId", depoAccountId); // todo опечатка в поле класса, см. meta.xml! } TradingClearingRegistry result = tradingClearingRegistryMap.getSingleObjectByFieldValues(query); log.trace("TradingClearingRegistry by: {}; {}found", query, result == null ? "not " : ""); diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java new file mode 100644 index 000000000..1510de3e8 --- /dev/null +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java @@ -0,0 +1,309 @@ +package ru.spcex.clearing.company.service; + +import org.apache.kafka.clients.consumer.MockConsumer; +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.account.ClientCode; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.profile.CompanyInfo; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.clearing.platform.dictionary.*; +import ru.spcex.clearing.company.config.BeanConfiguration; +import ru.spcex.clearing.company.config.validation.ClientCodeValidationConfig; +import ru.spcex.clearing.company.config.validation.ValidationConfig; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.BaseRequest; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.test.MatcherFactory; +import ru.spcex.clearing.test.TestUtils; +import ru.spcex.clearing.test.config.ImdgTestConfig; +import ru.spcex.clearing.test.config.KafkaTestConfig; +import ru.spcex.platform.enumeration.TradingClearingRegistryType; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; + +import javax.annotation.PostConstruct; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparator; +import static ru.spcex.clearing.test.TestUtils.*; +import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + ClientCodeService.class, + ClientCodeValidationConfig.class, + + ValidationConfig.class, + BeanConfiguration.class, + + KafkaTestConfig.class, + ImdgTestConfig.class}) +class ClientCodeServiceTest { + + private static final int PARTITION = 0; + private static final Long ID = 4L; + public static final MatcherFactory.Matcher CLIENT_CODE_MATCHER = usingIgnoringFieldsComparator(); + + private static final Long TCR_ID = 41L; + private static final Long COMPANY_ID = 42L; + + @Autowired + ClientCodeService clientCodeService; + @Autowired + @Qualifier("hazelcastServiceTest") + private ImdgProvider hazelcastServiceTest; + @Captor + private ArgumentCaptor producerRecord; + @SpyBean + private MockProducer mockProducer; + + private Imdg clientCodeImdg; + + + // ****************************-******************* + + @PostConstruct + private void init() { + waitAvailableImdgProviderAndAddAdminWithDefaultId(); + clientCodeImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class); + + // Словари для теста, применяются в ValidationConfig + putToDictionary(IMDGDistributedNames.Map_WorkflowStatusDictionary, new WorkflowStatusDictionary(), "ACTV"); + putToDictionary(IMDGDistributedNames.Map_CompanySymbolDictionary, new CompanySymbolDictionary(), "CLRC"); + putToDictionary(IMDGDistributedNames.Map_CorporationSoleTypeDictionary, new CorporationSoleTypeDictionary(), "GDIR"); + putToDictionary(IMDGDistributedNames.Map_CountryCodeDictionary, new CountryCodeDictionary(), "RUS"); + putToDictionary(IMDGDistributedNames.Map_AllowedDictionary, new AllowedDictionary(), "ALWD"); + putToDictionary(IMDGDistributedNames.Map_LegalKindDictionary, new LegalKindDictionary(), "JURD"); + putToDictionary(IMDGDistributedNames.Map_OrganizationTypeDictionary, new OrganizationTypeDictionary(), "NCRD"); + + + Imdg companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + Company company1 = new Company(); + company1.setId(COMPANY_ID); + company1.setWorkflowStatus(WorkflowStatus.Active.getKey()); + company1.setFullName("Company prime"); + company1.setShortName("Seizwell"); + company1.setProfile(new CompanyInfo()); + company1.getProfile().setCompanyId(COMPANY_ID); + company1.getProfile().setCountryCode("TLDI"); + company1.getProfile().setDescription("Big profit from TLD Company Prime."); + company1.getProfile().setLegalKind("TLDI"); + company1.getProfile().setResidence("TLDI"); + companyImdg.insert(company1); + + Imdg tcrImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); + TradingClearingRegistry registry1 = new TradingClearingRegistry(); + registry1.setId(TCR_ID); + registry1.setCompanyId(COMPANY_ID); + registry1.setCode("code-120-101"); + registry1.setMoneyAccountId(131L); + registry1.setDepoAaccountId(132L); + registry1.setTradingClearingRegistryType(TradingClearingRegistryType.Client_B.getKey()); + registry1.setStatus(WorkflowStatus.Active.getKey()); + tcrImdg.insert(registry1); + + TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class); + doReturn(future).when(mockProducer).send(producerRecord.capture()); + } + + private void putToDictionary(String mapName, D object, String code) { + Imdg dMap = (Imdg) hazelcastServiceTest.getImdg(mapName, object.getClass()); + object.setId(2L); + object.setCode(code); + object.setName("name of " + code); + dMap.insert(object); + } + + @Test + void selectTradingClearingRegistry() { + TradingClearingRegistry tcr = clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 131L, 132L); + assertNotNull(tcr); + assertEquals(41L, tcr.getId()); + + tcr = clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 131L, null); + assertNotNull(tcr); + assertEquals(41L, tcr.getId()); + + assertNull(clientCodeService.selectTradingClearingRegistry(0L, 131L, 132L)); + assertNull(clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 0L, 132L)); + assertNull(clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 131L, 0L)); + } + + + /** + * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
+ * Тест проверяет создание {@link ClientCode} в IMDG при передаче из Apache Kafka (очередь 1).
+ * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest}:
+ **/ + @Test + void clientCodeNew1() { + //ARRANGE + final String ccCode = "Lucky planet"; + ClientCodeNewRequest clientCodeNewRequest = new ClientCodeNewRequest(); + clientCodeNewRequest.setCompanyId(COMPANY_ID); + clientCodeNewRequest.setCode(ccCode); + clientCodeNewRequest.setTradingClearingRegistryId(TCR_ID); + clientCodeNewRequest.setDepoAccountId(null); + clientCodeNewRequest.setMoneyAccountId(null); + clientCodeNewRequest.setStatus("ACTV"); + + ClientCode predictableClientCode = new ClientCode(); + predictableClientCode.setCode(ccCode); + predictableClientCode.setStatus("ACTV"); + predictableClientCode.setCompanyId(COMPANY_ID); + predictableClientCode.setMoneyAccountId(131L); + predictableClientCode.setDepoAccountId(132L); + predictableClientCode.setTradingClearingRegistryId(TCR_ID); + + //ACT + String jsonString = getJsonStringForNew(clientCodeNewRequest, ID); + + addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_NEW, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = %d", ccCode)); + predictableClientCode.setId(resultNew.getId()); + CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode); + } + + /** + * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
+ * Тест проверяет создание {@link ClientCode} в IMDG при передаче из Apache Kafka (очередь 2).
+ * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest}:
+ **/ + @Test + void clientCodeNew2() { + //ARRANGE + final String ccCode = "Lucky planet"; + ClientCodeNewRequest clientCodeNewRequest = new ClientCodeNewRequest(); + clientCodeNewRequest.setCompanyId(COMPANY_ID); + clientCodeNewRequest.setCode(ccCode); + clientCodeNewRequest.setTradingClearingRegistryId(TCR_ID); + clientCodeNewRequest.setDepoAccountId(null); + clientCodeNewRequest.setMoneyAccountId(null); + clientCodeNewRequest.setStatus("ACTV"); + + ClientCode predictableClientCode = new ClientCode(); + predictableClientCode.setCode(ccCode); + predictableClientCode.setStatus("ACTV"); + predictableClientCode.setCompanyId(COMPANY_ID); + predictableClientCode.setMoneyAccountId(131L); + predictableClientCode.setDepoAccountId(132L); + predictableClientCode.setTradingClearingRegistryId(TCR_ID); + + //ACT + String jsonString = getJsonStringForNew(clientCodeNewRequest, ID); + + addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_NEW_UM_COMPANY, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = %d", ccCode)); + predictableClientCode.setId(resultNew.getId()); + CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode); + } + + /** + * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
+ * Тест проверяет обновление сущности {@link ClientCode} в IMDG при передаче из Apache Kafka.
+ * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest}:
+ **/ + @Test + void clientCodeUpdate() { + //ARRANGE + ClientCode existsClientCode = new ClientCode(); + existsClientCode.setId(ID); + existsClientCode.setCompanyId(COMPANY_ID); + existsClientCode.setCode("0000"); + existsClientCode.setTradingClearingRegistryId(TCR_ID); + existsClientCode.setMoneyAccountId(200L); + existsClientCode.setDepoAccountId(201L); + existsClientCode.setStatus("ACTV"); + + ClientCodeUpdateRequest clientCodeUpdateRequest = new ClientCodeUpdateRequest(); + clientCodeUpdateRequest.setId(ID); + existsClientCode.setCompanyId(COMPANY_ID); + existsClientCode.setCode("1111"); +// existsClientCode.setTradingClearingRegistryId(TCR_ID); + existsClientCode.setMoneyAccountId(200L); + existsClientCode.setDepoAccountId(201L); + existsClientCode.setStatus("ACTV"); + + ClientCode predictableClientCode = new ClientCode(); + predictableClientCode.setId(ID); + predictableClientCode.setCompanyId(COMPANY_ID); + predictableClientCode.setCode("1111"); + predictableClientCode.setTradingClearingRegistryId(TCR_ID); + predictableClientCode.setMoneyAccountId(200L); + predictableClientCode.setDepoAccountId(201L); + predictableClientCode.setStatus("ACTV"); + + //ACT + String jsonString = getJsonStringForUpdate(clientCodeUpdateRequest, ID); + + addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_UPDATE, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + + ClientCode resultUpdating = clientCodeImdg.getSingleObjectByID(ID); + CLIENT_CODE_MATCHER.assertMatch(resultUpdating, predictableClientCode); + //todo !!!! + } + + + /** + * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
+ * Тест проверяет удаление {@link ClientCode} из IMDG при передаче из Apache Kafka.
+ * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest}:
+ **/ + @Test + void clientCodeDelete() { + //ARRANGE + ClientCode existsClientCode = new ClientCode(); + existsClientCode.setId(ID); + existsClientCode.setCompanyId(COMPANY_ID); + existsClientCode.setCode("0000"); + existsClientCode.setTradingClearingRegistryId(TCR_ID); + existsClientCode.setMoneyAccountId(200L); + existsClientCode.setDepoAccountId(201L); + existsClientCode.setStatus("ACTV"); + + clientCodeImdg.insert(existsClientCode); + + CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest(); + clientCodeDeleteRequest.setId(ID); + + Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data + + //ACT + String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID); + + addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID); + Assertions.assertNull(resultUpdate); + } + + +} \ No newline at end of file From 795b488629630acbfd6f41f60d1f7b0013078baf Mon Sep 17 00:00:00 2001 From: AKurakin Date: Wed, 3 May 2023 13:58:35 +0300 Subject: [PATCH 03/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-272?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exchangers/BiDirectionQueueExchanger.java | 8 ++- .../ClientCodeValidationConfig.java | 14 +++--- .../company/service/ClientCodeService.java | 2 +- .../service/ClientCodeServiceTest.java | 49 ++++++++++++++++--- .../platform/messaging/domain/Consts.java | 2 +- 5 files changed, 58 insertions(+), 17 deletions(-) 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 index 6a0444a4e..35da485b1 100644 --- 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 @@ -59,11 +59,13 @@ public class BiDirectionQueueExchanger> extends Queu * @param kafkaProducer * @param outQueue отправляет в очередь * @param inQueue слушает очередь/топик, ожидает ответов. Пример: Consts.CONTINUE_CLEARING + * @param ignoreOtherResponse true для inQueue=Consts.REQUEST_INFO_UPDATE * @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено */ public BiDirectionQueueExchanger(Consumer kafkaQueue, Producer kafkaProducer, String outQueue, String inQueue, + boolean ignoreOtherResponse, long timeout) { super(kafkaQueue); this.producer = kafkaProducer; @@ -85,8 +87,9 @@ public class BiDirectionQueueExchanger> extends Queu timeout = 0; } this.timeout = timeout; + this.ignoreOtherResponse = ignoreOtherResponse; - initReplyListener(); + //fixme debug only ! initReplyListener(); } /** @@ -132,6 +135,9 @@ public class BiDirectionQueueExchanger> extends Queu log.warn("Terminated waiter {} kafka at thread {}", this, Thread.currentThread().getName()); throw new InterruptedException(getClass().getSimpleName() + " closed"); } + if (ignoreOtherResponse && !sentRequestId.equals(lastResponseId)) { + log.debug("Ignore response id={}, we waiting {}.", lastResponseId, sentRequestId); + } } while (ignoreOtherResponse && !sentRequestId.equals(lastResponseId) && (timeout > 0 && waitTime > 0)); if (!sentRequestId.equals(lastResponseId)) { log.error("FATAL: last response from {} update from Kafka ID was {}, but sent ID was {}", diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java index 296b3b103..0b88150b4 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java @@ -5,15 +5,13 @@ import org.springframework.context.annotation.Configuration; import ru.clearing.classes.statics.data.account.Account; import ru.clearing.classes.statics.data.account.ClientCode; import ru.clearing.classes.statics.data.company.Company; -import ru.clearing.platform.dictionary.ClearingCategoryDictionary; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; import ru.clearing.platform.dictionary.WorkflowStatusDictionary; import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest; 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.CompanySymbolUpdateRequest; import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule; import ru.spcex.clearing.validation.common.rules.FieldRequiredRule; import ru.spcex.clearing.validation.common.rules.IdPresentRule; @@ -42,7 +40,7 @@ public class ClientCodeValidationConfig { addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry); addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary); return new ValidatorImpl<>(context, - FieldRequiredRule.instance("companyId", CompanySymbolUpdateRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), + FieldRequiredRule.instance("companyId", ClientCodeNewRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), IdPresentRule.instance("companyId", ClientCodeNewRequest::getCompanyId, IMDGDistributedNames.Map_Company, @@ -73,7 +71,7 @@ public class ClientCodeValidationConfig { IdPresentRule.instance("tradingClearingRegistryId", ClientCodeNewRequest::getTradingClearingRegistryId, IMDGDistributedNames.Map_TradingClearingRegistry, - Account.class, + TradingClearingRegistry.class, CompanyErrors.RequiredFieldEmpty, CompanyErrors.TradingClearingRegistryNotFound, false, @@ -113,7 +111,7 @@ public class ClientCodeValidationConfig { CompanyErrors.RecordNotFound ), - FieldRequiredRule.instance("companyId", CompanySymbolUpdateRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), + FieldRequiredRule.instance("companyId", ClientCodeNewRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), IdPresentRule.instance("companyId", ClientCodeUpdateRequest::getCompanyId, IMDGDistributedNames.Map_Company, @@ -144,7 +142,7 @@ public class ClientCodeValidationConfig { IdPresentRule.instance("tradingClearingRegistryId", ClientCodeUpdateRequest::getTradingClearingRegistryId, IMDGDistributedNames.Map_TradingClearingRegistry, - Account.class, + TradingClearingRegistry.class, CompanyErrors.RequiredFieldEmpty, CompanyErrors.TradingClearingRegistryNotFound, false, @@ -169,7 +167,7 @@ public class ClientCodeValidationConfig { ImdgValidationContext context = new ImdgValidationContext<>(); context.setValidatedObject(companyDeleteRequest); Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); - addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_ClientCode); return new ValidatorImpl<>(context, // FieldRequiredRule.instance("id", CommonDeleteRequest::getId, CompanyErrors.RequiredFieldEmpty), IdPresentRule.instance("id", diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java index a03d9c7a0..2e82f5e9b 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java @@ -94,7 +94,7 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean this.accountServiceExchanger = new BiDirectionQueueExchanger<>(kafkaQueue, kafkaProducer, Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW, - Consts.DESTINATION_TRADING_CLEARING_REGISTRY_REPLY, // todo naming + Consts.REQUEST_INFO_UPDATE, true, // REQUEST_INFO_UPDATE - стандартная очередь, для результатов всех реквестов. DESTINATION_TRADING_CLEARING_REGISTRY_REPLY, 60000 ); } diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java index 1510de3e8..46867f68a 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java @@ -39,8 +39,7 @@ import ru.spcex.platform.imdg.api.ImdgProvider; import javax.annotation.PostConstruct; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.*; import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparator; import static ru.spcex.clearing.test.TestUtils.*; import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId; @@ -179,7 +178,7 @@ class ClientCodeServiceTest { //ASSERT waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); - ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = %d", ccCode)); + ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = '%s'", ccCode)); predictableClientCode.setId(resultNew.getId()); CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode); } @@ -216,7 +215,7 @@ class ClientCodeServiceTest { //ASSERT waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); - ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = %d", ccCode)); + ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = '%s'", ccCode)); predictableClientCode.setId(resultNew.getId()); CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode); } @@ -276,12 +275,50 @@ class ClientCodeServiceTest { * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest}:
**/ @Test - void clientCodeDelete() { + void clientCodeDelete1() { //ARRANGE ClientCode existsClientCode = new ClientCode(); existsClientCode.setId(ID); existsClientCode.setCompanyId(COMPANY_ID); existsClientCode.setCode("0000"); + // Если следующие поля заполнить, то дополнительно отправит сообщение в trading-clearing-registry-update: +// existsClientCode.setTradingClearingRegistryId(TCR_ID); +// existsClientCode.setMoneyAccountId(200L); +// existsClientCode.setDepoAccountId(201L); + existsClientCode.setStatus("ACTV"); + + clientCodeImdg.insert(existsClientCode); + + CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest(); + clientCodeDeleteRequest.setId(ID); + + Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data + + //ACT + String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID); + + addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString); + + //ASSERT + + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID); + Assertions.assertNull(resultUpdate); + } + + /** + * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
+ * Тест проверяет удаление {@link ClientCode} из IMDG при передаче из Apache Kafka.
+ * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest}:
+ **/ + @Test + void clientCodeDelete2() { + //ARRANGE + ClientCode existsClientCode = new ClientCode(); + existsClientCode.setId(ID); + existsClientCode.setCompanyId(COMPANY_ID); + existsClientCode.setCode("0000"); + // Если следующие поля заполнить, то дополнительно отправит сообщение в trading-clearing-registry-update: existsClientCode.setTradingClearingRegistryId(TCR_ID); existsClientCode.setMoneyAccountId(200L); existsClientCode.setDepoAccountId(201L); @@ -300,10 +337,10 @@ class ClientCodeServiceTest { addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString); //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID); Assertions.assertNull(resultUpdate); } - } \ No newline at end of file diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java index 95b708d0d..20b041d22 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java @@ -73,7 +73,7 @@ public interface Consts { String DESTINATION_TRADING_CLEARING_REGISTRY_NEW = "trading-clearing-registry-new"; String DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE = "trading-clearing-registry-update"; String DESTINATION_TRADING_CLEARING_REGISTRY_DELETE = "trading-clearing-registry-delete"; - String DESTINATION_TRADING_CLEARING_REGISTRY_REPLY = "trading-clearing-registry"; +// String DESTINATION_TRADING_CLEARING_REGISTRY_REPLY = "trading-clearing-registry"; String DESTINATION_SDF08_NEW = "s-df-08-new"; String DESTINATION_SDF02_NEW = "s-df-02-new"; From f53d05ba6cc3b69e43fb7763a991e3555a6ab3ff Mon Sep 17 00:00:00 2001 From: psemenkov Date: Thu, 4 May 2023 13:22:38 +0300 Subject: [PATCH 04/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-276?= =?UTF-8?q?=20=D0=9F=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BE?= =?UTF-8?q?=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D1=83=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/importer/services/TradeImporterService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clearing-parent/trade-importer/src/main/java/ru/spcex/clearing/trade/importer/services/TradeImporterService.java b/clearing-parent/trade-importer/src/main/java/ru/spcex/clearing/trade/importer/services/TradeImporterService.java index 2d8134533..551119d24 100644 --- a/clearing-parent/trade-importer/src/main/java/ru/spcex/clearing/trade/importer/services/TradeImporterService.java +++ b/clearing-parent/trade-importer/src/main/java/ru/spcex/clearing/trade/importer/services/TradeImporterService.java @@ -68,12 +68,12 @@ public class TradeImporterService { } if (byCommand) { - STradesImportedRequest sTradesImportedRequest = new STradesImportedRequest(); - producer.send(new ProducerRecord<>(S_TRADES_IMPORTED, sTradesImportedRequest)); log.debug("Successfully import STrades from DB by command. Send to kafka command, topic={}", S_TRADES_IMPORTED); } else { - log.debug("Successfully import STrades from DB by scheduled"); + log.debug("Successfully import STrades from DB by scheduled. Send to kafka command, topic={}", S_TRADES_IMPORTED); } + STradesImportedRequest sTradesImportedRequest = new STradesImportedRequest(); + producer.send(new ProducerRecord<>(S_TRADES_IMPORTED, sTradesImportedRequest)); } public STrades getSTradesFromImdg(STrades tradesDb, Imdg sTradesImdg) { From 3ec2177641fb3acf849622f694a635f491950940 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Thu, 4 May 2023 16:16:13 +0300 Subject: [PATCH 05/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-272?= =?UTF-8?q?=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=8B=20(=D0=BD=D0=B5=20=D1=81=D1=82=D0=B0=D0=B1?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D1=8E=D1=82)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exchangers/BiDirectionQueueExchanger.java | 2 +- .../ClientCodeValidationConfig.java | 2 +- .../service/ClientCodeServiceTest.java | 172 ++++++++++-------- 3 files changed, 99 insertions(+), 77 deletions(-) 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 index 35da485b1..c26f63b0c 100644 --- 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 @@ -89,7 +89,7 @@ public class BiDirectionQueueExchanger> extends Queu this.timeout = timeout; this.ignoreOtherResponse = ignoreOtherResponse; - //fixme debug only ! initReplyListener(); + initReplyListener(); } /** diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java index 0b88150b4..653c6320d 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java @@ -111,7 +111,7 @@ public class ClientCodeValidationConfig { CompanyErrors.RecordNotFound ), - FieldRequiredRule.instance("companyId", ClientCodeNewRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), + FieldRequiredRule.instance("companyId", ClientCodeUpdateRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty), IdPresentRule.instance("companyId", ClientCodeUpdateRequest::getCompanyId, IMDGDistributedNames.Map_Company, diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java index 46867f68a..503174d22 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java @@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.account.Account; import ru.clearing.classes.statics.data.account.ClientCode; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.profile.CompanyInfo; @@ -44,6 +45,7 @@ import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparato import static ru.spcex.clearing.test.TestUtils.*; import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId; +//todo тесты случайно ломаются из-за BiDirectionQueueExchanger. Когда там выключаю initReplyListener() то тесты стабильно работают. @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { ClientCodeService.class, @@ -58,7 +60,7 @@ class ClientCodeServiceTest { private static final int PARTITION = 0; private static final Long ID = 4L; - public static final MatcherFactory.Matcher CLIENT_CODE_MATCHER = usingIgnoringFieldsComparator(); + public static final MatcherFactory.Matcher CLIENT_CODE_MATCHER = usingIgnoringFieldsComparator("created","updated"); private static final Long TCR_ID = 41L; private static final Long COMPANY_ID = 42L; @@ -118,6 +120,20 @@ class ClientCodeServiceTest { registry1.setStatus(WorkflowStatus.Active.getKey()); tcrImdg.insert(registry1); + Imdg accounts = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Account, Account.class); + Account moneyAccount=new Account(); + moneyAccount.setId(131L); + moneyAccount.setAccount("AAAA-4444"); + moneyAccount.setStatus("ACTV"); + moneyAccount.setCompanyId(COMPANY_ID); // для валидации принадлежности счёта + accounts.insert(moneyAccount); + Account depoAccount=new Account(); + depoAccount.setId(132L); + depoAccount.setAccount("AAAB-44654"); + depoAccount.setStatus("ACTV"); + depoAccount.setCompanyId(COMPANY_ID); // для валидации принадлежности счёта + accounts.insert(depoAccount); + TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class); doReturn(future).when(mockProducer).send(producerRecord.capture()); } @@ -167,8 +183,8 @@ class ClientCodeServiceTest { predictableClientCode.setCode(ccCode); predictableClientCode.setStatus("ACTV"); predictableClientCode.setCompanyId(COMPANY_ID); - predictableClientCode.setMoneyAccountId(131L); - predictableClientCode.setDepoAccountId(132L); +// predictableClientCode.setMoneyAccountId(131L); +// predictableClientCode.setDepoAccountId(132L); predictableClientCode.setTradingClearingRegistryId(TCR_ID); //ACT @@ -181,6 +197,7 @@ class ClientCodeServiceTest { ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = '%s'", ccCode)); predictableClientCode.setId(resultNew.getId()); CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode); + assertNotNull(resultNew.getCreated()); } /** @@ -204,8 +221,8 @@ class ClientCodeServiceTest { predictableClientCode.setCode(ccCode); predictableClientCode.setStatus("ACTV"); predictableClientCode.setCompanyId(COMPANY_ID); - predictableClientCode.setMoneyAccountId(131L); - predictableClientCode.setDepoAccountId(132L); +// predictableClientCode.setMoneyAccountId(131L); +// predictableClientCode.setDepoAccountId(132L); predictableClientCode.setTradingClearingRegistryId(TCR_ID); //ACT @@ -218,8 +235,11 @@ class ClientCodeServiceTest { ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = '%s'", ccCode)); predictableClientCode.setId(resultNew.getId()); CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode); + assertNotNull(resultNew.getCreated()); } + //todo добавить тест NEW заполненными MoneyAccountId(131L), DepoAccountId(132L); - от этого направляется дополнительное сообщение в очередь и используется ожидание ответа. + /** * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
* Тест проверяет обновление сущности {@link ClientCode} в IMDG при передаче из Apache Kafka.
@@ -233,26 +253,27 @@ class ClientCodeServiceTest { existsClientCode.setCompanyId(COMPANY_ID); existsClientCode.setCode("0000"); existsClientCode.setTradingClearingRegistryId(TCR_ID); - existsClientCode.setMoneyAccountId(200L); - existsClientCode.setDepoAccountId(201L); + existsClientCode.setMoneyAccountId(131L); + existsClientCode.setDepoAccountId(132L); existsClientCode.setStatus("ACTV"); + clientCodeImdg.insert(existsClientCode); ClientCodeUpdateRequest clientCodeUpdateRequest = new ClientCodeUpdateRequest(); clientCodeUpdateRequest.setId(ID); - existsClientCode.setCompanyId(COMPANY_ID); - existsClientCode.setCode("1111"); -// existsClientCode.setTradingClearingRegistryId(TCR_ID); - existsClientCode.setMoneyAccountId(200L); - existsClientCode.setDepoAccountId(201L); - existsClientCode.setStatus("ACTV"); + clientCodeUpdateRequest.setCompanyId(COMPANY_ID); + clientCodeUpdateRequest.setCode("1111"); + clientCodeUpdateRequest.setTradingClearingRegistryId(TCR_ID); + clientCodeUpdateRequest.setMoneyAccountId(131L); + clientCodeUpdateRequest.setDepoAccountId(132L); + clientCodeUpdateRequest.setStatus("ACTV"); ClientCode predictableClientCode = new ClientCode(); predictableClientCode.setId(ID); predictableClientCode.setCompanyId(COMPANY_ID); predictableClientCode.setCode("1111"); predictableClientCode.setTradingClearingRegistryId(TCR_ID); - predictableClientCode.setMoneyAccountId(200L); - predictableClientCode.setDepoAccountId(201L); + predictableClientCode.setMoneyAccountId(131L); + predictableClientCode.setDepoAccountId(132L); predictableClientCode.setStatus("ACTV"); //ACT @@ -265,7 +286,7 @@ class ClientCodeServiceTest { ClientCode resultUpdating = clientCodeImdg.getSingleObjectByID(ID); CLIENT_CODE_MATCHER.assertMatch(resultUpdating, predictableClientCode); - //todo !!!! + assertNotNull(resultUpdating.getUpdated()); } @@ -282,65 +303,66 @@ class ClientCodeServiceTest { existsClientCode.setCompanyId(COMPANY_ID); existsClientCode.setCode("0000"); // Если следующие поля заполнить, то дополнительно отправит сообщение в trading-clearing-registry-update: + existsClientCode.setTradingClearingRegistryId(null); + existsClientCode.setMoneyAccountId(null); + existsClientCode.setDepoAccountId(null); + existsClientCode.setStatus("ACTV"); + + clientCodeImdg.insert(existsClientCode); + + CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest(); + clientCodeDeleteRequest.setId(ID); + + Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data + + //ACT + String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID); + + addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString); + + //ASSERT + + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID); + Assertions.assertNull(resultUpdate); + } + +// /** +// * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
+// * Тест проверяет удаление {@link ClientCode} из IMDG при передаче из Apache Kafka.
+// * У ClientCode заполнены MoneyAccountId, DepoAccountId - по этому при удалении должно направиться дополнительное сообщение в очередь DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE
+// * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest}:
+// **/ +// @Test +// void clientCodeDelete2() { +// //ARRANGE +// ClientCode existsClientCode = new ClientCode(); +// existsClientCode.setId(ID); +// existsClientCode.setCompanyId(COMPANY_ID); +// existsClientCode.setCode("0000"); +// // Если следующие поля заполнить, то дополнительно отправит сообщение в trading-clearing-registry-update: // existsClientCode.setTradingClearingRegistryId(TCR_ID); -// existsClientCode.setMoneyAccountId(200L); -// existsClientCode.setDepoAccountId(201L); - existsClientCode.setStatus("ACTV"); - - clientCodeImdg.insert(existsClientCode); - - CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest(); - clientCodeDeleteRequest.setId(ID); - - Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data - - //ACT - String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID); - - addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString); - - //ASSERT - - waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); - ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID); - Assertions.assertNull(resultUpdate); - } - - /** - * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}
- * Тест проверяет удаление {@link ClientCode} из IMDG при передаче из Apache Kafka.
- * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest}:
- **/ - @Test - void clientCodeDelete2() { - //ARRANGE - ClientCode existsClientCode = new ClientCode(); - existsClientCode.setId(ID); - existsClientCode.setCompanyId(COMPANY_ID); - existsClientCode.setCode("0000"); - // Если следующие поля заполнить, то дополнительно отправит сообщение в trading-clearing-registry-update: - existsClientCode.setTradingClearingRegistryId(TCR_ID); - existsClientCode.setMoneyAccountId(200L); - existsClientCode.setDepoAccountId(201L); - existsClientCode.setStatus("ACTV"); - - clientCodeImdg.insert(existsClientCode); - - CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest(); - clientCodeDeleteRequest.setId(ID); - - Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data - - //ACT - String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID); - - addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString); - - //ASSERT - - waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); - ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID); - Assertions.assertNull(resultUpdate); - } +// existsClientCode.setMoneyAccountId(131L); +// existsClientCode.setDepoAccountId(132L); +// existsClientCode.setStatus("ACTV"); +// +// clientCodeImdg.insert(existsClientCode); +// +// CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest(); +// clientCodeDeleteRequest.setId(ID); +// +// Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data +// +// //ACT +// String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID); +// +// addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString); +// +// //ASSERT +// +// waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); +// ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID); +// Assertions.assertNull(resultUpdate); +// } } \ No newline at end of file From 864bbcf125a12fbd40bf9421b4cf1c9c09cca18f Mon Sep 17 00:00:00 2001 From: AKurakin Date: Thu, 4 May 2023 16:29:52 +0300 Subject: [PATCH 06/20] =?UTF-8?q?company-service=20http://jira.mfd.msk:808?= =?UTF-8?q?8/browse/CLS-272=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20BiDirectionQueueExchanger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/services/exchangers/BiDirectionQueueExchanger.java | 2 +- .../spcex/clearing/company/service/ClientCodeService.java | 6 +++--- .../clearing/company/service/ClientCodeServiceTest.java | 1 - .../clearing/platform/messaging/service/QueueConsumer.java | 1 + 4 files changed, 5 insertions(+), 5 deletions(-) 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 index c26f63b0c..b90b1993e 100644 --- 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 @@ -55,7 +55,7 @@ public class BiDirectionQueueExchanger> extends Queu /** * Синхронно-ассинхронный обмен сообщениями * - * @param kafkaQueue + * @param kafkaQueue уникальный kafka Consumer (Spring prototype). Нельзя переиспользовать существующие. * @param kafkaProducer * @param outQueue отправляет в очередь * @param inQueue слушает очередь/топик, ожидает ответов. Пример: Consts.CONTINUE_CLEARING diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java index 2e82f5e9b..a795a26db 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java @@ -70,7 +70,7 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean BiDirectionQueueExchanger> accountServiceExchanger; @Autowired - public ClientCodeService(Consumer kafkaQueue, + public ClientCodeService(Consumer kafkaQueue1, Consumer kafkaQueue2, Producer kafkaProducer, ImdgProvider imdgProvider, ValidationHelper validationHelper, @@ -79,7 +79,7 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean @Qualifier("clientCodeNewRequestValidator") Function clientCodeNewRequestValidator, @Qualifier("clientCodeUpdateRequestValidator") Function clientCodeUpdateRequestValidator, @Qualifier("clientCodeDeleteRequestValidator") Function clientCodeDeleteRequestValidator) { - super(kafkaQueue, kafkaProducer); + super(kafkaQueue1, kafkaProducer); this.kafkaProducer = kafkaProducer; this.idGenerator = imdgProvider.getImdgIdGenerator(); this.clientCodeMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class); @@ -92,7 +92,7 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean this.messageResolver = messageResolver; this.userRoleVerification = userRoleVerification; - this.accountServiceExchanger = new BiDirectionQueueExchanger<>(kafkaQueue, kafkaProducer, + this.accountServiceExchanger = new BiDirectionQueueExchanger<>(kafkaQueue2, kafkaProducer, Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW, Consts.REQUEST_INFO_UPDATE, true, // REQUEST_INFO_UPDATE - стандартная очередь, для результатов всех реквестов. DESTINATION_TRADING_CLEARING_REGISTRY_REPLY, 60000 diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java index 503174d22..0f34d0778 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java @@ -45,7 +45,6 @@ import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparato import static ru.spcex.clearing.test.TestUtils.*; import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId; -//todo тесты случайно ломаются из-за BiDirectionQueueExchanger. Когда там выключаю initReplyListener() то тесты стабильно работают. @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { ClientCodeService.class, 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 0b26d5c03..3f7afe713 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 @@ -74,6 +74,7 @@ public class QueueConsumer implements AutoCloseable { public void init() { inputExecutor.submit(() -> { try { + log.debug("Using kafka consumer {} for subscribe on \"{}\"", consumer, callbacks.keySet()); if (supportStartOffsetTimeWindow) { consumer.subscribe(callbacks.keySet(), new OffsetChanger(consumer, callbacks.keySet())); } else { From b6eb7a9d71b96b9ae9472e409e7584f671db35b3 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Thu, 4 May 2023 17:10:55 +0300 Subject: [PATCH 07/20] =?UTF-8?q?company-service=20http://jira.mfd.msk:808?= =?UTF-8?q?8/browse/CLS-272=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=20=D0=BA=20=D1=82?= =?UTF-8?q?=D0=B0=D1=81=D0=BA=D1=83=2027/=D0=B0=D0=BF=D1=80/23=2016:24?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClientCodeValidationConfig.java | 20 -------- .../company/service/ClientCodeService.java | 47 +++++++++---------- .../service/ClientCodeServiceTest.java | 4 +- 3 files changed, 24 insertions(+), 47 deletions(-) diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java index 653c6320d..c3b2776ae 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClientCodeValidationConfig.java @@ -68,16 +68,6 @@ public class ClientCodeValidationConfig { acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) ? null : CompanyErrors.AccountNotFound ), - IdPresentRule.instance("tradingClearingRegistryId", - ClientCodeNewRequest::getTradingClearingRegistryId, - IMDGDistributedNames.Map_TradingClearingRegistry, - TradingClearingRegistry.class, - CompanyErrors.RequiredFieldEmpty, - CompanyErrors.TradingClearingRegistryNotFound, - false, - acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) - ? null : CompanyErrors.TradingClearingRegistryNotFound - ), DictionaryPresentRule.instance("stauts", @@ -139,16 +129,6 @@ public class ClientCodeValidationConfig { acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) ? null : CompanyErrors.AccountNotFound ), - IdPresentRule.instance("tradingClearingRegistryId", - ClientCodeUpdateRequest::getTradingClearingRegistryId, - IMDGDistributedNames.Map_TradingClearingRegistry, - TradingClearingRegistry.class, - CompanyErrors.RequiredFieldEmpty, - CompanyErrors.TradingClearingRegistryNotFound, - false, - acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) - ? null : CompanyErrors.TradingClearingRegistryNotFound - ), DictionaryPresentRule.instance("stauts", ClientCodeUpdateRequest::getStatus, diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java index a795a26db..183e6da6d 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ClientCodeService.java @@ -147,14 +147,6 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean } } - if (req.getTradingClearingRegistryId() == null && req.getMoneyAccountId() != null) { - TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); - if (tradingClearingRegistry == null) { - return makeErrorResponse(userRequest, CompanyErrors.TradingClearingRegistryNotFound); - } else { - req.setTradingClearingRegistryId(tradingClearingRegistry.getId()); - } - } ClientCode newClientCode = buildClientCode(req); clientCodeMap.insert(newClientCode); log.debug("successfully processed, new clientCode id {}", newClientCode.getId()); @@ -188,14 +180,6 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean } } - if (req.getTradingClearingRegistryId() == null && req.getMoneyAccountId() != null) { - TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); - if (tradingClearingRegistry == null) { - return makeErrorResponse(userRequest, CompanyErrors.TradingClearingRegistryNotFound); - } else { - req.setTradingClearingRegistryId(tradingClearingRegistry.getId()); - } - } ClientCode newClientCode = buildClientCode(req); clientCodeMap.insert(newClientCode); log.debug("successfully processed, new clientCode id {}", newClientCode.getId()); @@ -233,14 +217,6 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean } } - if (req.getTradingClearingRegistryId() == null && req.getMoneyAccountId() != null) { - TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); - if (tradingClearingRegistry == null) { - return makeErrorResponse(userRequest, CompanyErrors.TradingClearingRegistryNotFound); - } else { - req.setTradingClearingRegistryId(tradingClearingRegistry.getId()); - } - } updateClientCode(clientCode, req); clientCodeMap.update(clientCode); @@ -392,7 +368,17 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean clientCode.setCompanyId(req.getCompanyId()); clientCode.setCode(req.getCode()); - clientCode.setTradingClearingRegistryId(req.getTradingClearingRegistryId()); + + if (req.getMoneyAccountId() != null) { + TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (tradingClearingRegistry == null) { + log.warn("TCR not found: CompanyId {}, MoneyAccountId {}, DepoAccountId {}", + req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + } else { + clientCode.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + } + } + clientCode.setMoneyAccountId(req.getMoneyAccountId()); clientCode.setDepoAccountId(req.getDepoAccountId()); clientCode.setStatus(req.getStatus()); @@ -405,6 +391,17 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean clientCode.setCompanyId(req.getCompanyId()); clientCode.setCode(req.getCode()); + + if (req.getMoneyAccountId() != null) { + TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + if (tradingClearingRegistry == null) { + log.warn("TCR not found: CompanyId {}, MoneyAccountId {}, DepoAccountId {}", + req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId()); + } else { + clientCode.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + } + } + clientCode.setTradingClearingRegistryId(req.getTradingClearingRegistryId()); clientCode.setMoneyAccountId(req.getMoneyAccountId()); clientCode.setDepoAccountId(req.getDepoAccountId()); diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java index 0f34d0778..2599a0ec9 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClientCodeServiceTest.java @@ -184,7 +184,7 @@ class ClientCodeServiceTest { predictableClientCode.setCompanyId(COMPANY_ID); // predictableClientCode.setMoneyAccountId(131L); // predictableClientCode.setDepoAccountId(132L); - predictableClientCode.setTradingClearingRegistryId(TCR_ID); +// predictableClientCode.setTradingClearingRegistryId(TCR_ID); //ACT String jsonString = getJsonStringForNew(clientCodeNewRequest, ID); @@ -222,7 +222,7 @@ class ClientCodeServiceTest { predictableClientCode.setCompanyId(COMPANY_ID); // predictableClientCode.setMoneyAccountId(131L); // predictableClientCode.setDepoAccountId(132L); - predictableClientCode.setTradingClearingRegistryId(TCR_ID); +// predictableClientCode.setTradingClearingRegistryId(TCR_ID); //ACT String jsonString = getJsonStringForNew(clientCodeNewRequest, ID); From a83f4f348fe870936bc999567792064f3c7cdcfc Mon Sep 17 00:00:00 2001 From: AKurakin Date: Thu, 4 May 2023 19:06:39 +0300 Subject: [PATCH 08/20] =?UTF-8?q?backend-api=20http://jira.mfd.msk:8088/br?= =?UTF-8?q?owse/CLS-273=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20swagger/json=20=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../registry/TradingClearingRegistryBackendGetFields.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/registry/TradingClearingRegistryBackendGetFields.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/registry/TradingClearingRegistryBackendGetFields.java index 60495a336..d4822d731 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/registry/TradingClearingRegistryBackendGetFields.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/registry/TradingClearingRegistryBackendGetFields.java @@ -36,10 +36,12 @@ public class TradingClearingRegistryBackendGetFields { @ApiModelProperty(value = "Наименование статуса", example = "ACTV") private String status; - @JsonProperty("Дата-время создания записи") + @JsonProperty + @ApiModelProperty(value = "Дата-время создания записи") @JsonSerialize(using = InstantSerializer.class) private Instant createdAt; - @JsonProperty("Дата-время изменения записи") + @JsonProperty + @ApiModelProperty(value = "Дата-время изменения записи") @JsonSerialize(using = InstantSerializer.class) private Instant updatedAt; From cdd6a0996fc12d1b88d41a1e5c9a9992b7825bab Mon Sep 17 00:00:00 2001 From: AKurakin Date: Fri, 5 May 2023 11:57:49 +0300 Subject: [PATCH 09/20] =?UTF-8?q?QueueConsumer=20=D1=83=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D1=88=D0=B8=D0=BB=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA?= =?UTF-8?q?.=20IMDGMessageResolver=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BD=D0=B0=D0=B4=D1=91=D0=B6=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D0=BF=D1=80=D0=B8=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D0=B0=D1=85=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BE=D1=88=D0=B8=D0=B1?= =?UTF-8?q?=D0=BE=D0=BA.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/services/IMDGMessageResolver.java | 17 +++++++++++------ .../messaging/service/QueueConsumer.java | 5 ++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/IMDGMessageResolver.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/IMDGMessageResolver.java index 97dfbf8cf..3d64121d6 100644 --- a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/IMDGMessageResolver.java +++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/IMDGMessageResolver.java @@ -1,5 +1,6 @@ package ru.spcex.clearing.util.services; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.clearing.platform.dictionary.ErrorCodeDictionary; @@ -25,13 +26,17 @@ public class IMDGMessageResolver implements IMessageResolver { @Override public String resolve(EnumMessage errorMessage) { if (errorMessage == null) return "null"; - - ErrorCodeDictionary errorDictionary = errorCodeDictionaryIMDG.getSingleObjectByID(errorMessage.getSubject().getId()); - if (errorDictionary == null) { - log.warn("ERROR_CODE_DICTIONARY not found fo id={}", errorMessage.getSubject().getId()); + try { + ErrorCodeDictionary errorDictionary = errorCodeDictionaryIMDG.getSingleObjectByID(errorMessage.getSubject().getId()); + if (errorDictionary == null) { + log.warn("ERROR_CODE_DICTIONARY not found fo id={}", errorMessage.getSubject().getId()); + return String.format("(%d) args %s", errorMessage.getSubject().getId(), Arrays.toString(errorMessage.getArgs())); + } + String textTemplate = errorDictionary.getName(); + return String.format(textTemplate, errorMessage.getArgs()); + } catch (Exception errFormatting) { // MissingFormatArgumentException + log.warn("Error in message resolver for error {}: {}", errorMessage.getSubject(), ExceptionUtils.getStackTrace(errFormatting)); return String.format("(%d) args %s", errorMessage.getSubject().getId(), Arrays.toString(errorMessage.getArgs())); } - String textTemplate = errorDictionary.getName(); - return String.format(textTemplate, errorMessage.getArgs()); } } 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 3f7afe713..380250d37 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 @@ -83,9 +83,11 @@ public class QueueConsumer implements AutoCloseable { Object o = null; int lastErrors = 0; while (!closed.get()) { + String lastTopic = null; try { ConsumerRecords records = consumer.poll(Duration.of(10, ChronoUnit.SECONDS)); for (ConsumerRecord next : records) { + lastTopic = next.topic(); ConsumerSpecificClass callback = callbacks.get(next.topic()); Class clazz = callback.getClazz(); JavaType payloadType = json.getTypeFactory().constructParametricType(BaseRequest.class, clazz); @@ -99,7 +101,8 @@ public class QueueConsumer implements AutoCloseable { } lastErrors = 0; } catch (Throwable e) { - log.error(ExceptionUtils.getStackTrace(e)); + log.error("Listener {} last topic \"{}\", error: {}", + QueueConsumer.this.getClass().getName(), lastTopic, ExceptionUtils.getStackTrace(e)); if (producer != null && o != null) { sendErrorResponse((BaseRequest) o); } From 1b98981c9f2977513af0682906f31d5774909ab7 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Fri, 5 May 2023 12:48:07 +0300 Subject: [PATCH 10/20] =?UTF-8?q?company-service=20http://jira.mfd.msk:808?= =?UTF-8?q?8/browse/CLS-259=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ContactValidationConfig.java | 2 +- .../ProfileDocumentValidationConfig.java | 12 ++++- .../company/service/CompanyInfoService.java | 47 +++++++++++++++++-- .../service/ProfileDocumentService.java | 6 ++- .../service/CompanySymbolServiceTest.java | 9 ++++ 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ContactValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ContactValidationConfig.java index f92635d78..a69e7731c 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ContactValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ContactValidationConfig.java @@ -73,7 +73,7 @@ public class ContactValidationConfig { IMDGDistributedNames.Map_Contact, Contact.class, CompanyErrors.RequiredFieldEmpty, - CompanyErrors.CompanyNotFound, + CompanyErrors.ContactNotFound, contact -> { if (contactUpdateRequest.getContactType() == null) return null; if (!contactUpdateRequest.getContactType().equalsIgnoreCase(contact.getContactType())) { diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java index 9fe82a927..5449f8f9e 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java @@ -44,7 +44,7 @@ public class ProfileDocumentValidationConfig { Company.class, CompanyErrors.RequiredFieldEmpty, CompanyErrors.CompanyNotFound, - company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled), + company -> WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled), DictionaryPresentRule.instance("documentType", ProfileDocumentNewRequest::getDocumentType, IMDGDistributedNames.Map_DocumentTypeDictionary, @@ -138,7 +138,15 @@ public class ProfileDocumentValidationConfig { IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class, CompanyErrors.RequiredFieldEmpty, - CompanyErrors.RecordNotFound) + CompanyErrors.RecordNotFound, + profileDoc -> { + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + Company company = companyImdg.getSingleObjectByID(profileDoc.getCompanyId()); + if (company == null) { + return CompanyErrors.CompanyNotFound; + } + return null; + }) ); }; } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java index 7dd8ba584..0beb21c0a 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java @@ -22,14 +22,18 @@ import ru.spcex.clearing.util.security.UserRoleVerification; import ru.spcex.clearing.validation.common.ValidationHelper; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.api.ImdgTransaction; +import ru.spcex.platform.utils.error.ValidationException; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; +import java.util.Objects; import java.util.function.Function; @Service public class CompanyInfoService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); + private final ImdgProvider imdgProvider; private final Imdg companyMap; protected final CompanyService companyService; private final RequestHelper requestHelper; @@ -46,6 +50,7 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea Function companyInfoUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.companyService = companyService; + this.imdgProvider = imdgProvider; this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); this.validationHelper = validationHelper; this.userRoleVerification = userRoleVerification; @@ -56,16 +61,16 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea @Override public void afterPropertiesSet() { callback(CompanyInfoUpdateRequest.class) - .setFunction(this::companyInfoUpdate) + .setFunction(request -> requestHelper.requestFunction(this::companyInfoUpdate, request)) .forDestination(Consts.DESTINATION_COMPANY_INFO_UPDATE, callbacks::put); callback(CompanyInfoUpdateRequest.class) - .setFunction(this::companyInfoUpdate) + .setFunction(request -> requestHelper.requestFunction(this::companyInfoUpdate, request)) .forDestination(Consts.DESTINATION_COMPANY_INFO_NEW, callbacks::put); // логика заполнения одинакова с companyInfoUpdate init(); } - public RequestInfoUpdate companyInfoUpdate(BaseRequest companyInfoReq) { + public RequestInfoUpdate companyInfoUpdate(BaseRequest companyInfoReq) throws ValidationException { CompanyInfoUpdateRequest req = companyInfoReq.getRequestPayload(); log.debug("{} received", req.getClass().getSimpleName()); { // Валидация, ValidationException @@ -81,6 +86,7 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea log.trace("Company {} not found", req.getId()); return requestHelper.makeErrorResponse(companyInfoReq, CompanyErrors.CompanyNotFound, companyInfoReq.getId()); } + company.setUpdated(Instant.now()); CompanyInfo companyInfo = company.getProfile(); companyInfo.setCorporationSoleType(req.getCorporationSoleType()); @@ -93,8 +99,39 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea companyInfo.setShortNameEng(req.getShortNameEng()); companyInfo.setFullNameEng(req.getFullNameEng()); - company.setUpdated(Instant.now()); - companyMap.update(company); + company.setShortName(req.getShortName()); + company.setFullName(req.getFullName()); + boolean simpleUpdate = true; + if (req.getWorkflowStatus() != null) { + String prevStatus = company.getWorkflowStatus(); + company.setWorkflowStatus(req.getWorkflowStatus()); + if (!Objects.equals(prevStatus, company.getWorkflowStatus())) { + simpleUpdate = false; + ImdgTransaction transaction = imdgProvider.newTransaction(); + transaction.beginTransaction(); + boolean txOk = false; + try { + companyService.relationHelper.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus()); + Imdg txCompanyMap = transaction.getImdg(IMDGDistributedNames.Map_Company, Company.class); + txCompanyMap.update(company); + log.trace("Company {} updated", company.getId()); + txOk = true; + } finally { + if (txOk) + transaction.commitTransaction(); + else + transaction.rollbackTransaction(); + } + } else { + log.trace("Status was not changed"); + } + } else { + log.trace("Null new WorkflowStatus"); + } + if (simpleUpdate) { + companyMap.update(company); + log.trace("Company {} updated", company.getId()); + } log.debug("successfully CompanyInfo processed, id {}", companyInfo.getId()); } return null; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java index 411cfd669..adf51b4ed 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java @@ -174,8 +174,10 @@ public class ProfileDocumentService extends QueueConsumer implements Initializin ProfileDocument profileDocument = profileDocumentMap.getSingleObjectByID(profileDocumentUpdateRequest.getId()); String prevDocType = profileDocument.getDocumentType(); - if (profileDocumentUpdateRequest.getCompanyId() != null) - profileDocument.setCompanyId(profileDocumentUpdateRequest.getCompanyId()); + if (profileDocumentUpdateRequest.getCompanyId() != null && !profileDocumentUpdateRequest.getCompanyId().equals(profileDocument.getCompanyId())) { + log.warn("profileDocumentUpdateRequest[{}] CompanyId {} not match", profileDocumentUpdateRequest.getId(), profileDocumentUpdateRequest.getCompanyId()); + return requestHelper.makeErrorResponse(profileDocumentUpdateRequestBaseRequest, CompanyErrors.WrongFieldValue, "companyId"); + } if (profileDocumentUpdateRequest.getDocumentType() != null) profileDocument.setDocumentType(profileDocumentUpdateRequest.getDocumentType()); diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java index e247fb26a..98383d456 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java @@ -12,6 +12,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.CompanySymbols; import ru.clearing.platform.dictionary.CompanySymbolDictionary; import ru.spcex.clearing.company.config.BeanConfiguration; @@ -92,6 +93,14 @@ class CompanySymbolServiceTest { cioSymbol.setName(CompanySymbol.CIO.getKey()); companySymbolDictionaryImdg.insert(cioSymbol); } + Imdg companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + { + Company company = new Company(); + company.setId(ID); + company.setShortName("TST"); + company.setWorkflowStatus("ACTV"); + companyImdg.insert(company); + } TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class); From 5938786f842f37c56577c81e16ac6696992267c2 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Fri, 5 May 2023 14:30:08 +0300 Subject: [PATCH 11/20] =?UTF-8?q?backend-api=20=D0=BF=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BF=D0=BE=D0=BB=D1=8F=20=D0=B2=20?= =?UTF-8?q?CompanyInfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../queue/company/CompanyInfoController.java | 14 +- .../company/CompanyInfoBackendGetAll.java | 48 ++++ .../company/CompanyInfoBackendGetFields.java | 224 ++++++++++++++++++ 3 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetAll.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetFields.java diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/company/CompanyInfoController.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/company/CompanyInfoController.java index 6ac88b427..02ef05d01 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/company/CompanyInfoController.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/company/CompanyInfoController.java @@ -14,6 +14,7 @@ import ru.spcex.clearing.backendapi.controller.request.cud.company.CompanyInfoUp import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse; import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse; import ru.spcex.clearing.backendapi.controller.response.entity.CommonGetAllResponse; +import ru.spcex.clearing.backendapi.controller.response.entity.company.CompanyInfoBackendGetAll; import ru.spcex.clearing.backendapi.meta.GetResponseFactory; import ru.spcex.clearing.backendapi.service.IOperator; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -53,19 +54,14 @@ public class CompanyInfoController extends AbstractQueueController { } @ApiOperation(value = "get all CompanyInfo's.") - @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CommonGetAllResponse.class)}) + @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CompanyInfoBackendGetAll.class)}) @RequestMapping(method = RequestMethod.GET) @ResponseBody - public CommonGetAllResponse getAll() { + public CompanyInfoBackendGetAll getAll() { Collection> all = new ArrayList<>(); Collection companies = companyImdg.getAllValues(); - for (Company company : companies) { - if (company.getProfile() != null && company.getProfile().getId() != null) { // пока возвращает "пустой" CompanyInfo если его нет для Company - all.add(responseFactory.responseFromObject(company.getProfile())); - } - } - CommonGetAllResponse response = new CommonGetAllResponse(); - response.fromEntity(all); + CompanyInfoBackendGetAll response = new CompanyInfoBackendGetAll(); + response.fromEntity(companies); return response; } } diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetAll.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetAll.java new file mode 100644 index 000000000..e134eb83a --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetAll.java @@ -0,0 +1,48 @@ +package ru.spcex.clearing.backendapi.controller.response.entity.company; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import ru.clearing.classes.statics.data.company.Company; +import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@ApiModel(description = "Ответ при получении объектов CompanyInfos.") +public class CompanyInfoBackendGetAll extends BasicSpcexResponse { + + @JsonProperty + @ApiModelProperty(value = "Полезная нагрузка") + private CompanyInfoBackendPayload payload = new CompanyInfoBackendPayload(); + + private static class CompanyInfoBackendPayload { + private List items = new ArrayList<>(); + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + } + + public CompanyInfoBackendPayload getPayload() { + return payload; + } + + public void setPayload(CompanyInfoBackendPayload payload) { + this.payload = payload; + } + + public void fromEntity(Collection companys) { + var payload = this.getPayload(); + for (var company : companys) { + var singleItem = CompanyInfoBackendGetFields.fromEntity(company); + payload.getItems().add(singleItem); + } + } + +} \ No newline at end of file diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetFields.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetFields.java new file mode 100644 index 000000000..4e039a019 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/company/CompanyInfoBackendGetFields.java @@ -0,0 +1,224 @@ +package ru.spcex.clearing.backendapi.controller.response.entity.company; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.profile.CompanyInfo; + +public class CompanyInfoBackendGetFields { + @JsonProperty + @ApiModelProperty(value = "Идентификатор записи") + private Long id; + @JsonProperty + @ApiModelProperty(value = "Идентификатор компании") + private Long companyId; + @JsonProperty + @ApiModelProperty(value = "Код единоличного исполнительного органа") + private String corporationSoleType; + @JsonProperty + @ApiModelProperty(value = "Код юрисдикции") + private String countryCode; + @JsonProperty + @ApiModelProperty(value = "Описание компании") + private String description; + @JsonProperty + @ApiModelProperty(value = "Код признака профессионального участника") + private String professionalSign; + @JsonProperty + @ApiModelProperty(value = "Код вида субъекта") + private String legalKind; + @JsonProperty + @ApiModelProperty(value = "Код типа организации") + private String organizationType; + @JsonProperty + @ApiModelProperty(value = "Код резиденции") + private String residence; + @JsonProperty + @ApiModelProperty(value = "Краткое наименование компании") + private String shortName; + @JsonProperty + @ApiModelProperty(value = "Полное наименование компании") + private String fullName; + @JsonProperty + @ApiModelProperty(value = "Краткое наименование компании на английском") + private String shortNameEng; + @JsonProperty + @ApiModelProperty(value = "Краткое наименование компании на английском") + private String fullNameEng; + @JsonProperty + @ApiModelProperty(value = "Код участника торгов") + private String tradingCode; + @JsonProperty + @ApiModelProperty(value = "Код участника клиринга") + private String clearingCode; + @JsonProperty + @ApiModelProperty(value = "Регистрационный код участника") + private String registrationCode; + @JsonProperty + @ApiModelProperty(value = "Наименование статуса") + private String workflowStatus; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getCompanyId() { + return companyId; + } + + public void setCompanyId(Long companyId) { + this.companyId = companyId; + } + + public String getCorporationSoleType() { + return corporationSoleType; + } + + public void setCorporationSoleType(String corporationSoleType) { + this.corporationSoleType = corporationSoleType; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getProfessionalSign() { + return professionalSign; + } + + public void setProfessionalSign(String professionalSign) { + this.professionalSign = professionalSign; + } + + public String getLegalKind() { + return legalKind; + } + + public void setLegalKind(String legalKind) { + this.legalKind = legalKind; + } + + public String getOrganizationType() { + return organizationType; + } + + public void setOrganizationType(String organizationType) { + this.organizationType = organizationType; + } + + public String getResidence() { + return residence; + } + + public void setResidence(String residence) { + this.residence = residence; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getShortNameEng() { + return shortNameEng; + } + + public void setShortNameEng(String shortNameEng) { + this.shortNameEng = shortNameEng; + } + + public String getFullNameEng() { + return fullNameEng; + } + + public void setFullNameEng(String fullNameEng) { + this.fullNameEng = fullNameEng; + } + + public String getTradingCode() { + return tradingCode; + } + + public void setTradingCode(String tradingCode) { + this.tradingCode = tradingCode; + } + + public String getClearingCode() { + return clearingCode; + } + + public void setClearingCode(String clearingCode) { + this.clearingCode = clearingCode; + } + + public String getRegistrationCode() { + return registrationCode; + } + + public void setRegistrationCode(String registrationCode) { + this.registrationCode = registrationCode; + } + + public String getWorkflowStatus() { + return workflowStatus; + } + + public void setWorkflowStatus(String workflowStatus) { + this.workflowStatus = workflowStatus; + } + + public static CompanyInfoBackendGetFields fromEntity(Company company) { + if (company == null || company.getProfile() == null) { + return null; + } + CompanyInfo info = company.getProfile(); + CompanyInfoBackendGetFields fields = new CompanyInfoBackendGetFields(); + fields.setId(info.getId()); + fields.setCompanyId(info.getCompanyId()); + fields.setCorporationSoleType(info.getCorporationSoleType()); + fields.setCountryCode(info.getCountryCode()); + fields.setDescription(info.getDescription()); + fields.setProfessionalSign(info.getProfessionalSign()); + fields.setLegalKind(info.getLegalKind()); + fields.setOrganizationType(info.getOrganizationType()); + fields.setResidence(info.getResidence()); + fields.setShortNameEng(info.getShortNameEng()); + fields.setFullNameEng(info.getFullNameEng()); + + fields.setShortName(company.getShortName()); + fields.setFullName(company.getFullName()); + fields.setTradingCode(company.getTradingCode()); + fields.setClearingCode(company.getClearingCode()); + fields.setRegistrationCode(company.getRegistrationCode()); + fields.setWorkflowStatus(company.getWorkflowStatus()); + + return fields; + } +} From 2829e50e7e003e492e4473dcbd65639e7251cc07 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Fri, 5 May 2023 14:36:33 +0300 Subject: [PATCH 12/20] =?UTF-8?q?company-service=20http://jira.mfd.msk:808?= =?UTF-8?q?8/browse/CLS-284=20=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20(?= =?UTF-8?q?=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0=D1=82=D1=8C!)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../company/service/CompanyInfoService.java | 2 +- .../company/service/CompanyService.java | 26 ++++++------ ...lationHelper.java => RelationService.java} | 40 ++++++++++++++++++- .../service/CompanyInfoServiceTest.java | 2 +- .../company/service/CompanyServiceTest.java | 2 +- .../service/CompanySymbolServiceTest.java | 2 +- 6 files changed, 54 insertions(+), 20 deletions(-) rename clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/{RelationHelper.java => RelationService.java} (66%) diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java index 0beb21c0a..03d355d49 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java @@ -111,7 +111,7 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea transaction.beginTransaction(); boolean txOk = false; try { - companyService.relationHelper.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus()); + companyService.relationService.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus()); Imdg txCompanyMap = transaction.getImdg(IMDGDistributedNames.Map_Company, Company.class); txCompanyMap.update(company); log.trace("Company {} updated", company.getId()); diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java index 3444b1243..542916892 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java @@ -29,13 +29,11 @@ import ru.spcex.platform.imdg.api.ImdgId; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.ImdgTransaction; import ru.spcex.platform.utils.enumeration.EnumMessage; -import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.error.ClearingBaseException; import ru.spcex.platform.utils.error.ValidationException; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.Map; import java.util.Objects; import java.util.function.Function; @@ -56,7 +54,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean { protected CompanySymbolService companySymbolService; protected AccountNotificationHelper accountNotification; - protected RelationHelper relationHelper; + protected RelationService relationService; @Autowired public CompanyService(Consumer kafkaQueue, Producer kafkaProducer, @@ -73,7 +71,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean { CompanySymbolService companySymbolService, AccountNotificationHelper accountNotification, - RelationHelper relationHelper + RelationService relationService ) { super(kafkaQueue, kafkaProducer); this.imdgProvider = imdgProvider; @@ -89,7 +87,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean { this.companySymbolService = companySymbolService; companySymbolService.setCompanyService(this); this.accountNotification = accountNotification; - this.relationHelper = relationHelper; + this.relationService = relationService; companyIMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); } @@ -145,9 +143,9 @@ public class CompanyService extends QueueConsumer implements InitializingBean { companyMap.insert(company); log.debug("company-new request processed, BaseRequest.id = {}, company.id={}", companyNewRequestBaseRequest.getId(), company.getId()); - relationHelper.createNewRelation(transaction, company); + relationService.createNewRelation(transaction, company); if (!(WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()))) { // Block - relationHelper.onChangeWorkflowStatus(transaction, company, null, company.getWorkflowStatus()); + relationService.onChangeWorkflowStatus(transaction, company, null, company.getWorkflowStatus()); } txOk = true; } finally { @@ -180,10 +178,10 @@ public class CompanyService extends QueueConsumer implements InitializingBean { log.trace("Company {} not found", updateRequest.getId()); return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyNotFound, updateRequest.getId()); } - if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) { - log.trace("Company {} not active: {}", company.getId(), company.getWorkflowStatus()); - return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyDisabled, updateRequest.getId()); - } +// if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) { +// log.trace("Company {} not active: {}", company.getId(), company.getWorkflowStatus()); +// return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyDisabled, updateRequest.getId()); +// } company.setUpdated(Instant.now()); company.setShortName(updateRequest.getShortName()); @@ -199,7 +197,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean { if (updateRequest.getWorkflowStatus() != null) { company.setWorkflowStatus(updateRequest.getWorkflowStatus()); if (!Objects.equals(prevStatus, company.getWorkflowStatus())) { - relationHelper.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus()); + relationService.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus()); } else { log.trace("Status was not changed"); } @@ -286,7 +284,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean { String prevStatus = company.getWorkflowStatus(); company.setWorkflowStatus(WorkflowStatus.Blocked.getKey()); - relationHelper.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus()); + relationService.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus()); log.debug("Update company.id={}", company.getId()); companyMap.update(company); @@ -339,7 +337,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean { company.setWorkflowStatus(WorkflowStatus.Blocked.getKey()); - relationHelper.onChangeWorkflowStatusOnlyRelationChange(transaction, company, company.getWorkflowStatus()); + relationService.onChangeWorkflowStatusOnlyRelationChange(transaction, company, company.getWorkflowStatus()); log.debug("Update company.id={}", company.getId()); companyMap.update(company); diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationHelper.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java similarity index 66% rename from clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationHelper.java rename to clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java index c68595767..ca0c4349f 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationHelper.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java @@ -1,17 +1,27 @@ package ru.spcex.clearing.company.service; +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.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.relation.Relation; +import ru.clearing.classes.statics.data.profile.ProfileDocument; import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentUpdateRequest; +import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.platform.enumeration.ServiceProduct; import ru.spcex.platform.enumeration.ServiceStatus; import ru.spcex.platform.enumeration.WorkflowStatus; import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.ImdgTransaction; import ru.spcex.platform.utils.error.ValidationException; @@ -20,15 +30,41 @@ import java.util.Collection; import java.util.Objects; @Service -public class RelationHelper { +public class RelationService extends QueueConsumer implements InitializingBean { protected static final Long SPVB_ID = 1L; // СПВБ protected final Logger log = LoggerFactory.getLogger(getClass()); + protected ImdgProvider imdgProvider; protected AccountNotificationHelper accountNotification; @Autowired - public RelationHelper(AccountNotificationHelper accountNotification) { + public RelationService(Consumer kafkaQueue, + Producer kafkaProducer, + ImdgProvider imdgProvider, + + AccountNotificationHelper accountNotification) { + super(kafkaQueue, kafkaProducer); + this.imdgProvider = imdgProvider; this.accountNotification = accountNotification; + +// this.requestHelper = requestHelper.setLogger(log); + } + + @Override + public void afterPropertiesSet() { +// this.profileDocumentMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class); +// this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); +//todo all CLS-284 +// callback(ProfileDocumentNewRequest.class) +// .setFunction(this::profileDocumentNew) +// .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_NEW, callbacks::put); +// callback(ProfileDocumentUpdateRequest.class) +// .setFunction(this::profileDocumentUpdate) +// .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_UPDATE, callbacks::put); +// callback(CommonDeleteRequest.class) +// .setFunction(this::profileDocumentDelete) +// .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_DELETE, callbacks::put); +// init(); } protected void createNewRelation(ImdgTransaction transaction, Company company) { diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java index d823d4ab6..b521fd7e4 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java @@ -50,7 +50,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv ValidationConfig.class, CompanySymbolService.class, AccountNotificationHelper.class, - RelationHelper.class, + RelationService.class, BeanConfiguration.class, KafkaTestConfig.class, diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java index b80446af5..f18f68a84 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java @@ -54,7 +54,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv ValidationConfig.class, CompanySymbolService.class, AccountNotificationHelper.class, - RelationHelper.class, + RelationService.class, CompanySymbolService.class, CompanySymbolValidationConfig.class, diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java index 98383d456..39e77828d 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java @@ -50,7 +50,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv CompanyService.class, CompanyValidationConfig.class, AccountNotificationHelper.class, - RelationHelper.class, + RelationService.class, KafkaTestConfig.class, ImdgTestConfig.class}) From c5b80bd3c98c63c8592060232d4f273fd3565cf3 Mon Sep 17 00:00:00 2001 From: psemenkov Date: Fri, 5 May 2023 15:21:22 +0300 Subject: [PATCH 13/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-276?= =?UTF-8?q?=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=B5=20=D0=B2=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/cud/utilities/STradesImportedRequest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/utilities/STradesImportedRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/utilities/STradesImportedRequest.java index 348527aae..30383c910 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/utilities/STradesImportedRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/utilities/STradesImportedRequest.java @@ -1,4 +1,16 @@ package ru.spcex.clearing.platform.messaging.domain.cud.utilities; +import com.fasterxml.jackson.annotation.JsonProperty; + public class STradesImportedRequest { + @JsonProperty + private Long tradeNum; + + public Long getTradeNum() { + return tradeNum; + } + + public void setTradeNum(Long tradeNum) { + this.tradeNum = tradeNum; + } } From 8238757ca81ce454e23249291ebd58f67fbc29dc Mon Sep 17 00:00:00 2001 From: AKurakin Date: Fri, 5 May 2023 15:33:46 +0300 Subject: [PATCH 14/20] =?UTF-8?q?meta=20http://jira.mfd.msk:8088/browse/CL?= =?UTF-8?q?S-293=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D0=BB=20DATA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend-api/src/main/resources/meta/data.xml | 4 ++-- .../db-scripts/src/main/resources/db/DATA.sql | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clearing-parent/backend-api/src/main/resources/meta/data.xml b/clearing-parent/backend-api/src/main/resources/meta/data.xml index f3efd0b8d..e6c737fd9 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/data.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/data.xml @@ -80,7 +80,7 @@ - + @@ -198,7 +198,7 @@ - + diff --git a/clearing-parent/db-scripts/src/main/resources/db/DATA.sql b/clearing-parent/db-scripts/src/main/resources/db/DATA.sql index 20a64eaaa..63716ecd2 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/DATA.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/DATA.sql @@ -1,4 +1,4 @@ --- DB version: 3.5.0.20 +-- DB version: 3.5.0.21 -- DATA version: 3.5.0.4 /* Dictionaries */ @@ -160,7 +160,7 @@ INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (17, 'RG INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (18, 'UUID', 'Идентификатор во внешней системе', 'Внешний идентификатор') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME; -INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (19, 'RDPZ', 'Требуется получение документа о подтверждении открытия депозитного счета', 'Подтверждение депозитного счета') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME; +INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (19, 'LICM', 'Лицензия на управление инвестиционными фондами, паевыми инвестиционными фондами, негосударственными пенсионными фондами', 'Лицензия на управление фондами') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME; INSERT INTO COMPANY_ROLE_DICTIONARY(ID, CODE, NAME) values (1, 'RPRT', 'Отчетная организация') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; @@ -394,7 +394,7 @@ INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (12, 'CMBA', 'Формиро INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (14, 'GCMR', 'Формирование реестра участников клиринга') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; -INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (15, 'GBRR', 'Формирование реестра остатков денежных средств ') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; +INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (15, 'GBRR', 'Формирование реестра остатков денежных средств') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (16, 'GORR', 'Формирование реестра распоряжений, направленных расчетной организации') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; @@ -414,9 +414,9 @@ INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (36, 'SPRC', 'Запуск п INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (37, 'SPOC', 'Запуск постклиринга') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; -INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (38, 'LIMM', 'Выгрузка в торговую систему остатков секции МКР') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; +INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (38, 'LIMM', 'Выгрузка в торговую систему остатков по деньгам') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; -INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (39, 'LIMF', 'Выгрузка в торговую систему остатков Фондовой секции') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; +INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (39, 'LIMS', 'Выгрузка в торговую систему остатков по бумагам') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (40, 'LIQU', 'Ликвидационная сессия по обязательтсвам участника') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; From a37fea506195002d72a9cd049178ee4f91005aa7 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Fri, 5 May 2023 20:17:35 +0300 Subject: [PATCH 15/20] =?UTF-8?q?company-service=20http://jira.mfd.msk:808?= =?UTF-8?q?8/browse/CLS-284=20=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB=20=D0=BA=D1=80=D0=BE=D0=BC=D0=B5=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=BE=D0=B9=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/RelationValidationConfig.java | 134 +++++++++++ .../config/validation/ValidationConfig.java | 2 + .../clearing/company/error/CompanyErrors.java | 1 + .../company/service/RelationService.java | 206 +++++++++++++++-- .../company/service/RelationServiceTest.java | 214 ++++++++++++++++++ .../platform/messaging/domain/Consts.java | 2 + .../cud/company/RelationNewRequest.java | 46 ++++ 7 files changed, 588 insertions(+), 17 deletions(-) create mode 100644 clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/RelationValidationConfig.java create mode 100644 clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/RelationServiceTest.java create mode 100644 platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/RelationNewRequest.java diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/RelationValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/RelationValidationConfig.java new file mode 100644 index 000000000..959f62491 --- /dev/null +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/RelationValidationConfig.java @@ -0,0 +1,134 @@ +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.company.relation.Relation; +import ru.clearing.platform.dictionary.ClearingCategoryDictionary; +import ru.clearing.platform.dictionary.WorkflowStatusDictionary; +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.RelationNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.RelationUpdateRequest; +import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule; +import ru.spcex.clearing.validation.common.rules.IdPresentRule; +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.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +@Configuration +public class RelationValidationConfig { + + @Bean("relationNewRequestValidation") + public Function relationNewRequestValidator( + Map> imdgForValidation + ) { + return relationNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(relationNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_ClearingCategoryDictionary); + addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary); + return new ValidatorImpl<>(context, + IdPresentRule.instance("companyId", + RelationNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.CompanyNotFound), + DictionaryPresentRule.instance("documentType", + RelationNewRequest::getClearingMemberCategory, + IMDGDistributedNames.Map_ClearingCategoryDictionary, + ClearingCategoryDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue), + DictionaryPresentRule.instance("serviceStatus", + RelationNewRequest::getServiceStatus, + IMDGDistributedNames.Map_WorkflowStatusDictionary, + WorkflowStatusDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue) + ); + }; + } + + @Bean("relationUpdateRequestValidation") + public Function relationUpdateRequestValidator( + Map> imdgForValidation + ) { + return relationUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(relationUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Relation); + addImdg.accept(IMDGDistributedNames.Map_Company); +// addImdg.accept(IMDGDistributedNames.Map_ClearingCategoryDictionary); + addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + RelationUpdateRequest::getId, + IMDGDistributedNames.Map_Relation, + Relation.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.RelationNotFound, + relation -> { + if (relation.getConsumerId() == null) return null; + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + Company company = companyImdg.getSingleObjectByID(relation.getConsumerId()); + if (company == null) { + return CompanyErrors.CompanyNotFound; + } else { + return null; + } + }), +// IdPresentRule.instance("companyId", +// RelationUpdateRequest::getCompanyId, +// IMDGDistributedNames.Map_Company, +// Company.class, +// CompanyErrors.RequiredFieldEmpty, +// CompanyErrors.CompanyNotFound), +// DictionaryPresentRule.instance("documentType", +// RelationUpdateRequest::getClearingMemberCategory, +// IMDGDistributedNames.Map_ClearingCategoryDictionary, +// ClearingCategoryDictionary.class, +// CompanyErrors.RequiredFieldEmpty, +// CompanyErrors.WrongFieldValue), + DictionaryPresentRule.instance("serviceStatus", + RelationUpdateRequest::getServiceStatus, + IMDGDistributedNames.Map_WorkflowStatusDictionary, + WorkflowStatusDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue) + ); + }; + } + + @Bean("relationDeleteRequestValidation") + public Function relationDeleteRequestValidator( + Map> imdgForValidation + ) { + return relationDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(relationDeleteRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Relation); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_Relation, + Relation.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.RelationNotFound + ) + ); + }; + } +} 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 index cd6671cf1..c586e2fd7 100644 --- 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 @@ -7,6 +7,7 @@ import ru.clearing.classes.statics.data.account.ClientCode; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.CompanySymbols; import ru.clearing.classes.statics.data.company.ClearingMemberCategory; +import ru.clearing.classes.statics.data.company.relation.Relation; import ru.clearing.classes.statics.data.profile.Contact; import ru.clearing.classes.statics.data.profile.ProfileDocument; import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; @@ -37,6 +38,7 @@ public class ValidationConfig { addImdg.accept(IMDGDistributedNames.Map_DocumentTypeDictionary, DocumentTypeDictionary.class); addImdg.accept(IMDGDistributedNames.Map_ContactTypeDictionary, ContactTypeDictionary.class); addImdg.accept(IMDGDistributedNames.Map_Contact, Contact.class); + addImdg.accept(IMDGDistributedNames.Map_Relation, Relation.class); addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary, WorkflowStatusDictionary.class); addImdg.accept(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); 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 3979ab8b9..a7e4b232d 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 @@ -25,6 +25,7 @@ public enum CompanyErrors implements IErrorEnumId { EditContactType(3021L), // Тип контакта компании %s не может быть изменен. TradingClearingRegistryNotFound(3022L), // ТКР с %s не найден AccountNotFound(3023L), // Счет %s не найден + RelationNotFound(3026L), // Запись о договорных отношениях не найдена ; private final Long id; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java index ca0c4349f..882abff8c 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java @@ -6,28 +6,35 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.relation.Relation; -import ru.clearing.classes.statics.data.profile.ProfileDocument; import ru.spcex.clearing.company.error.CompanyErrors; +import ru.spcex.clearing.company.util.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentNewRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentUpdateRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.*; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.util.security.UserRoleVerification; +import ru.spcex.clearing.validation.common.ValidationHelper; import ru.spcex.platform.enumeration.ServiceProduct; import ru.spcex.platform.enumeration.ServiceStatus; import ru.spcex.platform.enumeration.WorkflowStatus; import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgId; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.ImdgTransaction; import ru.spcex.platform.utils.error.ValidationException; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; import java.util.Collection; import java.util.Objects; +import java.util.function.Function; @Service public class RelationService extends QueueConsumer implements InitializingBean { @@ -35,38 +42,203 @@ public class RelationService extends QueueConsumer implements InitializingBean { protected final Logger log = LoggerFactory.getLogger(getClass()); protected ImdgProvider imdgProvider; + protected ImdgId idSequence; + protected Imdg relationMap; + protected Imdg companyMap; protected AccountNotificationHelper accountNotification; + protected UserRoleVerification userRoleVerification; + protected RequestHelper requestHelper; + + protected ValidationHelper validationHelper; + private Function relationNewRequestValidator; + private Function relationUpdateRequestValidator; + private Function relationDeleteRequestValidator; @Autowired public RelationService(Consumer kafkaQueue, Producer kafkaProducer, ImdgProvider imdgProvider, + RequestHelper requestHelper, + + UserRoleVerification userRoleVerification, + ValidationHelper validationHelper, + @Qualifier("relationNewRequestValidation") Function relationNewRequestValidator, + @Qualifier("relationUpdateRequestValidation") Function relationUpdateRequestValidator, + @Qualifier("relationDeleteRequestValidation") Function relationDeleteRequestValidator, AccountNotificationHelper accountNotification) { super(kafkaQueue, kafkaProducer); this.imdgProvider = imdgProvider; + this.idSequence = imdgProvider.getImdgIdGenerator(); this.accountNotification = accountNotification; + this.userRoleVerification = userRoleVerification; -// this.requestHelper = requestHelper.setLogger(log); + this.validationHelper = validationHelper; + this.relationNewRequestValidator = relationNewRequestValidator; + this.relationUpdateRequestValidator = relationUpdateRequestValidator; + this.relationDeleteRequestValidator = relationDeleteRequestValidator; + + relationMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); + companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + this.requestHelper = requestHelper.setLogger(log); } + // --- external API --- @Override public void afterPropertiesSet() { // this.profileDocumentMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class); // this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); -//todo all CLS-284 -// callback(ProfileDocumentNewRequest.class) -// .setFunction(this::profileDocumentNew) -// .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_NEW, callbacks::put); -// callback(ProfileDocumentUpdateRequest.class) -// .setFunction(this::profileDocumentUpdate) -// .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_UPDATE, callbacks::put); -// callback(CommonDeleteRequest.class) -// .setFunction(this::profileDocumentDelete) -// .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_DELETE, callbacks::put); -// init(); + + callback(RelationNewRequest.class) + .setFunction(this::relationNew) + .forDestination(Consts.DESTINATION_RELATION_NEW, callbacks::put); + callback(RelationUpdateRequest.class) + .setFunction(this::relationUpdate) + .forDestination(Consts.DESTINATION_RELATION_UPDATE, callbacks::put); + callback(CommonDeleteRequest.class) + .setFunction(this::relationDelete) + .forDestination(Consts.DESTINATION_RELATION_DELETE, callbacks::put); + init(); } + private synchronized RequestInfoUpdate relationNew(BaseRequest relationNewBaseRequest) { + RelationNewRequest req = relationNewBaseRequest.getRequestPayload(); + log.debug("relation-new request received, BaseRequest.id = {}", relationNewBaseRequest.getId()); + { // Валидация + RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(relationNewBaseRequest); + if (requestInfoUpdate != null) return requestInfoUpdate; + + requestInfoUpdate = validationHelper.validateTillFirstError(relationNewBaseRequest, relationNewRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + } + + + Company company = companyMap.getSingleObjectByID(req.getCompanyId()); + +// if (ClearingCategory.B.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.I.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) +// ) { +// /* +// relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=MKR, +// если запись создана и serviceStatus=CLOS, +// изменить запись в relation согласно описанию с тегом При возобнолвении +// , иначе вернуть ошибку (3024)"Договорные отношения %s в секции МКР уже созданы." +// */ +// } +// if (ClearingCategory.C.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.F.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) +// ) { +// /* +//проверить по relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=FOND, +//если запись создана и serviceStatus=CLOS, изменить запись в relation согласно описанию с тегом При возобнолвении, +// иначе вернуть ошибку (3025)"Договорные отношения %s на фондовой секции уже созданы." */ +// } + Relation relation = new Relation(); + relation.setId(idSequence.nextId()); + relation.setCreated(Instant.now()); + relation.setUpdated(relation.getCreated()); + + relation.setConsumerId(req.getCompanyId()); + relation.setSupplierId(SPVB_ID); // 1 СПВБ + if (req.getServiceStatus() != null) { + relation.setServiceStatus(req.getServiceStatus()); + } else { + log.warn("Request has no status. Set status from company[{}].status={}", company.getId(), company.getWorkflowStatus()); + relation.setServiceStatus(company.getWorkflowStatus()); + } + relation.setService(ru.spcex.platform.enumeration.Service.MKR.getKey()); // MKR + relation.setServiceProduct(ServiceProduct.ZERO.getKey()); + relation.setComment(req.getComment()); + + relationMap.insert(relation); + log.debug("New Relation[{}] created.", relation.getId()); + + return null; + } + + + private synchronized RequestInfoUpdate relationUpdate(BaseRequest relationUpdateBaseRequest) { + RelationUpdateRequest req = relationUpdateBaseRequest.getRequestPayload(); + log.debug("relation-update request received, BaseRequest.id = {}", relationUpdateBaseRequest.getId()); + { // Валидация + RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(relationUpdateBaseRequest); + if (requestInfoUpdate != null) return requestInfoUpdate; + + requestInfoUpdate = validationHelper.validateTillFirstError(relationUpdateBaseRequest, relationUpdateRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + } + + + //Company company = companyMap.getSingleObjectByID(req.getCompanyId()); +// +// if (ClearingCategory.B.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.I.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) +// ) { +// /* +// relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=MKR, +// если запись создана и serviceStatus=CLOS, +// изменить запись в relation согласно описанию с тегом При возобнолвении +// , иначе вернуть ошибку (3024)"Договорные отношения %s в секции МКР уже созданы." +// */ +// } +// if (ClearingCategory.C.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.F.equalsByKey(req.getClearingMemberCategory()) +// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) +// ) { +// /* +//проверить по relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=FOND, +//если запись создана и serviceStatus=CLOS, изменить запись в relation согласно описанию с тегом При возобнолвении, +// иначе вернуть ошибку (3025)"Договорные отношения %s на фондовой секции уже созданы." */ +// } + + Relation relation = relationMap.getSingleObjectByID(req.getId()); + relation.setUpdated(relation.getCreated()); + + if (req.getServiceStatus() != null) { + relation.setServiceStatus(req.getServiceStatus()); + } else { +// relation.setServiceStatus(company.getStatus()); + } + relation.setComment(req.getComment()); + + relationMap.insert(relation); + log.debug("Update Relation[{}] created.", relation.getId()); + + return null; + } + + + private synchronized RequestInfoUpdate relationDelete(BaseRequest relationDeleteBaseRequest) { + CommonDeleteRequest req = relationDeleteBaseRequest.getRequestPayload(); + log.debug("relation-delete request received, BaseRequest.id = {}", relationDeleteBaseRequest.getId()); + { // Валидация + RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(relationDeleteBaseRequest); + if (requestInfoUpdate != null) return requestInfoUpdate; + + requestInfoUpdate = validationHelper.validateTillFirstError(relationDeleteBaseRequest, relationDeleteRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + } + + + Relation relation = relationMap.getSingleObjectByID(req.getId()); + if (WorkflowStatus.Blocked.equalsByKey(relation.getServiceStatus())) { + log.warn("Relation {} already blocked.", relation.getId()); + } else { + relation.setUpdated(relation.getCreated()); + relation.setServiceStatus(WorkflowStatus.Blocked.getKey()); + + relationMap.insert(relation); + log.debug("Relation[{}] block.", relation.getId()); + } + return null; + } + + + // --- internal API --- + protected void createNewRelation(ImdgTransaction transaction, Company company) { Relation relation = new Relation(); // relation.setId(idSequence.nextId()); @@ -79,7 +251,7 @@ public class RelationService extends QueueConsumer implements InitializingBean { relation.setService(ru.spcex.platform.enumeration.Service.MKR.getKey()); // MKR relation.setServiceProduct(ServiceProduct.ZERO.getKey()); log.debug("New Relation[{}] created.", relation.getId()); - Imdg relationMap = transaction.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); + Imdg relationMap = transaction.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); relationMap.insert(relation); } @@ -103,7 +275,7 @@ public class RelationService extends QueueConsumer implements InitializingBean { } } - protected void onChangeWorkflowStatusOnlyRelationChange(ImdgTransaction transaction, Company company, String newStatus) throws ValidationException { + protected synchronized void onChangeWorkflowStatusOnlyRelationChange(ImdgTransaction transaction, Company company, String newStatus) throws ValidationException { assert Objects.equals(newStatus, company.getWorkflowStatus()); String query = String.format("consumerId=%s", company.getId()); Imdg relationMap = transaction.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/RelationServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/RelationServiceTest.java new file mode 100644 index 000000000..8bebb24f7 --- /dev/null +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/RelationServiceTest.java @@ -0,0 +1,214 @@ +package ru.spcex.clearing.company.service; + +import org.apache.kafka.clients.consumer.MockConsumer; +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.company.relation.Relation; +import ru.clearing.platform.dictionary.ClearingCategoryDictionary; +import ru.clearing.platform.dictionary.WorkflowStatusDictionary; +import ru.spcex.clearing.company.config.BeanConfiguration; +import ru.spcex.clearing.company.config.validation.RelationValidationConfig; +import ru.spcex.clearing.company.config.validation.ValidationConfig; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.RelationNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.RelationUpdateRequest; +import ru.spcex.clearing.test.MatcherFactory; +import ru.spcex.clearing.test.TestUtils; +import ru.spcex.clearing.test.config.ImdgTestConfig; +import ru.spcex.clearing.test.config.KafkaTestConfig; +import ru.spcex.platform.enumeration.ClearingCategory; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; + +import javax.annotation.PostConstruct; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparator; +import static ru.spcex.clearing.test.TestUtils.*; +import static ru.spcex.clearing.test.config.ImdgTestConfig.currentID; +import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + BeanConfiguration.class, + ValidationConfig.class, + RelationService.class, + AccountNotificationHelper.class, + RelationValidationConfig.class, + KafkaTestConfig.class, + ImdgTestConfig.class}) +class RelationServiceTest { + + public static final MatcherFactory.Matcher RELATION_MATCHER = usingIgnoringFieldsComparator("created", "updated"); + private static final int PARTITION = 0; + + private static final Long ID = currentID.getAndIncrement(); + @Autowired + RelationService relationService; + @Autowired + @Qualifier("hazelcastServiceTest") + private ImdgProvider hazelcastServiceTest; + private Imdg relationMap; + private Imdg companyMap; + + @Captor + private ArgumentCaptor producerRecord; + @SpyBean + private MockProducer mockProducer; + + private long COMPANY_ID; + + private final long RELATION_ID = ID; + + @PostConstruct + private void init() { + waitAvailableImdgProviderAndAddAdminWithDefaultId(); + this.relationMap = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); + this.companyMap = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + + Company testCompany = new Company(); + testCompany.setWorkflowStatus(WorkflowStatus.Active.getKey()); + COMPANY_ID = companyMap.insert(testCompany); + + Imdg workflowStatusDictionaryImdg = hazelcastServiceTest.getImdg( + IMDGDistributedNames.Map_WorkflowStatusDictionary, + WorkflowStatusDictionary.class + ); + WorkflowStatusDictionary workflowStatusDictionary = new WorkflowStatusDictionary(); + workflowStatusDictionary.setId(1L); + workflowStatusDictionary.setCode(WorkflowStatus.Active.getKey()); + workflowStatusDictionary.setName("active"); + workflowStatusDictionaryImdg.insert(workflowStatusDictionary); + workflowStatusDictionary = new WorkflowStatusDictionary(); + workflowStatusDictionary.setId(2L); + workflowStatusDictionary.setCode(WorkflowStatus.Blocked.getKey()); + workflowStatusDictionary.setName("not active"); + workflowStatusDictionaryImdg.insert(workflowStatusDictionary); + + Imdg clearingCategoryDictionaryImdg = hazelcastServiceTest.getImdg( + IMDGDistributedNames.Map_ClearingCategoryDictionary, + ClearingCategoryDictionary.class + ); + ClearingCategoryDictionary clearingCategoryDictionary = new ClearingCategoryDictionary(); + clearingCategoryDictionary.setId(1L); + clearingCategoryDictionary.setCode(ClearingCategory.I.getKey()); + clearingCategoryDictionary.setName("I"); + clearingCategoryDictionaryImdg.insert(clearingCategoryDictionary); + + TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class); + doReturn(future).when(mockProducer).send(producerRecord.capture()); + } + + + @Test + void newRelation() { + //ARRANGE + RelationNewRequest relationNewRequest = new RelationNewRequest(); + relationNewRequest.setCompanyId(COMPANY_ID); + relationNewRequest.setServiceStatus("ACTV"); + relationNewRequest.setClearingMemberCategory("I"); + relationNewRequest.setComment(null); + + Relation predictableRelation = new Relation(); + predictableRelation.setId(RELATION_ID); + predictableRelation.setConsumerId(relationNewRequest.companyId); + predictableRelation.setService("MKR"); + predictableRelation.setServiceProduct("ZERO"); + predictableRelation.setSupplierId(1L); + predictableRelation.setServiceStatus("ACTV"); + + //ACT + String jsonString = getJsonStringForNew(relationNewRequest, ID); + + addRecordToKafka((MockConsumer) relationService.getConsumer(), Consts.DESTINATION_RELATION_NEW, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + Relation resultNew = relationMap.getSingleObjectBySQL("serviceStatus=ACTV"); // String.format("supplierId = %d", COMPANY_ID)); + predictableRelation.setId(resultNew.getId()); + RELATION_MATCHER.assertMatch(resultNew, predictableRelation); + } + + @Test + void updateRelation() { + //ARRANGE + Relation existsRelation = new Relation(); + existsRelation.setId(ID); + existsRelation.setConsumerId(COMPANY_ID); + existsRelation.setSupplierId(1L); + existsRelation.setComment("Test ONE"); + existsRelation.setServiceStatus("ACTV"); + existsRelation.setServiceProduct("PROD"); + existsRelation.setService("MKR"); + relationMap.insert(existsRelation); + + Relation predictableRelation = new Relation(); + predictableRelation.setId(ID); + predictableRelation.setConsumerId(COMPANY_ID); + predictableRelation.setSupplierId(1L); + predictableRelation.setComment("Another Me - ONE"); + predictableRelation.setServiceStatus("ACTV"); + predictableRelation.setServiceProduct("PROD"); + predictableRelation.setService("MKR"); + + RelationUpdateRequest relationUpdateRequest = new RelationUpdateRequest(); + relationUpdateRequest.setId(RELATION_ID); + relationUpdateRequest.setComment("Another Me - ONE"); + relationUpdateRequest.setServiceStatus("ACTV"); + + //ACT + String jsonString = getJsonStringForUpdate(relationUpdateRequest, ID); + + addRecordToKafka((MockConsumer) relationService.getConsumer(), Consts.DESTINATION_RELATION_UPDATE, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + Relation resultUpdate = relationMap.getSingleObjectBySQL(String.format("id = %d", RELATION_ID)); +// predictableProfileDocument.setId(resultUpdate.getId()); + RELATION_MATCHER.assertMatch(resultUpdate, predictableRelation); + } + + + @Test + void deleteProfileDocument() { + //ARRANGE + Relation existsRelation = new Relation(); + existsRelation.setId(ID); + existsRelation.setConsumerId(COMPANY_ID); + existsRelation.setSupplierId(1L); + existsRelation.setComment("Test ONE"); + existsRelation.setServiceStatus("ACTV"); + existsRelation.setServiceProduct("PROD"); + existsRelation.setService("MKR"); + relationMap.insert(existsRelation); + + CommonDeleteRequest profileDocumentDeleteRequest = new CommonDeleteRequest(); + profileDocumentDeleteRequest.setId(RELATION_ID); + + //ACT + String jsonString = getJsonStringForUpdate(profileDocumentDeleteRequest, ID); + + addRecordToKafka((MockConsumer) relationService.getConsumer(), Consts.DESTINATION_RELATION_DELETE, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + Relation resultUpdate = relationMap.getSingleObjectByID(RELATION_ID); +// Assertions.assertNull(resultUpdate); + assertEquals(WorkflowStatus.Blocked.getKey(), resultUpdate.getServiceStatus()); + } +} \ No newline at end of file diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java index c00ea09a8..2d0f0cae6 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java @@ -72,7 +72,9 @@ public interface Consts { @Deprecated String ACCOUNT_NEW_SDF01 = "account-new-sdf01"; + String DESTINATION_RELATION_NEW = "relation-new"; String DESTINATION_RELATION_UPDATE = "relation-update"; + String DESTINATION_RELATION_DELETE = "relation-delete"; String DESTINATION_PROFILE_DOCUMENT_NEW = "profile-document-new"; String DESTINATION_PROFILE_DOCUMENT_UPDATE = "profile-document-update"; String DESTINATION_PROFILE_DOCUMENT_DELETE = "profile-document-delete"; diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/RelationNewRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/RelationNewRequest.java new file mode 100644 index 000000000..9e630303a --- /dev/null +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/RelationNewRequest.java @@ -0,0 +1,46 @@ +package ru.spcex.clearing.platform.messaging.domain.cud.company; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class RelationNewRequest { + @JsonProperty + public Long companyId; + @JsonProperty + private String serviceStatus; + @JsonProperty + private String clearingMemberCategory; + @JsonProperty + private String comment; + + public Long getCompanyId() { + return companyId; + } + + public void setCompanyId(Long companyId) { + this.companyId = companyId; + } + + public String getServiceStatus() { + return serviceStatus; + } + + public void setServiceStatus(String serviceStatus) { + this.serviceStatus = serviceStatus; + } + + public String getClearingMemberCategory() { + return clearingMemberCategory; + } + + public void setClearingMemberCategory(String clearingMemberCategory) { + this.clearingMemberCategory = clearingMemberCategory; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } +} From 3d56c0fc6376e8040b23b84631d58178dc783d86 Mon Sep 17 00:00:00 2001 From: psemenkov Date: Tue, 9 May 2023 21:32:01 +0300 Subject: [PATCH 16/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-268?= =?UTF-8?q?=20=D0=9F=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BA=D1=83=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81?= =?UTF-8?q?=D0=BA=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...erServiceImdgConfig.java => ImdgConfig.java} | 2 +- .../config/SchedulerServiceConfig.java | 17 +++++++++++++++++ .../clearing/scheduler/service/TaskManager.java | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) rename clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/{SchedulerServiceImdgConfig.java => ImdgConfig.java} (97%) create mode 100644 clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/SchedulerServiceConfig.java diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/SchedulerServiceImdgConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ImdgConfig.java similarity index 97% rename from clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/SchedulerServiceImdgConfig.java rename to clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ImdgConfig.java index f9d5da568..69fea82d7 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/SchedulerServiceImdgConfig.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ImdgConfig.java @@ -10,7 +10,7 @@ import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; @Configuration -public class SchedulerServiceImdgConfig { +public class ImdgConfig { private static ThreadPoolTaskExecutor createThreadPoolTaskExecutor(int maxPoolSz, boolean waitForCompletion) { ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); if (maxPoolSz > 2) { diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/SchedulerServiceConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/SchedulerServiceConfig.java new file mode 100644 index 000000000..4e9c619c0 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/SchedulerServiceConfig.java @@ -0,0 +1,17 @@ +package ru.spcex.clearing.scheduler.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +@Configuration +public class SchedulerServiceConfig { + @Bean(name = "taskScheduler") + public TaskScheduler taskScheduler() { + ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); + threadPoolTaskScheduler.setPoolSize(5); + threadPoolTaskScheduler.setThreadNamePrefix("ThreadPoolTaskScheduler"); + return threadPoolTaskScheduler; + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java index 9aed3335e..2f0719507 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java @@ -48,7 +48,7 @@ public class TaskManager implements InitializingBean, AutoCloseable { private final ExecutorService outputExecutor; @Autowired - TaskManager(TaskScheduler taskScheduler, + TaskManager(@Qualifier("taskScheduler") TaskScheduler taskScheduler, ImdgProvider imdgProvider, LauncherSender launcherSender, @Qualifier("plannerQueue") BlockingQueue> plannerQueue) { From 84870fb64f5a6dfa52f83998fdffe2cbd61c2960 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Wed, 10 May 2023 12:16:41 +0300 Subject: [PATCH 17/20] =?UTF-8?q?company-service=20http://jira.mfd.msk:808?= =?UTF-8?q?8/browse/CLS-284=20=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../clearing/company/error/CompanyErrors.java | 2 + .../company/service/RelationService.java | 126 +++++++++++------- 2 files changed, 78 insertions(+), 50 deletions(-) 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 a7e4b232d..1c5b42c49 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 @@ -25,6 +25,8 @@ public enum CompanyErrors implements IErrorEnumId { EditContactType(3021L), // Тип контакта компании %s не может быть изменен. TradingClearingRegistryNotFound(3022L), // ТКР с %s не найден AccountNotFound(3023L), // Счет %s не найден + ClearingMemberCategoryOnMKRAlreadyExist(3024L), // Договорные отношения %s в секции МКР уже созданы. + ClearingMemberCategoryOnFONDAlreadyExist(3025L), // Договорные отношения %s на фондовой секции уже созданы. RelationNotFound(3026L), // Запись о договорных отношениях не найдена ; private final Long id; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java index 882abff8c..ab47be9ad 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java @@ -21,6 +21,7 @@ import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.util.security.UserRoleVerification; import ru.spcex.clearing.validation.common.ValidationHelper; +import ru.spcex.platform.enumeration.ClearingCategory; import ru.spcex.platform.enumeration.ServiceProduct; import ru.spcex.platform.enumeration.ServiceStatus; import ru.spcex.platform.enumeration.WorkflowStatus; @@ -33,6 +34,7 @@ import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; import java.util.Collection; +import java.util.Map; import java.util.Objects; import java.util.function.Function; @@ -115,38 +117,48 @@ public class RelationService extends QueueConsumer implements InitializingBean { Company company = companyMap.getSingleObjectByID(req.getCompanyId()); -// if (ClearingCategory.B.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.I.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) -// ) { -// /* -// relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=MKR, -// если запись создана и serviceStatus=CLOS, -// изменить запись в relation согласно описанию с тегом При возобнолвении -// , иначе вернуть ошибку (3024)"Договорные отношения %s в секции МКР уже созданы." -// */ -// } -// if (ClearingCategory.C.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.F.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) -// ) { -// /* -//проверить по relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=FOND, -//если запись создана и serviceStatus=CLOS, изменить запись в relation согласно описанию с тегом При возобнолвении, -// иначе вернуть ошибку (3025)"Договорные отношения %s на фондовой секции уже созданы." */ -// } - Relation relation = new Relation(); - relation.setId(idSequence.nextId()); - relation.setCreated(Instant.now()); - relation.setUpdated(relation.getCreated()); + Relation existRelation = searchRelation(req.getClearingMemberCategory(), req.getCompanyId()); + if (existRelation != null && !WorkflowStatus.Blocked.equalsByKey(existRelation.getServiceStatus())) { + CompanyErrors errorType; + if (ru.spcex.platform.enumeration.Service.MKR.equalsByKey(existRelation.getService())) { + errorType = CompanyErrors.ClearingMemberCategoryOnMKRAlreadyExist; + } else if (ru.spcex.platform.enumeration.Service.FOND.equalsByKey(existRelation.getService())) { + errorType = CompanyErrors.ClearingMemberCategoryOnFONDAlreadyExist; + } else { + log.warn("Unknown relation[{}] service={}", existRelation.getId(), existRelation.getService()); + errorType = CompanyErrors.GeneralError; + } + return requestHelper.makeErrorResponse(relationNewBaseRequest, errorType); + } + + Relation relation; + if (existRelation == null) { + relation = new Relation(); + relation.setId(idSequence.nextId()); + relation.setCreated(Instant.now()); + relation.setUpdated(relation.getCreated()); + } else { + log.info("Found exist relation id={}, it will be update.", existRelation.getId()); + relation = existRelation; + relation.setUpdated(Instant.now()); + } relation.setConsumerId(req.getCompanyId()); relation.setSupplierId(SPVB_ID); // 1 СПВБ if (req.getServiceStatus() != null) { relation.setServiceStatus(req.getServiceStatus()); } else { - log.warn("Request has no status. Set status from company[{}].status={}", company.getId(), company.getWorkflowStatus()); - relation.setServiceStatus(company.getWorkflowStatus()); + if (existRelation != null) { + relation.setServiceStatus(ServiceStatus.Reopened.getKey()); + log.debug("Request has no status. Set status by resume: {}", relation.getServiceStatus()); + } else { + String toStatus = WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Active.getKey() : + WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Closed.getKey() : + null; + log.debug("Request has no status. Set status by company[{}].status={}. Relation[{}].serviceSStatus={}", + company.getId(), company.getWorkflowStatus(), toStatus); + relation.setServiceStatus(toStatus); + } } relation.setService(ru.spcex.platform.enumeration.Service.MKR.getKey()); // MKR relation.setServiceProduct(ServiceProduct.ZERO.getKey()); @@ -158,6 +170,27 @@ public class RelationService extends QueueConsumer implements InitializingBean { return null; } + private Relation searchRelation(String clearingMemberCategory, Long consumerId) { + String svc; + if (ClearingCategory.B.equalsByKey(clearingMemberCategory) + || ClearingCategory.I.equalsByKey(clearingMemberCategory) + || ClearingCategory.V.equalsByKey(clearingMemberCategory) + ) { + svc = ru.spcex.platform.enumeration.Service.MKR.getKey(); + } else if (ClearingCategory.C.equalsByKey(clearingMemberCategory) + || ClearingCategory.F.equalsByKey(clearingMemberCategory) + ) { + svc = ru.spcex.platform.enumeration.Service.FOND.getKey(); + } else { + log.warn("Unexpected relation Relation={}", clearingMemberCategory); + return null; + } + Relation existRelation = relationMap.getSingleObjectByFieldValues(Map.of( + "consumerId", consumerId, + "service", svc + )); + return existRelation; + } private synchronized RequestInfoUpdate relationUpdate(BaseRequest relationUpdateBaseRequest) { RelationUpdateRequest req = relationUpdateBaseRequest.getRequestPayload(); @@ -171,37 +204,30 @@ public class RelationService extends QueueConsumer implements InitializingBean { } - //Company company = companyMap.getSingleObjectByID(req.getCompanyId()); -// -// if (ClearingCategory.B.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.I.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) -// ) { -// /* -// relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=MKR, -// если запись создана и serviceStatus=CLOS, -// изменить запись в relation согласно описанию с тегом При возобнолвении -// , иначе вернуть ошибку (3024)"Договорные отношения %s в секции МКР уже созданы." -// */ -// } -// if (ClearingCategory.C.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.F.equalsByKey(req.getClearingMemberCategory()) -// || ClearingCategory.V.equalsByKey(req.getClearingMemberCategory()) -// ) { -// /* -//проверить по relation.consumerId (clearingMemberCategory.companyId=relation.companyId) и service=FOND, -//если запись создана и serviceStatus=CLOS, изменить запись в relation согласно описанию с тегом При возобнолвении, -// иначе вернуть ошибку (3025)"Договорные отношения %s на фондовой секции уже созданы." */ -// } - Relation relation = relationMap.getSingleObjectByID(req.getId()); relation.setUpdated(relation.getCreated()); if (req.getServiceStatus() != null) { + log.debug("To relation {} set serivceStatus=\"{}\" by user request.", relation.getId(), req.getServiceStatus()); relation.setServiceStatus(req.getServiceStatus()); } else { -// relation.setServiceStatus(company.getStatus()); + if (relation.getConsumerId() == null) { + log.warn("Relation[{}]. consumerId was null", relation.getId()); + } + Company company = companyMap.getSingleObjectByID(relation.getConsumerId()); + String toStatus = WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Active.getKey() : + WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Closed.getKey() : + null; + if (ServiceStatus.Active.equalsByKey(toStatus) && ServiceStatus.Closed.equalsByKey(relation.getServiceStatus())) { + relation.setServiceStatus(ServiceStatus.Reopened.getKey()); + log.debug("Set status by resume: {}", relation.getServiceStatus()); + } else { + relation.setServiceStatus(toStatus); + log.debug("Request has no status. Set status by company[{}].status={}. Relation[{}].serviceSStatus={}", + company.getId(), company.getWorkflowStatus(), toStatus, relation.getServiceStatus()); + } } + relation.setComment(req.getComment()); relationMap.insert(relation); From a4d1a618cb1db406dbebfc4796af3c2cfa3dbd4f Mon Sep 17 00:00:00 2001 From: AKurakin Date: Wed, 10 May 2023 12:17:20 +0300 Subject: [PATCH 18/20] =?UTF-8?q?RequestHelper=20=D1=82.=D0=BA.=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=8B=D1=87=D0=BD=D0=BE=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82?= =?UTF-8?q?=20=D1=81=D1=80=D0=B0=D0=B7=D1=83=20=D0=B2=D0=BE=D0=B7=D0=B2?= =?UTF-8?q?=D1=80=D0=B0=D1=89=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20-=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B7=D0=B0=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D1=8C=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0=20=D0=BE?= =?UTF-8?q?=D1=82=D0=B2=D0=B5=D1=82=D0=B0=20=D0=B2=20=D0=BB=D0=BE=D0=B3=20?= =?UTF-8?q?info?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/spcex/clearing/company/util/RequestHelper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java index f134ec949..ac865b66a 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java @@ -74,6 +74,7 @@ public class RequestHelper { public RequestInfoUpdate makeErrorResponse(BaseRequest request, EnumMessage msg) { String errorMsg = msg == null? "" : messageResolver.resolve(msg); + log.info("{}", errorMsg); return new RequestInfoUpdate() .setId(request.getId()) .setStatus(Status.Error) From a60726241202bb6b65d2fe0a0f5336ba0831e1e7 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Wed, 10 May 2023 12:27:17 +0300 Subject: [PATCH 19/20] =?UTF-8?q?http://jira.mfd.msk:8088/browse/CLS-284?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spcex/clearing/company/service/CompanyInfoServiceTest.java | 2 ++ .../ru/spcex/clearing/company/service/CompanyServiceTest.java | 3 ++- .../clearing/company/service/CompanySymbolServiceTest.java | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java index b521fd7e4..2735eff4c 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyInfoServiceTest.java @@ -18,6 +18,7 @@ import ru.clearing.platform.dictionary.*; import ru.spcex.clearing.company.config.BeanConfiguration; import ru.spcex.clearing.company.config.validation.CompanySymbolValidationConfig; import ru.spcex.clearing.company.config.validation.CompanyValidationConfig; +import ru.spcex.clearing.company.config.validation.RelationValidationConfig; import ru.spcex.clearing.company.config.validation.ValidationConfig; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; @@ -51,6 +52,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv CompanySymbolService.class, AccountNotificationHelper.class, RelationService.class, + RelationValidationConfig.class, BeanConfiguration.class, KafkaTestConfig.class, diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java index f18f68a84..e6ec57333 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java @@ -21,6 +21,7 @@ import ru.clearing.platform.dictionary.WorkflowStatusDictionary; import ru.spcex.clearing.company.config.BeanConfiguration; import ru.spcex.clearing.company.config.validation.CompanySymbolValidationConfig; import ru.spcex.clearing.company.config.validation.CompanyValidationConfig; +import ru.spcex.clearing.company.config.validation.RelationValidationConfig; import ru.spcex.clearing.company.config.validation.ValidationConfig; import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -54,7 +55,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv ValidationConfig.class, CompanySymbolService.class, AccountNotificationHelper.class, - RelationService.class, + RelationService.class, RelationValidationConfig.class, CompanySymbolService.class, CompanySymbolValidationConfig.class, diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java index 39e77828d..f9dee4531 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanySymbolServiceTest.java @@ -18,6 +18,7 @@ import ru.clearing.platform.dictionary.CompanySymbolDictionary; import ru.spcex.clearing.company.config.BeanConfiguration; import ru.spcex.clearing.company.config.validation.CompanySymbolValidationConfig; import ru.spcex.clearing.company.config.validation.CompanyValidationConfig; +import ru.spcex.clearing.company.config.validation.RelationValidationConfig; import ru.spcex.clearing.company.config.validation.ValidationConfig; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; @@ -50,7 +51,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv CompanyService.class, CompanyValidationConfig.class, AccountNotificationHelper.class, - RelationService.class, + RelationService.class, RelationValidationConfig.class, KafkaTestConfig.class, ImdgTestConfig.class}) From 795075a4b6a8e1c6c6c333fc015bf7974a9e4413 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Wed, 10 May 2023 13:33:54 +0300 Subject: [PATCH 20/20] =?UTF-8?q?RequestHelper=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D1=91=D1=81=20=D0=B2=20clearing-validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/services}/RequestHelper.java | 19 +++++++++++++------ .../company/config/BeanConfiguration.java | 4 ++-- .../company/service/CompanyInfoService.java | 2 +- .../service/CompanyRoleSetService.java | 2 +- .../company/service/CompanyService.java | 2 +- .../company/service/CompanySymbolService.java | 2 +- .../service/ProfileDocumentService.java | 3 +-- .../company/service/RelationService.java | 2 +- 8 files changed, 21 insertions(+), 15 deletions(-) rename clearing-parent/{company-service/src/main/java/ru/spcex/clearing/company/util => clearing-validation/src/main/java/ru/spcex/clearing/util/services}/RequestHelper.java (84%) diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/RequestHelper.java similarity index 84% rename from clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/RequestHelper.java index ac865b66a..04decd8a7 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java +++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/RequestHelper.java @@ -1,8 +1,7 @@ -package ru.spcex.clearing.company.util; +package ru.spcex.clearing.util.services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.Status; @@ -22,21 +21,28 @@ import java.util.Objects; * callback(CompanyNewRequest.class) * .setFunction( request -> requestHelper.requestFunction(this::createCompany, request)) * .forDestination(Consts.DESTINATION_COMPANY_NEW, callbacks::put); + * + * return requestHelper.makeErrorResponse(CompanyError.GeneralError, ...) */ public class RequestHelper { protected Logger log = LoggerFactory.getLogger(getClass()); protected final IMessageResolver messageResolver; + protected final IErrorEnumId generalError; - public RequestHelper(IMessageResolver messageResolver) { + public RequestHelper(IMessageResolver messageResolver, IErrorEnumId generalError) { Objects.requireNonNull(messageResolver); this.messageResolver = messageResolver; + this.generalError = generalError; + Objects.requireNonNull(generalError, "Required generalError enum"); } - public RequestHelper(Logger log, IMessageResolver messageResolver) { + public RequestHelper(Logger log, IMessageResolver messageResolver, IErrorEnumId generalError) { Objects.requireNonNull(log); Objects.requireNonNull(messageResolver); this.log = log; this.messageResolver = messageResolver; + this.generalError = generalError; + Objects.requireNonNull(generalError, "Required generalError enum"); } /** @@ -58,13 +64,14 @@ public class RequestHelper { String message = expectedE.getEnumMsg() == null ? expectedE.getMessage() : messageResolver.resolve(expectedE.getEnumMsg()); + log.info("Response: {}", message); return new RequestInfoUpdate() .setId(userRequest.getId()) .setStatus(Status.Error) .setMessage(message); } catch (Exception unexpectedE) { log.error("Error at {}: {} ", command, ExceptionUtils.getStackTrace(unexpectedE)); - String message = messageResolver.resolve(new EnumMessage(CompanyErrors.GeneralError)); + String message = messageResolver.resolve(new EnumMessage(generalError)); return new RequestInfoUpdate() .setId(userRequest.getId()) .setStatus(Status.Error) @@ -74,7 +81,7 @@ public class RequestHelper { public RequestInfoUpdate makeErrorResponse(BaseRequest request, EnumMessage msg) { String errorMsg = msg == null? "" : messageResolver.resolve(msg); - log.info("{}", errorMsg); + log.info("Response: {}", errorMsg); return new RequestInfoUpdate() .setId(request.getId()) .setStatus(Status.Error) diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java index d6248d708..fd44e1d0e 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java @@ -5,7 +5,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import ru.spcex.clearing.company.error.CompanyErrors; -import ru.spcex.clearing.company.util.RequestHelper; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.clearing.util.security.UserRoleVerification; import ru.spcex.platform.enumeration.UserRole; import ru.spcex.platform.imdg.api.ImdgProvider; @@ -22,7 +22,7 @@ public class BeanConfiguration { @Bean @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public RequestHelper requestHelper(IMessageResolver messageResolver) { - return new RequestHelper(messageResolver); + return new RequestHelper(messageResolver, CompanyErrors.GeneralError); } @Bean diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java index 03d355d49..c3199aca8 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyInfoService.java @@ -11,7 +11,7 @@ import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.profile.CompanyInfo; import ru.spcex.clearing.company.error.CompanyErrors; -import ru.spcex.clearing.company.util.RequestHelper; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyRoleSetService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyRoleSetService.java index 2af7a358c..ca4526b9b 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyRoleSetService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyRoleSetService.java @@ -9,7 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.CompanyRoleSet; import ru.spcex.clearing.company.error.CompanyErrors; -import ru.spcex.clearing.company.util.RequestHelper; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java index 542916892..f7182432d 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java @@ -11,7 +11,7 @@ import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.CompanySymbols; import ru.spcex.clearing.company.error.CompanyErrors; -import ru.spcex.clearing.company.util.RequestHelper; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanySymbolService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanySymbolService.java index 85c0469f8..cf534c0ea 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanySymbolService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanySymbolService.java @@ -10,7 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.CompanySymbols; -import ru.spcex.clearing.company.util.RequestHelper; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java index adf51b4ed..30eab291e 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java @@ -12,7 +12,7 @@ import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.profile.ProfileDocument; import ru.spcex.clearing.company.error.CompanyErrors; -import ru.spcex.clearing.company.util.RequestHelper; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; @@ -21,7 +21,6 @@ import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentNe import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; -import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; import ru.spcex.clearing.util.security.UserRoleVerification; import ru.spcex.clearing.validation.common.ValidationHelper; import ru.spcex.platform.enumeration.DocumentTypes; diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java index ab47be9ad..d91417af6 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/RelationService.java @@ -11,7 +11,7 @@ import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.relation.Relation; import ru.spcex.clearing.company.error.CompanyErrors; -import ru.spcex.clearing.company.util.RequestHelper; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts;