From a129db1c98d75bd2de83823d077da319ad4cd8a3 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Mon, 25 May 2026 12:29:11 +0300 Subject: [PATCH] http://jira.mfd.msk:8088/browse/CLS-1023 --- .../ClientCodeValidationConfig.java | 5 +- .../service/v2/facade/AccountFacade.java | 118 ++++++++++++------ .../service/v2/facade/ClientCodeFacade.java | 28 +++-- .../listeners/ClientCodeMessageListener.java | 58 +++------ .../GatewayEksClientCodeValidationRule.java | 38 ++++-- 5 files changed, 143 insertions(+), 104 deletions(-) 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 b4897e7ea..b008c5538 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 @@ -197,9 +197,10 @@ public class ClientCodeValidationConfig { addImdg.accept(IMDGDistributedNames.Map_DepoAccount); return new ValidatorImpl<>(context, FieldRequiredRule.instance("client_code", TkrAccount::getClientCode, AccountError.RequiredFieldEmpty), + GatewayEksClientCodeValidationRule.RubAccountPresent, GatewayEksClientCodeValidationRule.CompanyPresent, -// GatewayClientCodeValidationRule.AllAccountsPresent, - GatewayEksClientCodeValidationRule.DepoAccountsPresent + GatewayEksClientCodeValidationRule.DepoAccountsPresent, + GatewayEksClientCodeValidationRule.TcrIsNotPresent // GatewayClientCodeValidationRule.TcrIsNotPresent, // GatewayClientCodeValidationRule.TcrListIsNotPresent ); diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/AccountFacade.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/AccountFacade.java index 0ecc9badf..7b9182e77 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/AccountFacade.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/AccountFacade.java @@ -7,7 +7,9 @@ import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.account.ClearingAccount; import ru.clearing.classes.statics.data.account.InformationAccount; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.misc.Currency; @@ -25,6 +27,7 @@ import ru.spcex.platform.imdg.api.ImdgId; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; +import ru.spcex.platform.utils.collection.Pair; @Service public class AccountFacade implements IClearingFacade { @@ -33,6 +36,7 @@ public class AccountFacade implements IClearingFacade { private final ImdgProvider imdgProvider; private final Imdg accountImdg; private final Imdg informationAccountImdg; + private final Imdg clearingAccountImdg; private final Imdg currencyImdg; private final InformationAccountService informationAccountService; private final AccountHelper accountHelper; @@ -48,6 +52,7 @@ public class AccountFacade implements IClearingFacade { this.imdgProvider = imdgProvider; this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class); this.informationAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_InformationAccount, InformationAccount.class); + this.clearingAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class); this.currencyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Currency, Currency.class); this.informationAccountService = informationAccountService; this.accountHelper = accountHelper; @@ -55,62 +60,95 @@ public class AccountFacade implements IClearingFacade { this.tradingClearingRegistryListFacade = tradingClearingRegistryListFacade; } - public Optional createInfoAccount(MoneyAccountMsgRequest moneyAccountMsgRequest, Company company) { + public Optional> createAccountWithSpecificType(MoneyAccountMsgRequest moneyAccountMsgRequest, Company company) { String currencyCode = moneyAccountMsgRequest.getCurrCode() == null ? CurrencyCode.RUB.getKey() : moneyAccountMsgRequest.getCurrCode(); - ImdgPredicateBuilder predicateBuilder = currencyImdg.predicateBuilder(); - Currency currency = currencyImdg.getFirstObjectByPredicate( - predicateBuilder.equals("currencyCode", currencyCode) - ); - - Long currencyCodeId = CurrencyCode.RUB.getKey().equals(currencyCode) ? 810 : currency.getId(); Instant now = Instant.now(); - Account infoAccount = new Account(); - infoAccount.setCompanyId(company.getId()); - infoAccount.setAccount(moneyAccountMsgRequest.getEks_account()); - - ImdgPredicateBuilder pb = accountImdg.predicateBuilder(); - ImdgPredicate andPredicate = pb.and( - pb.equals("accountType", AccountType.Anlt.getKey()), - pb.equals("currency", currency.getCurrencyCode()) - ); - Collection accountsAnlt = accountImdg.getCollectionObjectsByPredicate(andPredicate); - if (accountsAnlt.isEmpty()) { - log.warn("Account with {} not exist.", andPredicate); - } else if (accountsAnlt.size() > 1) { - log.warn("Account for companyId 1 and accountType=ANLT contains multiply elements, use first"); + AccountType accountType = StringUtils.hasText(moneyAccountMsgRequest.getAccount()) ? AccountType.Clrn : + StringUtils.hasText(moneyAccountMsgRequest.getEks_account()) ? AccountType.Info : null; + if (accountType == null) { + return Optional.empty(); } - Account anltAccount = accountsAnlt.iterator().next(); - String specialAnltAccId = anltAccount.getAccount().substring(anltAccount.getAccount().length() - 4); - Long infoSequenceId = informationAccountService.accountNextId(currencyCode, currencyCodeId); - String accountValue = informationAccountService.generateInfoAccount(currencyCodeId, infoSequenceId, specialAnltAccId); - log.trace("New info-account SequenceId={} account={}", infoSequenceId, accountValue); - infoAccount.setAccount(accountValue); - infoAccount.setAccountType(AccountType.Info.getKey()); - infoAccount.setCurrency(currencyCode); - infoAccount.setStatus(WorkflowStatus.Active.getKey()); - infoAccount.setCreated(now); - infoAccount.setUpdated(now); - accountHelper.fillAccountFromRelation(infoAccount, null, false); - accountImdg.insert(infoAccount); + String accountValue = defineAccountValByType(accountType, moneyAccountMsgRequest, currencyCode); + Account account = new Account(); + account.setCompanyId(company.getId()); + account.setAccount(accountValue); + account.setAccountType(accountType.getKey()); + account.setCurrency(currencyCode); + account.setStatus(WorkflowStatus.Active.getKey()); + account.setCreated(now); + account.setUpdated(now); + accountHelper.fillAccountFromRelation(account, null, false); + accountImdg.insert(account); + + Long specificAccId; + switch (accountType) { + case Clrn -> specificAccId = makeClrnPart(account).getAccountId(); + case Info -> specificAccId = makeInfoPart(account).getAccountId(); + default -> throw new IllegalArgumentException("Unknown accountType: " + accountType); + } + return Optional.of(new Pair<>(specificAccId, currencyCode)); + } + + private String defineAccountValByType(AccountType accountType, MoneyAccountMsgRequest moneyAccountMsgRequest, + String currencyCode) { + if (AccountType.Clrn == accountType) { + return moneyAccountMsgRequest.getAccount(); + } else if (AccountType.Info == accountType) { + ImdgPredicateBuilder predicateBuilder = currencyImdg.predicateBuilder(); + Currency currency = currencyImdg.getFirstObjectByPredicate( + predicateBuilder.equals("currencyCode", currencyCode) + ); + Long currencyCodeId = CurrencyCode.RUB.getKey().equals(currencyCode) ? 810 : currency.getId(); + + ImdgPredicateBuilder pb = accountImdg.predicateBuilder(); + ImdgPredicate andPredicate = pb.and( + pb.equals("accountType", AccountType.Anlt.getKey()), + pb.equals("currency", currencyCode) + ); + Collection accountsAnlt = accountImdg.getCollectionObjectsByPredicate(andPredicate); + if (accountsAnlt.isEmpty()) { + log.warn("Account with {} not exist.", andPredicate); + } else if (accountsAnlt.size() > 1) { + log.warn("Account for companyId 1 and accountType=ANLT contains multiply elements, use first"); + } + Account anltAccount = accountsAnlt.iterator().next(); + String specialAnltAccId = anltAccount.getAccount().substring(anltAccount.getAccount().length() - 4); + Long infoSequenceId = informationAccountService.accountNextId(currencyCode, currencyCodeId); + String accountValue = informationAccountService.generateInfoAccount(currencyCodeId, infoSequenceId, specialAnltAccId); + log.trace("New info-account SequenceId={} account={}", infoSequenceId, accountValue); + return accountValue; + } + return null; + } + + private InformationAccount makeInfoPart(Account account) { InformationAccount infoAcc = new InformationAccount(); - infoAcc.setAccountId(infoAccount.getId()); + infoAcc.setAccountId(account.getId()); Account firstAccountAntl = accountImdg.getFirstObjectByFieldValues(Map.of( "companyId", Sender.One.getId(), "accountType", AccountType.Anlt.getKey(), - "currency", infoAccount.getCurrency() + "currency", account.getCurrency() )); if (firstAccountAntl == null) { - log.warn("Can not find 1 ANTL {} account for fill information ClearingAccountId.", infoAccount.getCurrency()); + log.warn("Can not find 1 ANTL {} account for fill information ClearingAccountId.", account.getCurrency()); } else { infoAcc.setClearingAccountId(firstAccountAntl.getId()); } - infoAcc.setCompanyId(infoAccount.getCompanyId()); + infoAcc.setCompanyId(account.getCompanyId()); Long infoId = informationAccountImdg.insert(infoAcc); - log.debug("For account id={} make InformationAccount id={}", infoAccount.getId(), infoId); - return Optional.of(infoAcc); + log.debug("For account id={} make InformationAccount id={}", account.getId(), infoId); + return infoAcc; } + protected ClearingAccount makeClrnPart(Account account) { + ClearingAccount clnrAcc = new ClearingAccount(); + clnrAcc.setAccountId(account.getId()); + clnrAcc.setCompanyId(account.getCompanyId()); + Long clrnId = clearingAccountImdg.insert(clnrAcc); + log.debug("For account id={} make ClearingAccount id={}", account.getId(), clrnId); + return clnrAcc; + } public void lock() { // tradingClearingRegistryFacade.lock() // tradingClearingRegistryListFacade.lock() diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/ClientCodeFacade.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/ClientCodeFacade.java index 2cbc02773..7d4d9478b 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/ClientCodeFacade.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/ClientCodeFacade.java @@ -16,6 +16,7 @@ import ru.spcex.platform.enumeration.TradingClearingRegistryType; 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.predicate.ImdgPredicateBuilder; import ru.spcex.platform.utils.validation.IValidator; @Service @@ -61,17 +62,28 @@ public class ClientCodeFacade implements IClearingFacade { } { - ClientCode clientCode = new ClientCode(); - clientCode.setCreated(Instant.now()); - clientCode.setUpdated(clientCode.getCreated()); + ImdgPredicateBuilder predicateBuilder = clientCodeImdg.predicateBuilder(); + ClientCode clientCode = clientCodeImdg.getFirstObjectByPredicate( + predicateBuilder.and( + predicateBuilder.equals("companyId", request.getCompanyId()), + predicateBuilder.equals("code", request.getCode()), + predicateBuilder.equals("tradingClearingRegistryId", tradingClearingRegistry.getId()) + ) + ); + if (clientCode == null) { + clientCode = new ClientCode(); + clientCode.setCreated(Instant.now()); + clientCode.setUpdated(clientCode.getCreated()); - clientCode.setCompanyId(request.getCompanyId()); - clientCode.setCode(request.getCode()); + clientCode.setCompanyId(request.getCompanyId()); + clientCode.setCode(request.getCode()); + clientCode.setTradingClearingRegistryId(tradingClearingRegistry.getId()); // clientCode.setMoneyAccountId(request.getMoneyAccountId()); // clientCode.setDepoAccountId(request.getDepoAccountId()); - clientCode.setStatus(request.getStatus()); - clientCodeImdg.insert(clientCode); - log.debug("successfully processed, new clientCode id {}", clientCode.getId()); + clientCode.setStatus(request.getStatus()); + clientCodeImdg.insert(clientCode); + log.debug("successfully processed, new clientCode id {}", clientCode.getId()); + } } } 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 72d1f6c6a..8ebe5bdf6 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 @@ -14,7 +14,6 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.account.Account; import ru.clearing.classes.statics.data.account.DepoAccount; -import ru.clearing.classes.statics.data.account.InformationAccount; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; import ru.spcex.clearing.account.model.ValidationResult; @@ -42,6 +41,7 @@ import ru.spcex.platform.enumeration.CurrencyCode; import ru.spcex.platform.enumeration.TradingClearingRegistryType; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.collection.Pair; import ru.spcex.platform.utils.validation.IValidator; @Service @@ -106,27 +106,8 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali AtomicBoolean isAnyoneInvalid = new AtomicBoolean(false); Map eksAccountsAfterValidation = new HashMap<>(); Map accountsAfterValidation = new HashMap<>(); - List withAccount = gatewayRequest.getAccounts().stream() - .filter(tkrAccount -> tkrAccount.getMoneyAccounts() != null && - tkrAccount.getMoneyAccounts().stream() - .anyMatch(moneyAccountMsgRequest -> moneyAccountMsgRequest.getAccount() != null)) - .toList(); - List withEksAccount = gatewayRequest.getAccounts().stream() - .filter(tkrAccount -> tkrAccount.getMoneyAccounts() != null && - tkrAccount.getMoneyAccounts().stream() - .anyMatch(moneyAccountMsgRequest -> moneyAccountMsgRequest.getEks_account() != null)) - .toList(); - withAccount.forEach(tkrAccount -> { - ValidationResult validationResult = clientCodeValidator.checkGatewayRequest(tkrAccount); - if (!validationResult.isValid()) { - log.debug("Validation failed for tkr.client_code {}", tkrAccount.getClientCode()); - isAnyoneInvalid.set(true); - } - accountsAfterValidation.put(tkrAccount, validationResult); - }); - - withEksAccount.forEach(tkrAccount -> { + gatewayRequest.getAccounts().forEach(tkrAccount -> { ValidationResult validationResult = clientCodeValidator.checkGatewayRequestWithEksAcc(tkrAccount); if (!validationResult.isValid()) { log.debug("Validation failed for tkr.client_code {}", tkrAccount.getClientCode()); @@ -137,15 +118,6 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali if (isAnyoneInvalid.get()) { log.debug("Create error request to gateway service"); - - List tkrs = accountsAfterValidation.entrySet() - .stream() - .map(tkrAccountValidationResultEntry -> - gatewayRequestCreator.crateErrorTkrToGateway( - tkrAccountValidationResultEntry.getKey(), - tkrAccountValidationResultEntry.getValue().errorMsg() - )) - .toList(); List eksTkrs = eksAccountsAfterValidation.entrySet() .stream() .map(tkrAccountValidationResultEntry -> @@ -154,13 +126,10 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali tkrAccountValidationResultEntry.getValue().errorMsg() )) .toList(); - sendTkrRequest.getTkrs().addAll(tkrs); sendTkrRequest.getTkrs().addAll(eksTkrs); kafkaSender.sendRequestToQueue(Consts.ACCOUNTS_TO_GATEWAY, sendTkrRequest); return null; } - - processAccount(accountsAfterValidation, gatewayRequest); processEksAccount(eksAccountsAfterValidation, gatewayRequest); kafkaSender.sendRequestToQueue(Consts.ACCOUNTS_TO_GATEWAY, sendTkrRequest); return null; @@ -213,28 +182,33 @@ public class ClientCodeMessageListener extends QueueConsumer implements Initiali IValidator validator = validationResult.validator(); Company company = validator.getStored(ClientCodeStoreObjects.COMPANY); Optional depoAccount = validator.getStored(ClientCodeStoreObjects.DEPO_ACCOUNT); - Long depoAccountId = depoAccount.map(DepoAccount::getId).orElse(null); - List accountIds = new ArrayList<>(); - List infoAccsId = new ArrayList<>(); + Long depoAccountId = depoAccount.map(DepoAccount::getAccountId).orElse(null); + List> accountIds = new ArrayList<>(); for (MoneyAccountMsgRequest account : tkrAccount.getMoneyAccounts()) { - Optional infoAccId = accountFacade.createInfoAccount(account, company); - if (infoAccId.isPresent()) { - accountIds.add(infoAccId.get().getAccountId()); - infoAccsId.add(infoAccId.get().getId()); + Optional> accId = accountFacade.createAccountWithSpecificType(account, company); + if (accId.isPresent()) { + accountIds.add(accId.get()); } else { log.error("Can't create info account for account: {}", tkrAccount.getClientCode()); } } + Optional rubMoneyAcc = accountIds.stream() + .filter(longStringPair -> CurrencyCode.RUB.equalsByKey(longStringPair.getSecond())) + .findFirst() + .map(Pair::getFirst); + List accIds = accountIds.stream() + .map(Pair::getFirst) + .toList(); ClientCodeNewRequest clientCodeNewRequest = new ClientCodeNewRequest(); log.debug("Creating new clientCode by tkr account: {}", tkrAccount.getClientCode()); clientCodeNewRequest.setCompanyId(company.getId()); clientCodeNewRequest.setCode(tkrAccount.getClientCode()); - clientCodeNewRequest.setMoneyAccountId(accountIds.get(0)); + clientCodeNewRequest.setMoneyAccountId(rubMoneyAcc.get()); clientCodeNewRequest.setDepoAccountId(depoAccountId); - clientCodeNewRequest.setCurrencyAccountList(accountIds); + clientCodeNewRequest.setCurrencyAccountList(accIds); clientCodeFacade.createClientCode(clientCodeNewRequest, validator, false); } } diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayEksClientCodeValidationRule.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayEksClientCodeValidationRule.java index e639a2ea9..181a01760 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayEksClientCodeValidationRule.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/GatewayEksClientCodeValidationRule.java @@ -1,21 +1,21 @@ package ru.spcex.clearing.account.validation; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; -import ru.clearing.classes.statics.data.account.Account; import ru.clearing.classes.statics.data.account.AccountSymbols; import ru.clearing.classes.statics.data.account.DepoAccount; import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; 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.CurrencyCode; +import ru.spcex.platform.enumeration.Status; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; import ru.spcex.platform.imdg.validation.ImdgValidationContext; @@ -44,7 +44,7 @@ public enum GatewayEksClientCodeValidationRule implements IValidationRule validate(ImdgValidationContext context) { TkrAccount validatedObject = context.getValidatedObject(); @@ -56,15 +56,6 @@ public enum GatewayEksClientCodeValidationRule implements IValidationRule imdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); - Map accountByCurrency = new HashMap<>(); - for (MoneyAccountMsgRequest moneyAccountMsg : accountList) { - //если в списке есть eksAccount то проверим, что его нет в системе - if (!StringUtils.hasText(moneyAccountMsg.getEks_account())) { - return of(AccountError.RequiredFieldEmpty, "eks_account"); - } - } - context.storeObject(ClientCodeStoreObjects.MAPPED_TO_CURRENCY_ACCOUNTS, accountByCurrency); return Optional.empty(); } }, @@ -99,6 +90,29 @@ public enum GatewayEksClientCodeValidationRule implements IValidationRule validate(ImdgValidationContext context) { + Optional depoAccountOpt = context.getStoredObject(ClientCodeStoreObjects.DEPO_ACCOUNT); + if (depoAccountOpt.isEmpty()) { + return empty(); + } + DepoAccount depoAccount = depoAccountOpt.get(); + Imdg imdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, + TradingClearingRegistry.class); + TradingClearingRegistry tcr = imdg.getFirstObjectByFieldValues( + Map.of( + "depoAccountId", depoAccount.getId(), + "status", Status.Active.getKey() + ) + ); + if (tcr != null) { + return of(AccountError.TradingClearingRegistryAlreadyExist, tcr.getCode(), "code"); + } + return Optional.empty(); + } }; private static final Logger log = LoggerFactory.getLogger(GatewayEksClientCodeValidationRule.class);