From 6b2290e0cfcf62167cfa952bb7d43fee721238b4 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Fri, 7 Jun 2024 16:24:50 +0300 Subject: [PATCH] new version services [account-service] --- .../account/model/ValidationResult.java | 12 ++ .../account/service/ClientCodeService.java | 9 +- .../service/v2/GatewayRequestCreator.java | 130 ++++++++++++ .../service/v2/facade/ClientCodeFacade.java | 90 +++++++++ .../facade/TradingClearingRegistryFacade.java | 191 ++++++++++++++++++ .../TradingClearingRegistryListFacade.java | 89 ++++++++ .../listeners/ClientCodeMessageListener.java | 156 ++++++++++++++ .../v2/validators/ClientCodeValidator.java | 46 +++++ .../validation/ClientCodeStoreObjects.java | 9 + .../base/interfaces/IClearingFacade.java | 7 + 10 files changed, 735 insertions(+), 4 deletions(-) create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/model/ValidationResult.java create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/GatewayRequestCreator.java create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/ClientCodeFacade.java create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryFacade.java create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryListFacade.java create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/listeners/ClientCodeMessageListener.java create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/validators/ClientCodeValidator.java create mode 100644 clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/validation/ClientCodeStoreObjects.java create mode 100644 platform-parent/platform-classes-base/src/main/java/ru/spcex/platform/classes/base/interfaces/IClearingFacade.java 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..335e4ea12 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryFacade.java @@ -0,0 +1,191 @@ +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; + + public TradingClearingRegistryFacade(ImdgProvider imdgProvider, + KafkaSender kafkaSender) { + this.imdgProvider = imdgProvider; + this.kafkaSender = kafkaSender; + } + + public TradingClearingRegistry createTradingClearingRegistry(TradingClearingRegistryNewRequest request, + IValidator validator) { + Imdg tradingClearingRegistryImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class + ); + Imdg depoAccountImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_DepoAccount, DepoAccount.class + ); + Imdg clearingAccountImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class + ); + Imdg companyImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_Company, Company.class + ); + + 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..c12afcab2 --- /dev/null +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/v2/facade/TradingClearingRegistryListFacade.java @@ -0,0 +1,89 @@ +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; + + public TradingClearingRegistryListFacade(ImdgProvider imdgProvider, + KafkaSender kafkaSender) { + this.imdgProvider = imdgProvider; + this.kafkaSender = kafkaSender; + } + + public static class Stored { + TradingClearingRegistry tcr; + Account account; + + } + public List createTradingClearingRegistryList(TradingClearingRegistryListNewRequest request, + Stored stored) { + Imdg tradingClearingRegistryImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class + ); + Imdg tradingClearingRegistryListImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class + ); + Imdg accountImdg = imdgProvider.getImdg( + IMDGDistributedNames.Map_Account, Account.class + ); + + 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..bf862330d --- /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 != 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/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? +}