From 7492fbe8238347696a8b0a90a2e933b6ef583df7 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 17 Jun 2026 09:27:09 +0300 Subject: [PATCH] http://jira.mfd.msk:8088/browse/CLS-1039 --- .../ClientCodeValidationConfig.java | 16 ++++ .../listeners/ClientCodeMessageListener.java | 81 +++++++++++++++--- .../v2/validators/ClientCodeValidator.java | 8 ++ ...ewayUpdateEksClientCodeValidationRule.java | 82 +++++++++++++++++++ 4 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayUpdateEksClientCodeValidationRule.java diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/ClientCodeValidationConfig.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/ClientCodeValidationConfig.java index 8b807f073..01d85d8bc 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/ClientCodeValidationConfig.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/ClientCodeValidationConfig.java @@ -12,6 +12,7 @@ import ru.spcex.clearing.account.errors.AccountError; import ru.spcex.clearing.account.validation.BackendClientCodeValidationRule; import ru.spcex.clearing.account.validation.GatewayClientCodeValidationRule; import ru.spcex.clearing.account.validation.GatewayEksClientCodeValidationRule; +import ru.spcex.clearing.account.validation.GatewayUpdateEksClientCodeValidationRule; 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; @@ -163,4 +164,19 @@ public class ClientCodeValidationConfig { }; } + @Bean("updateTkrEksAccountsGatewayValidator") + public Function updateTkrEksAccountsGatewayValidator(Map> imdgForValidation) { + return tkrGatewayRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(tkrGatewayRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Account); + addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry); + addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistryList); + return new ValidatorImpl<>(context, + GatewayUpdateEksClientCodeValidationRule.TkrIsPresent, + GatewayUpdateEksClientCodeValidationRule.AccountsNotLinkedToTkr + ); + }; + } } diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/listeners/ClientCodeMessageListener.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/listeners/ClientCodeMessageListener.java index 53c15e5a2..93932c385 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/listeners/ClientCodeMessageListener.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/listeners/ClientCodeMessageListener.java @@ -23,6 +23,7 @@ import ru.spcex.clearing.account.service.TradingClearingRegistryService; import ru.spcex.clearing.account.service.v2.GatewayRequestCreator; import ru.spcex.clearing.account.service.v2.facade.AccountFacade; import ru.spcex.clearing.account.service.v2.facade.ClientCodeFacade; +import ru.spcex.clearing.account.service.v2.facade.TradingClearingRegistryListFacade; import ru.spcex.clearing.account.service.v2.validators.ClientCodeValidator; import ru.spcex.clearing.account.validation.ClientCodeStoreObjects; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -34,6 +35,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.TkrAccountsGatewa import ru.spcex.clearing.platform.messaging.domain.cud.gateway.MoneyAccountMsgRequest; import ru.spcex.clearing.platform.messaging.domain.cud.gateway.SendTkrRequest; import ru.spcex.clearing.platform.messaging.domain.cud.gateway.Tkr; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryListNewRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.Status; @@ -57,6 +59,7 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali private final UserRoleVerification userRoleVerification; private final AccountFacade accountFacade; private final TradingClearingRegistryService tradingClearingRegistryService; + private final TradingClearingRegistryListFacade tradingClearingRegistryListFacade; public ClientCodeMessageListener(Consumer kafkaQueue, Producer kafkaProducer, @@ -67,7 +70,8 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali GatewayRequestCreator gatewayRequestCreator, UserRoleVerification userRoleVerification, AccountFacade accountFacade, - TradingClearingRegistryService tradingClearingRegistryService) { + TradingClearingRegistryService tradingClearingRegistryService, + TradingClearingRegistryListFacade tradingClearingRegistryListFacade) { super(kafkaQueue, kafkaProducer); this.kafkaSender = kafkaSender; this.imdgProvider = imdgProvider; @@ -77,6 +81,7 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali this.userRoleVerification = userRoleVerification; this.accountFacade = accountFacade; this.tradingClearingRegistryService = tradingClearingRegistryService; + this.tradingClearingRegistryListFacade = tradingClearingRegistryListFacade; } @Override @@ -92,7 +97,7 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali .setFunction(this::clientCodeNewFromGateway) .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW_FROM_GATEWAY, callbacks::put); callback(TkrAccountsGatewayRequest.class) - .setFunction(this::clientCodeNewFromGateway) + .setFunction(this::clientCodeUpdateFromGateway) .forDestination(Consts.DESTINATION_CLIENT_CODE_UPDATE_FROM_GATEWAY, callbacks::put); init(); } @@ -118,16 +123,10 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali eksAccountsAfterValidation.put(tkrAccount, validationResult); }); + if (isAnyoneInvalid.get()) { log.debug("Create error request to gateway service"); - List eksTkrs = eksAccountsAfterValidation.entrySet() - .stream() - .map(tkrAccountValidationResultEntry -> - gatewayRequestCreator.crateErrorTkrToGateway( - tkrAccountValidationResultEntry.getKey(), - tkrAccountValidationResultEntry.getValue().errorMsg() - )) - .toList(); + List eksTkrs = makeErrorTkrResponse(eksAccountsAfterValidation); sendTkrRequest.getTkrs().addAll(eksTkrs); kafkaSender.sendRequestToQueue(Consts.ACCOUNTS_TO_GATEWAY, sendTkrRequest); return null; @@ -137,6 +136,37 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali return null; } + private RequestInfoUpdate clientCodeUpdateFromGateway(BaseRequest tkrRequest) { + TkrAccountsGatewayRequest gatewayRequest = tkrRequest.getRequestPayload(); + + SendTkrRequest sendTkrRequest = new SendTkrRequest(); + sendTkrRequest.setRequestId(gatewayRequest.getRequestId()); + + AtomicBoolean isAnyoneInvalid = new AtomicBoolean(false); + Map eksAccountsAfterValidation = new HashMap<>(); + + gatewayRequest.getAccounts().forEach(tkrAccount -> { + ValidationResult validationResult = clientCodeValidator.checkGatewayUpdateRequestWithEksAcc(tkrAccount); + if (!validationResult.isValid()) { + log.debug("Validation failed for tkr.client_code {}", tkrAccount.getClientCode()); + isAnyoneInvalid.set(true); + } + eksAccountsAfterValidation.put(tkrAccount, validationResult); + }); + + if (isAnyoneInvalid.get()) { + log.debug("Create error request to gateway service"); + List eksTkrs = makeErrorTkrResponse(eksAccountsAfterValidation); + sendTkrRequest.getTkrs().addAll(eksTkrs); + kafkaSender.sendRequestToQueue(Consts.ACCOUNTS_TO_GATEWAY, sendTkrRequest); + return null; + } + + processUpdateEksAccount(eksAccountsAfterValidation, sendTkrRequest); + kafkaSender.sendRequestToQueue(Consts.ACCOUNTS_TO_GATEWAY, sendTkrRequest); + return null; + } + private void processEksAccount(Map accountsAfterValidation, SendTkrRequest tkrRequest) { for (Map.Entry entry : accountsAfterValidation.entrySet()) { TkrAccount tkrAccount = entry.getKey(); @@ -180,6 +210,26 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali } } + private void processUpdateEksAccount(Map accountsAfterValidation, SendTkrRequest tkrRequest) { + for (Map.Entry entry : accountsAfterValidation.entrySet()) { + TkrAccount tkrAccount = entry.getKey(); + ValidationResult validationResult = entry.getValue(); + IValidator validator = validationResult.validator(); + List clrnAccs = validator.getStored(ClientCodeStoreObjects.CLRN_ACCS); + TradingClearingRegistry tradingClearingRegistry = validator.getStored(ClientCodeStoreObjects.TRADING_CLEARING_REGISTRY); + List accIds = clrnAccs.stream() + .map(Account::getId) + .toList(); + + TradingClearingRegistryListNewRequest tcrListNew = new TradingClearingRegistryListNewRequest(); + tcrListNew.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + tcrListNew.setCurrencyAccountList(accIds); + List tkrListIds = tradingClearingRegistryListFacade.createTradingClearingRegistryList(tcrListNew, null); + Optional tkrReq = gatewayRequestCreator.createTkrGatewayReq(tradingClearingRegistry); + tkrReq.ifPresent(tkr -> tkrRequest.getTkrs().add(tkr)); + } + } + private RequestInfoUpdate clientCodeNewFromBackend(BaseRequest clientCodeNewRequest) { RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(clientCodeNewRequest); if (requestInfoUpdate != null) return requestInfoUpdate; @@ -193,6 +243,17 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali return null; } + private List makeErrorTkrResponse(Map eksAccountsAfterValidation) { + return eksAccountsAfterValidation.entrySet() + .stream() + .map(tkrAccountValidationResultEntry -> + gatewayRequestCreator.crateErrorTkrToGateway( + tkrAccountValidationResultEntry.getKey(), + tkrAccountValidationResultEntry.getValue().errorMsg() + )) + .toList(); + } + private RequestInfoUpdate makeErrorResponse(BaseRequest clientCodeNewRequest, ValidationResult validationResult) { RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/validators/ClientCodeValidator.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/validators/ClientCodeValidator.java index 516519748..29f28f266 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/validators/ClientCodeValidator.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/validators/ClientCodeValidator.java @@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.spcex.clearing.account.model.ValidationResult; import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest; @@ -25,6 +26,7 @@ public class ClientCodeValidator { private final Function clientCodeDeleteRequestValidator; private final Function tkrAccountsGatewayValidator; private final Function tkrEksAccountsGatewayValidator; + private final Function updateTkrEksAccountsGatewayValidator; private final IMessageResolver messageResolver; public ClientCodeValidator(UserRoleVerification userRoleVerification, @@ -33,6 +35,7 @@ public class ClientCodeValidator { Function clientCodeDeleteRequestValidator, Function tkrAccountsGatewayValidator, Function tkrEksAccountsGatewayValidator, + @Qualifier("updateTkrEksAccountsGatewayValidator") Function updateTkrEksAccountsGatewayValidator, IMessageResolver messageResolver) { this.userRoleVerification = userRoleVerification; this.clientCodeNewRequestValidator = clientCodeNewRequestValidator; @@ -40,6 +43,7 @@ public class ClientCodeValidator { this.clientCodeDeleteRequestValidator = clientCodeDeleteRequestValidator; this.tkrAccountsGatewayValidator = tkrAccountsGatewayValidator; this.tkrEksAccountsGatewayValidator = tkrEksAccountsGatewayValidator; + this.updateTkrEksAccountsGatewayValidator = updateTkrEksAccountsGatewayValidator; this.messageResolver = messageResolver; } @@ -51,6 +55,10 @@ public class ClientCodeValidator { return standardValidation(tkrEksAccountsGatewayValidator, gatewayAccountRequest); } + public ValidationResult checkGatewayUpdateRequestWithEksAcc(TkrAccount gatewayAccountRequest) { + return standardValidation(updateTkrEksAccountsGatewayValidator, gatewayAccountRequest); + } + public ValidationResult checkBackendNewRequest(ClientCodeNewRequest clientCodeNewRequest) { return standardValidation(clientCodeNewRequestValidator, clientCodeNewRequest); } diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayUpdateEksClientCodeValidationRule.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayUpdateEksClientCodeValidationRule.java new file mode 100644 index 000000000..9e23868f2 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayUpdateEksClientCodeValidationRule.java @@ -0,0 +1,82 @@ +package ru.spcex.clearing.account.validation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistryList; +import ru.spcex.clearing.account.errors.AccountError; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.account.TkrAccount; +import ru.spcex.clearing.platform.messaging.domain.cud.gateway.MoneyAccountMsgRequest; +import ru.spcex.platform.enumeration.AccountType; +import ru.spcex.platform.enumeration.CurrencyCode; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +public enum GatewayUpdateEksClientCodeValidationRule implements IValidationRule> { + + TkrIsPresent() { + @Override + public Optional validate(ImdgValidationContext context) { + TkrAccount validatedObject = context.getValidatedObject(); + Imdg tkrImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); + ImdgPredicateBuilder predicate = tkrImdg.predicateBuilder(); + String trkCode = validatedObject.getTkrCode(); + TradingClearingRegistry existTkr = tkrImdg.getSingleObjectByPredicate( + predicate.equals("code", trkCode) + ); + if (existTkr == null) { + return of(AccountError.TradingClearingRegistryNotFound, trkCode); + } + context.storeObject(ClientCodeStoreObjects.TRADING_CLEARING_REGISTRY, existTkr); + return empty(); + } + }, + AccountsNotLinkedToTkr() { + @Override + public Optional validate(ImdgValidationContext context) { + TkrAccount validatedObject = context.getValidatedObject(); + Imdg accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); + Imdg tkrList = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class); + ImdgPredicateBuilder predicateBuilder = accountImdg.predicateBuilder(); + List accounts = validatedObject.getMoneyAccounts().stream() + .filter(moneyAccountMsgRequest -> + moneyAccountMsgRequest.getStatus().equals("ADD") + && !CurrencyCode.RUB.equalsByKey(moneyAccountMsgRequest.getCurrCode())) + .toList(); + List clrnAccounts = new ArrayList<>(); + for (MoneyAccountMsgRequest request : accounts) { + Account account = accountImdg.getFirstObjectByPredicate( + predicateBuilder.and( + predicateBuilder.equals("account", request.getAccount()), + predicateBuilder.equals("accountType", AccountType.Clrn.getKey()) + ) + ); + if (account == null) { + //todo пропускать такие счета и не выдавать ошибку? just continue; + return of(AccountError.AccountNotFound, request.getAccount()); + } + TradingClearingRegistryList tkrListByAccount = tkrList.getSingleObjectByPredicate( + predicateBuilder.equals("accountId", account.getId()) + ); + if (tkrListByAccount != null) { + //todo пропускать такие счета и не выдавать ошибку? just continue; + return of(AccountError.AccountForTradingClearingRegistryAlreadyUsed, account.getId()); + } + clrnAccounts.add(account); + } + context.storeObject(ClientCodeStoreObjects.CLRN_ACCS, clrnAccounts); + return empty(); + } + } + ; + + private static final Logger log = LoggerFactory.getLogger(GatewayUpdateEksClientCodeValidationRule.class); + }