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 4c8db44a6..2117e59f8 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 @@ -1,5 +1,6 @@ package ru.spcex.clearing.account.config.validation; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -13,8 +14,10 @@ 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.registry.TradingClearingRegistry; import ru.clearing.platform.dictionary.ServiceStatusDictionary; import ru.spcex.clearing.account.errors.AccountError; +import ru.spcex.clearing.account.validation.ClientCodeStoreObjects; 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; @@ -27,6 +30,7 @@ import ru.spcex.clearing.validation.common.rules.IdPresentRule; import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.enumeration.CompanySymbol; 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.ImdgPredicate; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; @@ -50,45 +54,149 @@ public class ClientCodeValidationConfig { addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry); addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary); return new ValidatorImpl<>(context, - FieldRequiredRule.instance("companyId", ClientCodeNewRequest::getCompanyId, AccountError.RequiredFieldEmpty), - IdPresentRule.instance("companyId", - ClientCodeNewRequest::getCompanyId, - IMDGDistributedNames.Map_Company, - Company.class, - AccountError.RequiredFieldEmpty, - AccountError.CompanyNotFound), + FieldRequiredRule.instance("companyId", ClientCodeNewRequest::getCompanyId, AccountError.RequiredFieldEmpty), + IdPresentRule.instance("companyId", + ClientCodeNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + AccountError.RequiredFieldEmpty, + AccountError.CompanyNotFound), - IdPresentRule.instance("moneyAccountId", - ClientCodeNewRequest::getMoneyAccountId, - IMDGDistributedNames.Map_Account, - Account.class, - AccountError.RequiredFieldEmpty, - AccountError.AccountNotFound, - false, - acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) - ? null : AccountError.AccountNotFound - ), - IdPresentRule.instance("depoAccountId", - ClientCodeNewRequest::getDepoAccountId, - IMDGDistributedNames.Map_Account, - Account.class, - AccountError.RequiredFieldEmpty, - AccountError.AccountNotFound, - false, - acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) - ? null : AccountError.AccountNotFound - ), - new ExistAllCurrencyAccountId<>("currencyAccountList", - ClientCodeNewRequest::getCurrencyAccountList - ), + IdPresentRule.instance("moneyAccountId", + ClientCodeNewRequest::getMoneyAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + AccountError.RequiredFieldEmpty, + AccountError.AccountNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : AccountError.AccountNotFound + ), + IdPresentRule.instance("depoAccountId", + ClientCodeNewRequest::getDepoAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + AccountError.RequiredFieldEmpty, + AccountError.AccountNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : AccountError.AccountNotFound + ), + new ExistAllCurrencyAccountId<>("currencyAccountList", + ClientCodeNewRequest::getCurrencyAccountList + ), - DictionaryPresentRule.instance("stauts", - ClientCodeNewRequest::getStatus, - IMDGDistributedNames.Map_ServiceStatusDictionary, - ServiceStatusDictionary.class, - AccountError.RequiredFieldEmpty, - AccountError.DictionaryNotFound, - false) + DictionaryPresentRule.instance("stauts", + ClientCodeNewRequest::getStatus, + IMDGDistributedNames.Map_ServiceStatusDictionary, + ServiceStatusDictionary.class, + AccountError.RequiredFieldEmpty, + AccountError.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_ServiceStatusDictionary); + return new ValidatorImpl>(context, + IdPresentRule.instance("id", + ClientCodeUpdateRequest::getId, + IMDGDistributedNames.Map_ClientCode, + ClientCode.class, + AccountError.RequiredFieldEmpty, + AccountError.RecordNotFound + ), + + FieldRequiredRule.instance("companyId", ClientCodeUpdateRequest::getCompanyId, AccountError.RequiredFieldEmpty), + IdPresentRule.instance("companyId", + ClientCodeUpdateRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + AccountError.RequiredFieldEmpty, + AccountError.CompanyNotFound), + + IdPresentRule.instance("moneyAccountId", + ClientCodeUpdateRequest::getMoneyAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + AccountError.RequiredFieldEmpty, + AccountError.AccountNotFound, + true, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : AccountError.AccountNotFound + ), + IdPresentRule.instance("depoAccountId", + ClientCodeUpdateRequest::getDepoAccountId, + IMDGDistributedNames.Map_Account, + Account.class, + AccountError.RequiredFieldEmpty, + AccountError.AccountNotFound, + false, + acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) + ? null : AccountError.AccountNotFound + ), + new ExistAllCurrencyAccountId<>("currencyAccountList", + ClientCodeUpdateRequest::getCurrencyAccountList + ), + + DictionaryPresentRule.instance("stauts", + ClientCodeUpdateRequest::getStatus, + IMDGDistributedNames.Map_ServiceStatusDictionary, + ServiceStatusDictionary.class, + AccountError.RequiredFieldEmpty, + AccountError.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_ClientCode); + return new ValidatorImpl<>(context, +// FieldRequiredRule.instance("id", CommonDeleteRequest::getId, CompanyErrors.RequiredFieldEmpty), + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_ClientCode, + ClientCode.class, + AccountError.RequiredFieldEmpty, + AccountError.RecordNotFound) + ); + }; + } + + @Bean("tkrAccountsGatewayValidator") + public Function tkrAccountsGatewayValidator(Map> imdgForValidation) { + return tkrGatewayRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(tkrGatewayRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_CompanySymbols); + addImdg.accept(IMDGDistributedNames.Map_Account); + addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry); + return new ValidatorImpl<>(context, + new ExistCompanyByUuid<>("companySymbolValue", + TkrAccount::getCompanyId), + new ExistAccountByValue<>("account", + TkrAccount::getMoneyAccounts), + new ExistDepoAccountByValue<>("depo_account", + TkrAccount::getDepoAccount), + new ExistTcrByCode<>("tcr_code", + TkrAccount::getTkrCode) ); }; } @@ -110,7 +218,7 @@ public class ClientCodeValidationConfig { return empty(); // необязательное поле } Imdg imdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); - for (Long id:ids) { + for (Long id : ids) { if (id == null) { // null значения в массиве не ожидаются return of(AccountError.RequiredFieldEmpty, fieldName); } @@ -128,6 +236,43 @@ public class ClientCodeValidationConfig { } } + public static class ExistTcrByCode implements IValidationRule> { + String fieldName; + Function codeGetter; + + public ExistTcrByCode(String fieldName, Function codeGetter) { + this.fieldName = fieldName; + this.codeGetter = codeGetter; + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + String tcrCode = codeGetter.apply(validatedObject); + if (!StringUtils.hasText(tcrCode)) { + return of(AccountError.RequiredFieldEmpty, fieldName); + } + Imdg imdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, + TradingClearingRegistry.class); + + TradingClearingRegistry tcr = imdg.getFirstObjectByFieldValues( + Map.of( + "code", tcrCode, + "status", Status.Active.getKey() + ) + ); + if (tcr != null) { + return of(AccountError.TCR_ALREADY_EXIST_GTW, fieldName); + } + return Optional.empty(); + } + + @Override + public String ruleName() { + return getClass().getSimpleName() + "{" + fieldName + "}"; + } + } + public static class ExistCompanyByUuid implements IValidationRule> { String fieldName; Function symbolCodeGetter; @@ -151,9 +296,17 @@ public class ClientCodeValidationConfig { "companySymbolValue", symbolCodeValue ) ); - if (companySymbols == null) { // null значения в массиве не ожидаются + if (companySymbols == null) { return of(AccountError.COMPANY_NOT_FOUND_GTW, fieldName); } + + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + Company company = companyImdg.getSingleObjectByID(companySymbols.getCompanyId()); + if (company == null) { + return of(AccountError.COMPANY_NOT_FOUND_GTW, fieldName); + } + + context.storeObject(ClientCodeStoreObjects.COMPANY, company); return Optional.empty(); } @@ -179,7 +332,12 @@ public class ClientCodeValidationConfig { if (accountList == null || accountList.isEmpty()) { return of(AccountError.RequiredFieldEmpty, fieldName); } + List currencies = accountList.stream().map(MoneyAccountMsgRequest::getCurrCode).toList(); + if (!currencies.contains(CurrencyCode.RUB.getKey())) { + return of(AccountError.RequiredFieldEmpty, fieldName); + } Imdg imdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); + Map accountByCurrency = new HashMap<>(); for (MoneyAccountMsgRequest moneyAccountMsg : accountList) { ImdgPredicateBuilder predicateBuilder = imdg.predicateBuilder(); ImdgPredicate currencyPredicate; @@ -198,7 +356,9 @@ public class ClientCodeValidationConfig { if (account == null) { return of(AccountError.ACCOUNT_NOT_FOUND_GTW, moneyAccountMsg.getAccount(), fieldName); } + accountByCurrency.put(account.getCurrency(), account); } + context.storeObject(ClientCodeStoreObjects.MAPPED_TO_CURRENCY_ACCOUNTS, accountByCurrency); return Optional.empty(); } @@ -208,103 +368,40 @@ public class ClientCodeValidationConfig { } } - @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_ServiceStatusDictionary); - return new ValidatorImpl>(context, - IdPresentRule.instance("id", - ClientCodeUpdateRequest::getId, - IMDGDistributedNames.Map_ClientCode, - ClientCode.class, - AccountError.RequiredFieldEmpty, - AccountError.RecordNotFound - ), + public static class ExistDepoAccountByValue implements IValidationRule> { + String fieldName; + Function depoAccountGetter; - FieldRequiredRule.instance("companyId", ClientCodeUpdateRequest::getCompanyId, AccountError.RequiredFieldEmpty), - IdPresentRule.instance("companyId", - ClientCodeUpdateRequest::getCompanyId, - IMDGDistributedNames.Map_Company, - Company.class, - AccountError.RequiredFieldEmpty, - AccountError.CompanyNotFound), + public ExistDepoAccountByValue(String fieldName, Function accountsListValueGetter) { + this.fieldName = fieldName; + this.depoAccountGetter = depoAccountGetter; + } - IdPresentRule.instance("moneyAccountId", - ClientCodeUpdateRequest::getMoneyAccountId, - IMDGDistributedNames.Map_Account, - Account.class, - AccountError.RequiredFieldEmpty, - AccountError.AccountNotFound, - true, - acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) - ? null : AccountError.AccountNotFound - ), - IdPresentRule.instance("depoAccountId", - ClientCodeUpdateRequest::getDepoAccountId, - IMDGDistributedNames.Map_Account, - Account.class, - AccountError.RequiredFieldEmpty, - AccountError.AccountNotFound, - false, - acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId()) - ? null : AccountError.AccountNotFound - ), - new ExistAllCurrencyAccountId<>("currencyAccountList", - ClientCodeUpdateRequest::getCurrencyAccountList - ), + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + String depoAccountVal = depoAccountGetter.apply(validatedObject); + if (!StringUtils.hasText(depoAccountVal)) { + context.storeObject(ClientCodeStoreObjects.DEPO_ACCOUNT,Optional.empty()); + return empty(); + } - DictionaryPresentRule.instance("stauts", - ClientCodeUpdateRequest::getStatus, - IMDGDistributedNames.Map_ServiceStatusDictionary, - ServiceStatusDictionary.class, - AccountError.RequiredFieldEmpty, - AccountError.DictionaryNotFound, - false) + Imdg imdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); + Account depoAccount = imdg.getFirstObjectByFieldValues( + Map.of("account", depoAccountVal) ); - }; - } + if (depoAccount == null) { + context.storeObject(ClientCodeStoreObjects.DEPO_ACCOUNT,Optional.empty()); + return of(AccountError.DEPO_ACCOUNT_NOT_FOUND_GTW, fieldName); + } - @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_ClientCode); - return new ValidatorImpl<>(context, -// FieldRequiredRule.instance("id", CommonDeleteRequest::getId, CompanyErrors.RequiredFieldEmpty), - IdPresentRule.instance("id", - CommonDeleteRequest::getId, - IMDGDistributedNames.Map_ClientCode, - ClientCode.class, - AccountError.RequiredFieldEmpty, - AccountError.RecordNotFound) - ); - }; - } + context.storeObject(ClientCodeStoreObjects.DEPO_ACCOUNT, depoAccount); + return Optional.empty(); + } - @Bean("tkrAccountsGatewayValidator") - public Function tkrAccountsGatewayValidator(Map> imdgForValidation) { - return tkrGatewayRequest -> { - ImdgValidationContext context = new ImdgValidationContext<>(); - context.setValidatedObject(tkrGatewayRequest); - Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); - addImdg.accept(IMDGDistributedNames.Map_CompanySymbols); - addImdg.accept(IMDGDistributedNames.Map_Account); - addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry); - return new ValidatorImpl<>(context, - new ExistCompanyByUuid<>("companySymbolValue", - TkrAccount::getCompanyId), - new ExistAccountByValue<>("account", - TkrAccount::getMoneyAccounts) - ); - }; + @Override + public String ruleName() { + return getClass().getSimpleName() + "{" + fieldName + "}"; + } } } diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/errors/AccountError.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/errors/AccountError.java index 61169108c..034b52630 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/errors/AccountError.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/errors/AccountError.java @@ -29,6 +29,8 @@ public enum AccountError implements IErrorEnumId { TCR_NOT_FOUND_GTW(5028L), ACCOUNT_NOT_FOUND_GTW(5029L), COMPANY_NOT_FOUND_GTW(5030L), + TCR_ALREADY_EXIST_GTW(5031L), + DEPO_ACCOUNT_NOT_FOUND_GTW(5032L), TradingClearingRegistryNotFound(3022L), CurrencyNotFound(1016L), ; diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/model/ValidationResult.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/model/ValidationResult.java new file mode 100644 index 000000000..dfd6c4b80 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/model/ValidationResult.java @@ -0,0 +1,12 @@ +package ru.spcex.clearing.account.model; + +import java.util.Optional; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; + +public record ValidationResult(IValidator validator, Optional error, Optional errorMsg) { + public boolean isValid() { + return error.isEmpty(); + } +} + diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/ClientCodeService.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/ClientCodeService.java index d0c00120d..a6457c252 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/ClientCodeService.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/ClientCodeService.java @@ -134,9 +134,10 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean callback(ClientCodeNewRequest.class) .setFunction(this::clientCodeNew) .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW, callbacks::put); - callback(TkrAccountsGatewayRequest.class) - .setFunction(this::clientCodeNewFromGateway) - .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW_FROM_GATEWAY, callbacks::put); + //note переехало в ClientCodeMessageListener[новая версия сервиса] +// callback(TkrAccountsGatewayRequest.class) +// .setFunction(this::clientCodeNewFromGateway) +// .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW_FROM_GATEWAY, callbacks::put); callback(ClientCodeNewRequest.class) .setFunction(this::clientCodeNewFromApiUmCompany) .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW_UM_COMPANY, callbacks::put); @@ -513,7 +514,7 @@ public class ClientCodeService extends QueueConsumer implements InitializingBean query.put("depoAccountId", depoAccountId); } TradingClearingRegistry result = tradingClearingRegistryMap.getFirstObjectByFieldValues(query); - log.trace("TradingClearingRegistry by: {}; {}found", query, result == null ? "not " : ""); + log.trace("TradingClearingRegistry by: {}; {} found", query, result == null ? "not" : ""); return result; } diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/GatewayRequestCreator.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/GatewayRequestCreator.java new file mode 100644 index 000000000..9ab1f9844 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/GatewayRequestCreator.java @@ -0,0 +1,130 @@ +package ru.spcex.clearing.account.service.v2; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +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.ClientCode; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.company.CompanySymbols; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistryList; +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.clearing.platform.messaging.domain.cud.gateway.MoneyAccountMsgResponse; +import ru.spcex.clearing.platform.messaging.domain.cud.gateway.Tkr; +import ru.spcex.platform.enumeration.CompanySymbol; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.TradingClearingRegistryType; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; + +@Service +public class GatewayRequestCreator { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ImdgProvider imdgProvider; + + public GatewayRequestCreator(ImdgProvider imdgProvider) { + this.imdgProvider = imdgProvider; + } + + public Tkr crateErrorTkrToGateway(TkrAccount tkrAccount, Optional errorMsg) { + Tkr tkr = new Tkr(); + tkr.setTkrCode(tkrAccount.getTkrCode()); + tkr.setClientCode(tkrAccount.getClientCode()); + tkr.setCompanyId(tkrAccount.getCompanyId()); + tkr.setDepoAccount(tkrAccount.getDepoAccount()); + tkr.setMoneyAccounts(tkrAccount.getMoneyAccounts() + .stream() + .map(this::convertAccountToResponse) + .collect(Collectors.toList())); + errorMsg.ifPresent(tkr::setErrorMessage); + return tkr; + } + + public Tkr createTkrGatewayReq(TradingClearingRegistry tradingClearingRegistry) { + Tkr tkr = new Tkr(); + log.debug("Found TKR with id: {} and code: {}", tradingClearingRegistry.getId(), tradingClearingRegistry.getCode()); + Imdg companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + Imdg companySymbolsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); + Imdg clientCodeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class); + Imdg accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class); + Imdg tradingClearingRegistryListImdg = imdgProvider. + getImdg(IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class); + + Company company = companyImdg.getSingleObjectByID(tradingClearingRegistry.getCompanyId()); + CompanySymbols companySymbols = companySymbolsImdg.getSingleObjectByFieldValues( + Map.of( + "companySymbol", CompanySymbol.UUID.getKey(), + "companyId", company.getId() + ) + ); + + ClientCode clientCode = clientCodeImdg.getFirstObjectByFieldValues( + Map.of("tradingClearingRegistryId", tradingClearingRegistry.getId()) + ); + tkr.setCompanyId(companySymbols.getCompanySymbolValue()); + tkr.setTradingCode(Long.valueOf(company.getTradingCode())); + tkr.setTkrCode(tradingClearingRegistry.getCode()); + tkr.setTkrType(tradingClearingRegistry.getTradingClearingRegistryPurpose()); + tkr.setActive(Status.Active.equalsByKey(tradingClearingRegistry.getStatus())); + String accountType; + if (clientCode == null) { + if (TradingClearingRegistryType.Client_B.equalsByKey( + tradingClearingRegistry.getTradingClearingRegistryType())) { + accountType = "Клиентский общий"; + } else { + accountType = "Общий"; + } + } else { + tkr.setClientCode(clientCode.getCode()); + accountType = "Клиентский обособленный"; + } + tkr.setAccountTypeName(accountType); + if (tradingClearingRegistry.getDepoAccountId() != null) { + Account depoAccount = accountImdg.getSingleObjectByID(tradingClearingRegistry.getDepoAccountId()); + if (depoAccount != null) { + tkr.setDepoAccount(depoAccount.getAccount()); + } + } + { + if (tradingClearingRegistry.getMoneyAccountId() != null) { + Account moneyAccount = accountImdg.getSingleObjectByID(tradingClearingRegistry.getMoneyAccountId()); + MoneyAccountMsgResponse moneyAccountMsg = new MoneyAccountMsgResponse(); + moneyAccountMsg.setAccount(moneyAccount.getAccount()); + moneyAccountMsg.setCurrCode(StringUtils.hasText(moneyAccount.getCurrency()) ? moneyAccount.getCurrency() : "RUB"); + moneyAccountMsg.setActive(Status.Active.equalsByKey(moneyAccount.getStatus())); + tkr.getMoneyAccounts().add(moneyAccountMsg); + } + } + { + Collection tradingClearingRegistries = tradingClearingRegistryListImdg.getCollectionObjectsByFieldValues( + Map.of( + "tradingClearingRegistryId", tradingClearingRegistry.getId() + ) + ); + for (TradingClearingRegistryList tkrList : tradingClearingRegistries) { + Account additionalAcc = accountImdg.getSingleObjectByID(tkrList.getAccountId()); + MoneyAccountMsgResponse moneyAccountMsg = new MoneyAccountMsgResponse(); + moneyAccountMsg.setAccount(additionalAcc.getAccount()); + moneyAccountMsg.setCurrCode(StringUtils.hasText(additionalAcc.getCurrency()) ? additionalAcc.getCurrency() : "RUB"); + moneyAccountMsg.setActive(Status.Active.equalsByKey(additionalAcc.getStatus())); + tkr.getMoneyAccounts().add(moneyAccountMsg); + } + } + return tkr; + } + + private MoneyAccountMsgResponse convertAccountToResponse(MoneyAccountMsgRequest moneyAccountMsgRequest) { + MoneyAccountMsgResponse msgResponse = new MoneyAccountMsgResponse(); + msgResponse.setAccount(moneyAccountMsgRequest.getAccount()); + msgResponse.setCurrCode(moneyAccountMsgRequest.getCurrCode()); + return msgResponse; + } +} 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 new file mode 100644 index 000000000..459724ec2 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/ClientCodeFacade.java @@ -0,0 +1,90 @@ +package ru.spcex.clearing.account.service.v2.facade; + +import java.time.Instant; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.account.ClientCode; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.spcex.clearing.account.validation.ClientCodeStoreObjects; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryListNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest; +import ru.spcex.platform.classes.base.interfaces.IClearingFacade; +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.utils.validation.IValidator; + +@Service +public class ClientCodeFacade implements IClearingFacade { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ImdgId idGenerator; + private final ImdgProvider imdgProvider; + private final Imdg clientCodeImdg; + private final TradingClearingRegistryFacade tradingClearingRegistryFacade; + private final TradingClearingRegistryListFacade tradingClearingRegistryListFacade; + + public ClientCodeFacade(ImdgProvider imdgProvider, + TradingClearingRegistryFacade tradingClearingRegistryFacade, TradingClearingRegistryListFacade tradingClearingRegistryListFacade) { + this.idGenerator = imdgProvider.getImdgIdGenerator(); + this.imdgProvider = imdgProvider; + this.clientCodeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class); + this.tradingClearingRegistryFacade = tradingClearingRegistryFacade; + this.tradingClearingRegistryListFacade = tradingClearingRegistryListFacade; + } + + /** + * Создает clientCode, TCR и опционально TCRList, если указаны валюты. + */ + public void createClientCode(ClientCodeNewRequest request, IValidator validator) { + log.trace("Start process creating new client code"); + TradingClearingRegistry tradingClearingRegistry = validator.getStored(ClientCodeStoreObjects.TRADING_CLEARING_REGISTRY); + if (tradingClearingRegistry == null) { + log.debug("Trading Clearing Registry is not exist, creating..."); + { + TradingClearingRegistryNewRequest creationTcrRequest = new TradingClearingRegistryNewRequest(); + creationTcrRequest.setCompanyId(request.getCompanyId()); + creationTcrRequest.setMoneyAccountId(request.getMoneyAccountId()); + creationTcrRequest.setDepoAccountId(request.getDepoAccountId()); + creationTcrRequest.setTradingClearingRegistryType(TradingClearingRegistryType.Client_B.getKey()); + tradingClearingRegistry = tradingClearingRegistryFacade.createTradingClearingRegistry(creationTcrRequest, null); + } + } + { + if (request.getCurrencyAccountList() != null && !request.getCurrencyAccountList().isEmpty()) { + TradingClearingRegistryListNewRequest tcrListNew = new TradingClearingRegistryListNewRequest(); + tcrListNew.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + tcrListNew.setCurrencyAccountList(request.getCurrencyAccountList()); + List tkrListIds = tradingClearingRegistryListFacade.createTradingClearingRegistryList(tcrListNew, null); + } + } + + { + ClientCode clientCode = new ClientCode(); + clientCode.setCreated(Instant.now()); + clientCode.setUpdated(clientCode.getCreated()); + + clientCode.setCompanyId(request.getCompanyId()); + clientCode.setCode(request.getCode()); + clientCode.setMoneyAccountId(request.getMoneyAccountId()); + clientCode.setDepoAccountId(request.getDepoAccountId()); + clientCode.setStatus(request.getStatus()); + clientCodeImdg.insert(clientCode); + log.debug("successfully processed, new clientCode id {}", clientCode.getId()); + } + } + + public void lock(){ +// tradingClearingRegistryFacade.lock() +// tradingClearingRegistryListFacade.lock() + } + + public void unlock(){ +// tradingClearingRegistryFacade.lock() +// tradingClearingRegistryListFacade.lock() + } +} diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryFacade.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryFacade.java new file mode 100644 index 000000000..6fc946f8e --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryFacade.java @@ -0,0 +1,187 @@ +package ru.spcex.clearing.account.service.v2.facade; + +import java.time.Instant; +import java.util.Collection; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.account.ClearingAccount; +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.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.clearing.CreateRegistryRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.reports.NotificationRequest; +import ru.spcex.clearing.platform.messaging.serialization.LogFormatter; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +import ru.spcex.platform.enumeration.ServiceStatus; +import ru.spcex.platform.enumeration.TradingClearingRegistryPurpose; +import ru.spcex.platform.enumeration.TradingClearingRegistryType; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; +import ru.spcex.platform.utils.validation.IValidator; + +@Service +public class TradingClearingRegistryFacade { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ImdgProvider imdgProvider; + private final KafkaSender kafkaSender; + private final Imdg tradingClearingRegistryImdg; + private final Imdg depoAccountImdg; + private final Imdg clearingAccountImdg; + private final Imdg companyImdg; + + public TradingClearingRegistryFacade(ImdgProvider imdgProvider, + KafkaSender kafkaSender) { + this.imdgProvider = imdgProvider; + this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, + TradingClearingRegistry.class); + this.depoAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class); + this.clearingAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class); + this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + this.kafkaSender = kafkaSender; + } + + public TradingClearingRegistry createTradingClearingRegistry(TradingClearingRegistryNewRequest request, + IValidator validator) { + Long id = tradingClearingRegistryImdg.nextIDSequenceFor(); + TradingClearingRegistry tradingClearingRegistry = new TradingClearingRegistry(); + tradingClearingRegistry.setId(id); + tradingClearingRegistry.setCompanyId(request.getCompanyId()); + tradingClearingRegistry.setMoneyAccountId(request.getMoneyAccountId()); + tradingClearingRegistry.setDepoAccountId(request.getDepoAccountId()); + + DepoAccount depoAccount = request.getDepoAccountId() != null ? + depoAccountImdg.getFirstObjectByFieldValues(Map.of("accountId", request.getDepoAccountId())) : null; + ClearingAccount clearingAccount = request.getMoneyAccountId() != null ? + clearingAccountImdg.getFirstObjectByFieldValues(Map.of("accountId", request.getMoneyAccountId())) : null; + + if (request.getStatus() == null) { + tradingClearingRegistry.setStatus(ServiceStatus.Active.getKey()); + log.trace("TCR status in request not set. Use default: {}", tradingClearingRegistry.getStatus()); + } else { + tradingClearingRegistry.setStatus(request.getStatus()); + log.trace("TCR status in request set: {}", tradingClearingRegistry.getStatus()); + } + + String tradingRegistryType; + if (request.getTradingClearingRegistryType() != null) { + tradingRegistryType = request.getTradingClearingRegistryType(); + } else if (depoAccount != null) { + tradingRegistryType = depoAccount.getDepoAccountType(); + } else { + if (clearingAccount != null) tradingRegistryType = clearingAccount.getClearingAccountType(); + else tradingRegistryType = TradingClearingRegistryType.Owner_A.getKey(); + } + tradingClearingRegistry.setTradingClearingRegistryType(tradingRegistryType); + + //http://jira.mfd.msk:8088/browse/CLS-631#comment-60200 + TradingClearingRegistryPurpose registryPurpose = TradingClearingRegistryPurpose.C; + tradingClearingRegistry.setTradingClearingRegistryPurpose(registryPurpose.getKey()); + + Company company = companyImdg.getSingleObjectByID(request.getCompanyId()); + Long seqId = companySequenceNextId(request.getCompanyId(), registryPurpose, tradingRegistryType); + String code = makeCode(company.getClearingCode(), registryPurpose, tradingRegistryType, seqId); + log.debug("For new TCR.id={} of companyId={} next sequence={}; code={}", id, request.getCompanyId(), seqId, code); + tradingClearingRegistry.setCode(code); + + Instant now = Instant.now(); + tradingClearingRegistry.setCreated(now); + tradingClearingRegistry.setUpdated(now); + + tradingClearingRegistryImdg.insert(tradingClearingRegistry); + + log.info("New TCR.id={} was created.", tradingClearingRegistry.getId()); + sendNotificationToReportSvc(tradingClearingRegistry); + sendNotificationToClearingSvc(tradingClearingRegistry); + + log.debug("successfully processed, id {}", id); + return tradingClearingRegistry; + } + + private Long companySequenceNextId(Long companyId, + TradingClearingRegistryPurpose registryPurpose, + String tradingRegistryType) { + Imdg tradingClearingRegistryImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class + ); + ImdgPredicateBuilder pb = tradingClearingRegistryImdg.predicateBuilder(); + Collection existTCR = tradingClearingRegistryImdg.getCollectionObjectsByPredicate( + pb.and( + pb.equals("companyId", companyId), + pb.equals("tradingClearingRegistryPurpose", registryPurpose.getKey()), + pb.equals("tradingClearingRegistryType", tradingRegistryType) + ) + ); + if (existTCR.isEmpty()) { + log.trace("For company id={} not found exist TCR.", companyId); + return 1L; + } + log.trace("For company id={} found {} exist TCR.", companyId, existTCR.size()); + long maxN = 0; + for (TradingClearingRegistry tcr : existTCR) { + Long codeN = parseCodeSeqId(tcr.getCode()); + if (codeN != null) { + if (maxN < codeN) + maxN = codeN; + } + } + return maxN + 1; + } + + private Long parseCodeSeqId(String code) { + if (code == null || code.isBlank()) + return null; + try { + String toParse = code.trim(); + if (toParse.length() > 5) + toParse = toParse.substring(toParse.length() - 5); + return Long.parseLong(toParse); + } catch (NumberFormatException nan) { + log.warn("Can not parse number from TCR code \"{}\": {}", code, nan.getMessage()); + } + return null; + } + + private String makeCode(String companyClearingCode, + TradingClearingRegistryPurpose registryPurpose, + String tradingRegistryType, + Long id) { + String code; + code = companyClearingCode; + if (code.length() > 4) + code = code.substring(code.length() - 4); + code = "%4s".formatted(code).replace(' ', '0'); +// code += registryPurpose.getKey(); // C / M / ... + code += "C";//пока ставим всегда С, возможно придется откатить + String trType = tradingRegistryType + "T"; // 2 символа + code += trType; + String sId = "%5s".formatted(id).replace(' ', '0'); + if (sId.length() > 5) + sId = sId.substring(sId.length() - 5); + code += sId; + return code; // 12 символов + } + + private void sendNotificationToClearingSvc(TradingClearingRegistry tradingClearingRegistry) { + CreateRegistryRequest request = new CreateRegistryRequest(); + request.setCompanyId(tradingClearingRegistry.getCompanyId()); + request.setTradingClearingRegistryId(tradingClearingRegistry.getId()); + log.debug("Send message to kafka \"{}\": {}", Consts.REGISTRY_NEW, LogFormatter.toStringWrapper(request)); + kafkaSender.sendRequestToQueue(Consts.REGISTRY_NEW, request); + } + + /** + * report-service сообщение на формирование уведомления о создании нового ТКР + */ + private void sendNotificationToReportSvc(TradingClearingRegistry tradingClearingRegistry) { + NotificationRequest request = new NotificationRequest(); + request.setConsumerId(tradingClearingRegistry.getCompanyId()); + log.debug("Send message to kafka \"{}\": {}", Consts.CREATE_NOTIFICATION_NTCR, LogFormatter.toStringWrapper(request)); + kafkaSender.sendRequestToQueue(Consts.CREATE_NOTIFICATION_NTCR, request); + } +} diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryListFacade.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryListFacade.java new file mode 100644 index 000000000..a6bf31300 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryListFacade.java @@ -0,0 +1,87 @@ +package ru.spcex.clearing.account.service.v2.facade; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +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.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.clearing.CreateRegistryRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryListNewRequest; +import ru.spcex.clearing.platform.messaging.serialization.LogFormatter; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +import ru.spcex.platform.enumeration.ServiceStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; + +@Service +public class TradingClearingRegistryListFacade { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ImdgProvider imdgProvider; + private final KafkaSender kafkaSender; + private final Imdg tradingClearingRegistryImdg; + private final Imdg tradingClearingRegistryListImdg; + private final Imdg accountImdg; + + public TradingClearingRegistryListFacade(ImdgProvider imdgProvider, + KafkaSender kafkaSender) { + this.imdgProvider = imdgProvider; + this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, + TradingClearingRegistry.class); + this.tradingClearingRegistryListImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistryList, + TradingClearingRegistryList.class); + this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class); + this.kafkaSender = kafkaSender; + } + + public static class Stored { + TradingClearingRegistry tcr; + Account account; + + } + + public List createTradingClearingRegistryList(TradingClearingRegistryListNewRequest request, + Stored stored) { + TradingClearingRegistry tcr = tradingClearingRegistryImdg.getSingleObjectByID(request.getTradingClearingRegistryId()); + Instant now = Instant.now(); + + List newIds = new ArrayList<>(); + for (Long currAccId : request.getCurrencyAccountList()) { + Long id = tradingClearingRegistryListImdg.nextIDSequenceFor(); + TradingClearingRegistryList tradingClearingRegistryList = new TradingClearingRegistryList(); + tradingClearingRegistryList.setId(id); + tradingClearingRegistryList.setCreated(now); + tradingClearingRegistryList.setUpdated(now); + tradingClearingRegistryList.setTradingClearingRegistryId(tcr.getId()); + tradingClearingRegistryList.setAccountId(currAccId); + Account account = accountImdg.getSingleObjectByID(currAccId); + tradingClearingRegistryList.setCurrency(account.getCurrency()); + if (request.getStatus() == null) { + tradingClearingRegistryList.setStatus(ServiceStatus.Active.getKey()); + log.trace("TCRList status in request not set. Use default: {}", tradingClearingRegistryList.getStatus()); + } else { + tradingClearingRegistryList.setStatus(request.getStatus()); + } + tradingClearingRegistryListImdg.insert(tradingClearingRegistryList); + newIds.add(id); + + } + log.info("New TCRList.id={} has created.", newIds); + newIds.forEach(listId -> sendNotificationToClearingSvc(listId, tcr)); + return newIds; + } + + private void sendNotificationToClearingSvc(Long tradingClearingRegistryId, TradingClearingRegistry tcr) { + CreateRegistryRequest request = new CreateRegistryRequest(); + request.setTcrListId(tradingClearingRegistryId); + request.setCompanyId(tcr.getCompanyId()); + request.setTradingClearingRegistryId(tcr.getId()); + log.debug("Send message to kafka \"{}\": {}", Consts.REGISTRY_NEW, LogFormatter.toStringWrapper(request)); + kafkaSender.sendRequestToQueue(Consts.REGISTRY_NEW, request); + } +} 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 new file mode 100644 index 000000000..56e68d2c9 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/listeners/ClientCodeMessageListener.java @@ -0,0 +1,156 @@ +package ru.spcex.clearing.account.service.v2.listeners; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +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.stereotype.Service; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.spcex.clearing.account.model.ValidationResult; +import ru.spcex.clearing.account.service.v2.GatewayRequestCreator; +import ru.spcex.clearing.account.service.v2.facade.ClientCodeFacade; +import ru.spcex.clearing.account.service.v2.validators.ClientCodeValidator; +import ru.spcex.clearing.account.validation.ClientCodeStoreObjects; +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.TkrAccount; +import ru.spcex.clearing.platform.messaging.domain.cud.account.TkrAccountsGatewayRequest; +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.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +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.validation.IValidator; + +@Service +public class ClientCodeMessageListener extends QueueConsumer implements InitializingBean { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final KafkaSender kafkaSender; + private final ImdgProvider imdgProvider; + private final ClientCodeFacade clientCodeFacade; + private final ClientCodeValidator clientCodeValidator; + private final GatewayRequestCreator gatewayRequestCreator; + + public ClientCodeMessageListener(Consumer kafkaQueue, + Producer kafkaProducer, + KafkaSender kafkaSender, + ImdgProvider imdgProvider, + ClientCodeFacade clientCodeFacade, + ClientCodeValidator clientCodeValidator, + GatewayRequestCreator gatewayRequestCreator) { + super(kafkaQueue, kafkaProducer); + this.kafkaSender = kafkaSender; + this.imdgProvider = imdgProvider; + this.clientCodeFacade = clientCodeFacade; + this.clientCodeValidator = clientCodeValidator; + this.gatewayRequestCreator = gatewayRequestCreator; + } + + @Override + public void afterPropertiesSet() { + imdgProvider.waitAvailable(); + + callback(TkrAccountsGatewayRequest.class) + .setFunction(this::clientCodeNewFromGateway) + .forDestination(Consts.DESTINATION_CLIENT_CODE_NEW_FROM_GATEWAY, callbacks::put); + init(); + } + + private RequestInfoUpdate clientCodeNewFromGateway(BaseRequest tkrRequest) { + clientCodeFacade.lock(); + //валидация запроса + TkrAccountsGatewayRequest gatewayRequest = tkrRequest.getRequestPayload(); + + SendTkrRequest sendTkrRequest = new SendTkrRequest(); + sendTkrRequest.setRequestId(gatewayRequest.getRequestId()); + + boolean isAnyoneInvalid = false; + Map accountsAfterValidation = new HashMap<>(); + for (TkrAccount tkrAccount : gatewayRequest.getAccounts()) { + ValidationResult validationResult = clientCodeValidator.checkGatewayRequest(tkrAccount); + if (!validationResult.isValid()) { + log.debug("Validation failed for tkr.client_code {}", tkrAccount.getClientCode()); + isAnyoneInvalid = true; + } + accountsAfterValidation.put(tkrAccount, validationResult); + } + if (isAnyoneInvalid) { + log.debug("Create error request to gateway service"); + + List tkrs = accountsAfterValidation.entrySet() + .stream() + .map(tkrAccountValidationResultEntry -> + gatewayRequestCreator.crateErrorTkrToGateway( + tkrAccountValidationResultEntry.getKey(), + tkrAccountValidationResultEntry.getValue().errorMsg() + )) + .toList(); + sendTkrRequest.setTkrs(tkrs); + kafkaSender.sendRequestToQueue(Consts.ACCOUNTS_TO_GATEWAY, sendTkrRequest); + return null; + } + + //unwrap запроса + for (Map.Entry entry : accountsAfterValidation.entrySet()) { + ClientCodeNewRequest clientCodeNewRequest = new ClientCodeNewRequest(); + TkrAccount tkrAccount = entry.getKey(); + ValidationResult validationResult = entry.getValue(); + log.debug("Creating new clientCode by tkr account: {}", tkrAccount.getClientCode()); + + IValidator validator = validationResult.validator(); + Company company = validator.getStored(ClientCodeStoreObjects.COMPANY); + Optional depoAccount = validator.getStored(ClientCodeStoreObjects.DEPO_ACCOUNT); + Long depoAccountId = depoAccount.map(Account::getId).orElse(null); + Map accountByCurrency = validator.getStored(ClientCodeStoreObjects.MAPPED_TO_CURRENCY_ACCOUNTS); + + clientCodeNewRequest.setCompanyId(company.getId()); + clientCodeNewRequest.setCode(tkrAccount.getClientCode()); + clientCodeNewRequest.setDepoAccountId(depoAccountId); + Account moneyAccount = accountByCurrency.get(CurrencyCode.RUB); + clientCodeNewRequest.setMoneyAccountId(moneyAccount.getId()); + + List foreignCurrencyList = accountByCurrency.entrySet() + .stream() + .filter(currencyCodeAccountEntry -> !CurrencyCode.RUB.equalsByKey(currencyCodeAccountEntry.getKey())) + .map(currencyCodeAccountEntry -> currencyCodeAccountEntry.getValue().getId()) + .toList(); + clientCodeNewRequest.setCurrencyAccountList(foreignCurrencyList); + clientCodeFacade.createClientCode(clientCodeNewRequest, validator); + + TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(company.getId(), + moneyAccount.getId(), depoAccountId); + sendTkrRequest.getTkrs().add(gatewayRequestCreator.createTkrGatewayReq(tradingClearingRegistry)); + log.debug("Success created new clientCode by tkr account: {}", tkrAccount.getClientCode()); + } + kafkaSender.sendRequestToQueue(Consts.ACCOUNTS_TO_GATEWAY, sendTkrRequest); + return null; + } + + private 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); + } + Imdg tradingClearingRegistryImdg = imdgProvider + .getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); + TradingClearingRegistry result = tradingClearingRegistryImdg.getFirstObjectByFieldValues(query); + log.trace("TradingClearingRegistry by: {}; {} found", query, result == null ? "not" : ""); + return result; + } +} 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 new file mode 100644 index 000000000..dc3a46ead --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/validators/ClientCodeValidator.java @@ -0,0 +1,46 @@ +package ru.spcex.clearing.account.service.v2.validators; + +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import ru.spcex.clearing.account.model.ValidationResult; +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.account.TkrAccount; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; + +@Service +public class ClientCodeValidator { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Function clientCodeNewRequestValidator; + private final Function clientCodeUpdateRequestValidator; + private final Function clientCodeDeleteRequestValidator; + private final Function tkrAccountsGatewayValidator; + private final IMessageResolver messageResolver; + + public ClientCodeValidator(Function clientCodeNewRequestValidator, + Function clientCodeUpdateRequestValidator, + Function clientCodeDeleteRequestValidator, + Function tkrAccountsGatewayValidator, + IMessageResolver messageResolver) { + this.clientCodeNewRequestValidator = clientCodeNewRequestValidator; + this.clientCodeUpdateRequestValidator = clientCodeUpdateRequestValidator; + this.clientCodeDeleteRequestValidator = clientCodeDeleteRequestValidator; + this.tkrAccountsGatewayValidator = tkrAccountsGatewayValidator; + this.messageResolver = messageResolver; + } + + public ValidationResult checkGatewayRequest(TkrAccount gatewayAccountRequest) { + IValidator validator = tkrAccountsGatewayValidator.apply(gatewayAccountRequest); + Optional error = validator.tillFirstError(); + AtomicReference> errorMsg = new AtomicReference<>(); + error.ifPresent(err -> errorMsg.set(Optional.of(messageResolver.resolve(err)))); + return new ValidationResult(validator, error, errorMsg.get()); + } +} diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/ClientCodeStoreObjects.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/ClientCodeStoreObjects.java new file mode 100644 index 000000000..b4d600f08 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/ClientCodeStoreObjects.java @@ -0,0 +1,9 @@ +package ru.spcex.clearing.account.validation; + +public enum ClientCodeStoreObjects { + COMPANY, + MONEY_ACCOUNT, + DEPO_ACCOUNT, + MAPPED_TO_CURRENCY_ACCOUNTS, + TRADING_CLEARING_REGISTRY +} diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.json b/clearing-parent/backend-api/src/main/resources/meta/meta.json index fbd4a8f11..6dffc7608 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.json +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.json @@ -9176,6 +9176,10 @@ {"code": "inSDfId", "type": 1,"name": "Идентификатор соответствующей записи из таблицы-источника","shortname": "Входящая запись","searchable": true,"sortable": true,"visible": true } + , + {"code": "accType", + "type": 3,"name": "Признак счета","shortname": "Признак счета","searchable": true,"sortable": true,"visible": true + } ] } diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.xml b/clearing-parent/backend-api/src/main/resources/meta/meta.xml index 7d7cf7639..560d926b7 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.xml @@ -2117,6 +2117,7 @@ + diff --git a/clearing-parent/backend-api/src/test/resources/meta.json b/clearing-parent/backend-api/src/test/resources/meta.json index fbd4a8f11..6dffc7608 100644 --- a/clearing-parent/backend-api/src/test/resources/meta.json +++ b/clearing-parent/backend-api/src/test/resources/meta.json @@ -9176,6 +9176,10 @@ {"code": "inSDfId", "type": 1,"name": "Идентификатор соответствующей записи из таблицы-источника","shortname": "Входящая запись","searchable": true,"sortable": true,"visible": true } + , + {"code": "accType", + "type": 3,"name": "Признак счета","shortname": "Признак счета","searchable": true,"sortable": true,"visible": true + } ] } diff --git a/clearing-parent/db-scripts/src/main/resources/db/DDL.sql b/clearing-parent/db-scripts/src/main/resources/db/DDL.sql index 10d4b9541..cecb1626f 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/DDL.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/DDL.sql @@ -4503,7 +4503,7 @@ GRANT ALL PRIVILEGES ON TABLE S_DF52 TO clearing; -- sDf53 - ДФ-53 Квитанция о получении информации о состоянии счета (блокировка/разблокировка/закрытие/открытие) DROP TABLE IF EXISTS S_DF53; -CREATE TABLE S_DF53(ID bigint PRIMARY KEY, ACC_NAME varchar(30), ACCOUNT varchar(25), DEAL varchar(4), DATE varchar(8), STATUS bigint, RESULT varchar(255), FILE_NAME varchar(255), GENERATION_TIME timestamp, GENERATION_ID bigint, IN_S_DF_ID bigint); +CREATE TABLE S_DF53(ID bigint PRIMARY KEY, ACC_NAME varchar(30), ACCOUNT varchar(25), DEAL varchar(4), DATE varchar(8), STATUS bigint, RESULT varchar(255), FILE_NAME varchar(255), GENERATION_TIME timestamp, GENERATION_ID bigint, IN_S_DF_ID bigint, ACC_TYPE bigint); COMMENT ON TABLE S_DF53 IS 'ДФ-53 Квитанция о получении информации о состоянии счета (блокировка/разблокировка/закрытие/открытие)'; COMMENT ON COLUMN S_DF53.ID IS 'Идентификатор записи'; @@ -4528,6 +4528,8 @@ COMMENT ON COLUMN S_DF53.GENERATION_ID IS 'Идентификатор взаим COMMENT ON COLUMN S_DF53.IN_S_DF_ID IS 'Идентификатор соответствующей записи из таблицы-источника'; +COMMENT ON COLUMN S_DF53.ACC_TYPE IS 'Признак счета'; + GRANT ALL PRIVILEGES ON TABLE S_DF53 TO clearing; -- sDf54 - ДФ-54 Вывод свободных средств для инициаторов категории В с клирингового счета 30414 diff --git a/clearing-parent/dbf-importer/src/main/java/ru/spcex/clearing/dbf/importer/config/SFTPConfig.java b/clearing-parent/dbf-importer/src/main/java/ru/spcex/clearing/dbf/importer/config/SFTPConfig.java index 257525394..072af77b6 100644 --- a/clearing-parent/dbf-importer/src/main/java/ru/spcex/clearing/dbf/importer/config/SFTPConfig.java +++ b/clearing-parent/dbf-importer/src/main/java/ru/spcex/clearing/dbf/importer/config/SFTPConfig.java @@ -5,7 +5,6 @@ import java.util.List; import com.jcraft.jsch.ChannelSftp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @@ -27,15 +26,9 @@ import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings; @Configuration public class SFTPConfig { private final Logger log = LoggerFactory.getLogger(getClass()); - private final ImportDBFServiceSettings settings; - - @Autowired - public SFTPConfig(ImportDBFServiceSettings settings) { - this.settings = settings; - } @Bean - public SessionFactory sftpSessionFactory() { + public SessionFactory sftpSessionFactory(ImportDBFServiceSettings settings) { DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true); factory.setHost(settings.getStore().getSftpIn().getServerIp()); factory.setPort(settings.getStore().getSftpIn().getServerPort()); diff --git a/platform-parent/platform-classes-base/src/main/java/ru/spcex/platform/classes/base/interfaces/IClearingFacade.java b/platform-parent/platform-classes-base/src/main/java/ru/spcex/platform/classes/base/interfaces/IClearingFacade.java new file mode 100644 index 000000000..d640f6026 --- /dev/null +++ b/platform-parent/platform-classes-base/src/main/java/ru/spcex/platform/classes/base/interfaces/IClearingFacade.java @@ -0,0 +1,7 @@ +package ru.spcex.platform.classes.base.interfaces; + +public interface IClearingFacade { + void lock(); + void unlock(); + //something about store objects? +}