From f22dad9a20e0271be357024cb77632546a8efc2a Mon Sep 17 00:00:00 2001 From: ialbert Date: Thu, 25 May 2023 21:05:36 +0300 Subject: [PATCH] Sdf01Executor --- .../clearing/config/SdfExecutorsConfig.java | 4 +- .../clearing/config/ValidationConfig.java | 18 ++ .../spcex/clearing/error/ClearingError.java | 5 + .../clearing/error/ClearingErrorInternal.java | 1 + .../service/executors/Sdf01Executor.java | 263 +++++++++++++----- .../service/executors/SdfLegacyExecutor.java | 215 ++++++++++++++ .../validation/Sdf01NewValidationRule.java | 93 +++++++ .../service/validation/ValidationStored.java | 4 +- .../spcex/platform/enumeration/AccType.java | 18 ++ .../platform/enumeration/MarketType.java | 2 +- 10 files changed, 551 insertions(+), 72 deletions(-) create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/SdfLegacyExecutor.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf01NewValidationRule.java create mode 100644 platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/AccType.java diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/SdfExecutorsConfig.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/SdfExecutorsConfig.java index 86a1142e9..775c7c45d 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/SdfExecutorsConfig.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/SdfExecutorsConfig.java @@ -3,8 +3,8 @@ package ru.spcex.clearing.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import ru.spcex.clearing.service.executors.AbstractExecutor; -import ru.spcex.clearing.service.executors.Sdf01Executor; import ru.spcex.clearing.service.executors.Sdf57Executor; +import ru.spcex.clearing.service.executors.SdfLegacyExecutor; import ru.spcex.platform.enumeration.SdfTable; import java.util.HashMap; @@ -14,7 +14,7 @@ import java.util.Map; public class SdfExecutorsConfig { @Bean("sdfExecutors") - public Map> executorsMap(Sdf01Executor sdf01Executor, + public Map> executorsMap(SdfLegacyExecutor sdf01Executor, Sdf57Executor sdf57Executor) { Map> executors = new HashMap<>(); executors.put(SdfTable.SDF_01, sdf01Executor); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java index afa056312..4ad5956a6 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java @@ -140,4 +140,22 @@ public class ValidationConfig { ); }; } + + @Bean("sdf01ValidatorNew") + public Function sdf01ValidatorNew() { + return sDf01 -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(sDf01); + Consumer addImdg = (s) -> context.addImdg(s, getImdg(s)); + addImdg.accept(IMDGDistributedNames.Map_Account); + addImdg.accept(IMDGDistributedNames.Map_Company); + return new ValidatorImpl<>(context, + Sdf01NewValidationRule.CompanyPresent, + Sdf01NewValidationRule.AccountType, + Sdf01NewValidationRule.AccountPresent, + Sdf01NewValidationRule.CurrencyCode, + Sdf01NewValidationRule.DatIsCurrentDt + ); + }; + } } diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java index 578fd53ac..085fa9555 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java @@ -19,6 +19,11 @@ public enum ClearingError implements IErrorEnumId { ClearingUnavailableForCompany(5421L), InsecurityObligation(5422L), NewDealsNotFound(5423L), + //ошибки "перенесенные" из balance-service + CompanyNotFoundB(5211L), + CurrencyNotFound(5213L), + OperationCanBeRunForTodayOnly(5214L), + AccountWrongType(5216L), ; private final Long id; diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java index c1d029a7e..c6f81e7c4 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingErrorInternal.java @@ -5,6 +5,7 @@ import ru.spcex.platform.utils.enumeration.IErrorEnumId; public enum ClearingErrorInternal implements IErrorEnumId { ClearingNotAllowed(1L), AccountNotActive(5415L), + AccountNotPresent(3L), CompanyNotActive(5411L), FinancialObligationNotSatisfied(4L), SessionGeneralError(2L); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf01Executor.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf01Executor.java index 8f18d90cc..f10b6c73d 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf01Executor.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf01Executor.java @@ -2,69 +2,88 @@ package ru.spcex.clearing.service.executors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.account.Account; -import ru.clearing.classes.statics.data.account.AccountBalance; +import ru.clearing.classes.statics.data.account.ClearingAccount; import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.misc.Currency; +import ru.clearing.classes.statics.data.registry.Registry; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; import ru.clearing.classes.statics.data.sdf.SDf01; import ru.clearing.classes.statics.data.sdf.SDf02; +import ru.clearing.classes.statics.data.security.Security; import ru.clearing.classes.statics.data.statement.Statement; import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.error.ClearingErrorInternal; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart; import ru.spcex.clearing.platform.messaging.domain.cud.balance.ExportToFileRequest; import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.clearing.ContinueSessionBnRequest; import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; import ru.spcex.clearing.service.LoggingService; import ru.spcex.clearing.service.model.Result; import ru.spcex.clearing.service.validation.ValidationStored; +import ru.spcex.clearing.session.stage.util.RegistryUtil; import ru.spcex.platform.enumeration.*; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; +import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder; import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; import ru.spcex.platform.utils.enumeration.IMessageResolver; -import ru.spcex.platform.utils.number.BigDecimalUtil; import ru.spcex.platform.utils.validation.IValidator; +import java.math.BigDecimal; import java.time.Instant; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Collection; import java.util.Map; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; @Service public class Sdf01Executor extends AbstractExecutor { private final Logger log = LoggerFactory.getLogger(getClass()); - private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy"); private final Imdg statementImdg; + private final Imdg registryImdg; private final Function sDf01Validator; - private final LoggingService errorLogger; - private final Imdg sdf02Imdg; private final ImdgProvider imdgProvider; - private final IMessageResolver errorResolver; - private final Imdg accountBalanceImdg; + private final Imdg clearingAccountImdg; + private final Imdg tradingClearingRegistryImdg; + private final Imdg securityImdg; + private final Imdg currencyImdg; + private final Imdg sdf02Imdg; + private final IMessageResolver messageResolver; - public Sdf01Executor(Function sDf01Validator, + public Sdf01Executor(@Qualifier("sdf01ValidatorNew") Function sDf01Validator, LoggingService errorLogger, ImdgProvider imdgProvider, - IMessageResolver errorResolver) { + IMessageResolver errorResolver, IMessageResolver messageResolver) { this.statementImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class); - this.sdf02Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf02, SDf02.class); - this.accountBalanceImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class); - ; + this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class); + this.clearingAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class); + this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); + this.currencyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Currency, Currency.class); this.sDf01Validator = sDf01Validator; - this.errorLogger = errorLogger; this.imdgProvider = imdgProvider; - this.errorResolver = errorResolver; + this.messageResolver = messageResolver; + this.securityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Security, Security.class); + this.sdf02Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf02, SDf02.class); } + //todo доделать контроль sdf01 и sdf57 + @Override public String exportTableName() { - return "DF-02"; + return null; } @Override @@ -74,6 +93,10 @@ public class Sdf01Executor extends AbstractExecutor { @Override public void sendCommand(KafkaSender kafkaSender, Result result) { + ContinueSessionBnRequest continueSessionBn = new ContinueSessionBnRequest(); + continueSessionBn.setGenerationId(result.getGenerationId()); + kafkaSender.sendRequestToQueue(Consts.CONTINUE_SESSION_BN_FIRST_PART, continueSessionBn); + ExportToFileRequest exportRequest = new ExportToFileRequest(); exportRequest.setSdfGroupId(result.getGenerationId()); exportRequest.setNameOfTable(exportTableName()); @@ -87,76 +110,85 @@ public class Sdf01Executor extends AbstractExecutor { for (SDf01 sdf01 : sdf) { IValidator validator = sDf01Validator.apply(sdf01); Optional error = validator.tillFirstError(); - Company company = validator.getStored(ValidationStored.Company); + Company company = validator.getStored(ValidationStored.Sdf01Company); + Account account = validator.getStored(ValidationStored.Sdf01Account); if (statementRequest.getAccountCreationResults().size() == 0 - && ClearingError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) { + && ClearingErrorInternal.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) { //на данном шаге company существует -> getId ok //формируем пакетный запрос на добавление account //ответ придет в этот же метод, process result.getAccountRequests().add(createAccountRequestPart(sdf01.getId(), sdf01.getAccount(), company.getId())); log.info("account {} for sdf01.id={} not found - send request for creation", sdf01.getAccount(), sdf01.getId()); continue; - } else if (ClearingError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) { + } else if (ClearingErrorInternal.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) { log.error("fatal error: resumed processing after generating accounts, but no account found for sdf01.id={}", sdf01.getId()); } if (error.isPresent()) { - errorLogger.logError("sdf01.id={}", error.get(), sdf01.getId()); + log.error("sdf01.id={} error: {}", sdf01.getId(), messageResolver.resolve(error.get())); + //fixme инициировать = команда для другого сервиса? sdf02Imdg.insert(createErrorSdf02(sdf01, error.get(), generationIdForGroup)); sdf02Imdg.insert(createErrorSdf02(sdf01, error.get(), generationIdForGroup)); continue; } - Statement statement = statementImdg.getSingleObjectByFieldValues(Map.of("account", sdf01.getAccount())); - if (statement == null) { - statement = createFlow(sdf01, - company, - validator.getStored(ValidationStored.Account)); - } else { - updateFlow(statement, sdf01, - validator.getStored(ValidationStored.Account)); - } - SDf02 sdf02New = createSuccessSdf02(sdf01, generationIdForGroup); + + Statement stmt = createSdf01Statement(sdf01, company, account); + + SDf02 sdf02New = createSuccessSdf02(sdf01, generationIdForGroup); //fixme тоже мб убрать sdf02Imdg.insert(sdf02New); - statement.setOutSDfId(sdf02New.getId()); -// AccountResult accountResult = accountBalanceService.createAccountBalance(statement.getAddresseeId(), statement.getAccountId(), statement.getAmount(), -// null/*statement.getCashMovementCurrencyCode()*/); -// if (accountResult.getError() != null) { -// statement.setErrorCodeId(accountResult.getError().getSubject().getId()); -// todo statement.setErrorText(errorResolver.resolve(accountResult.getError())); -// } else { -// accountBalanceImdg.insert(accountResult.getAccount()); //insert == update? -// statement.setOperationStatus(OperationStatus.Executed.getKey()); -// } - statementImdg.update(statement); + stmt.setOutSDfId(sdf02New.getId()); + statementImdg.update(stmt); + + Optional err = validateActiveness(company, account); + if (err.isEmpty()) { + Consumer update = rgs -> { + updateReg(stmt, rgs); + registryImdg.update(rgs); + }; + Consumer create = (dsgn) -> { + Registry registry = createRegistryByStatement(stmt, company, account, dsgn); + Registry registryF = registry.clone(); + registryF.setRegistryUnit(RegistryUnit.F.getKey()); + registryF.setRegistryCode(RegistryUtil.clearingCode(registryF)); + registryF.setId(imdgProvider.getImdgIdGenerator().nextId()); + Registry registryB = registry.clone(); + registryB.setRegistryUnit(RegistryUnit.B.getKey()); + registryB.setRegistryCode(RegistryUtil.clearingCode(registryB)); + registryB.setId(imdgProvider.getImdgIdGenerator().nextId()); + registryImdg.insert(registry); + registryImdg.insert(registryF); + registryImdg.insert(registryB); + }; + + findReg(stmt, RegistryInstrumentType.M).ifPresentOrElse(update, () -> create.accept(RegistryDesignation.A)); + findReg(stmt, RegistryInstrumentType.S).ifPresentOrElse(update, () -> create.accept(RegistryDesignation.D)); + stmt.setOperationStatus(OperationStatus.Executed.getKey()); + } else { + stmt.setErrorCodeId(err.get().getSubject().getId()); // fixme ErrorText insert + stmt.setOperationStatus(OperationStatus.Rejected.getKey()); + statementImdg.update(stmt); + } } return result; } - private Statement createFlow(SDf01 sdf01, Company company, Account account) { - Statement statement = new Statement(); - statement.setAddresseeId(company.getId()); - statement.setSenderId(Sender.Prc.getId()); - statement.setCreated(Instant.now()); - statement.setClearingDate(LocalDate.now()); - statement.setStatementType(StatementType.full.getKey()); - statement.setAccountId(account.getId()); - statement.setAccount(sdf01.getAccount()); - statement.setInOutDirection(InOutDirection.in.getKey()); - statement.setSettlementDate(LocalDate.parse(sdf01.getDat(), datFormatter)); - statement.setAmount(BigDecimalUtil.parse(sdf01.getRemainder())); - statement.setOperationStatus(OperationStatus.Pending.getKey()); - statement.setInSDfId(sdf01.getId()); - statement.setInOutSDfType(InOutSDfType.type1.getKey()); - statementImdg.insert(statement); - return statement; - } - - private void updateFlow(Statement statement, SDf01 sdf01, Account account) { - statement.setUpdated(Instant.now()); - statement.setAccountId(account.getId()); - statement.setAccount(sdf01.getAccount()); - statement.setInOutDirection(InOutDirection.in.getKey()); - statement.setSettlementDate(LocalDate.parse(sdf01.getDat(), datFormatter)); - statement.setAmount(BigDecimalUtil.parse(sdf01.getRemainder())); - statementImdg.update(statement); + private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yy"); + private Statement createSdf01Statement(SDf01 sdf01, Company company, Account account) { + Statement stmt = new Statement(); + stmt.setAddresseeId(company.getId()); + stmt.setAddresseeId(company.getId()); + stmt.setSenderId(Sender.Prc.getId()); + stmt.setStatementType(StatementType.full.getKey()); + stmt.setAccountId(account.getId()); + stmt.setAccount(account.getAccount()); + stmt.setInOutDirection(InOutDirection.in.getKey()); + stmt.setSettlementDate(LocalDate.parse(sdf01.getDat(), formatter)); + if (sdf01.getRemainder() != null) { + stmt.setAmount(new BigDecimal(sdf01.getRemainder())); + } + stmt.setOperationStatus(OperationStatus.Pending.getKey()); + stmt.setInSDfId(sdf01.getId()); + stmt.setInOutSDfType(InOutSDfType.type1.getKey()); + stmt.setCreated(Instant.now()); + return stmt; } private AccountSdfRequestPart createAccountRequestPart(Long sdf01Id, String account, Long companyId) { @@ -168,7 +200,6 @@ public class Sdf01Executor extends AbstractExecutor { return req; } - private SDf02 createErrorSdf02(SDf01 sdf01, EnumMessage error, Long generationIdForGroup) { SDf02 sDf02 = new SDf02(); sDf02.setCurr_code(sdf01.getCurr_code()); @@ -211,4 +242,100 @@ public class Sdf01Executor extends AbstractExecutor { sDf02.setResult("OK!"); return sDf02; } + + + private Optional validateActiveness(Company company, Account account) { + if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) { + return Optional.of(new EnumMessage(ClearingError.CompanyNotActive, company.getId())); + } + if (!WorkflowStatus.Active.equalsByKey(account.getStatus())) { + return Optional.of(new EnumMessage(ClearingError.AccountNotActive, account.getId())); + } + return Optional.empty(); + } + + private Registry createRegistryByStatement(Statement statement, Company company, Account account, RegistryDesignation designation) { + Registry rgs = new Registry(); + rgs.setCompanyId(statement.getAddresseeId()); + rgs.setTradingCode(company.getTradingCode()); + rgs.setClearingCode(company.getClearingCode()); + rgs.setShortName(company.getShortName()); + rgs.setFullName(company.getFullName()); + rgs.setAccountId(account.getId()); + rgs.setAccountType(account.getAccountType()); + rgs.setAccount(account.getAccount()); + rgs.setRegistryDesignation(designation.getKey()); + rgs.setRegistryInstrumentType(RegistryInstrumentType.M.getKey()); + + ClearingAccount accountForStatement = clearingAccountImdg.getSingleObjectByID(statement.getAccountId()); + if (accountForStatement != null) { + rgs.setRegistryCapacity(accountForStatement.getClearingAccountType()); + } + rgs.setRegistryUnit(RegistryUnit.T.getKey()); + rgs.setRegistryCode(RegistryUtil.clearingCode(rgs)); + + Collection tcrsByAccount = tradingClearingRegistryImdg.getCollectionObjectsByFieldValues(Map.of( + "moneyAccountId", statement.getAccountId() + )); + if (!tcrsByAccount.isEmpty()) { + TradingClearingRegistry tcr = tcrsByAccount.iterator().next(); + rgs.setTradingClearingRegistryId(tcr.getId()); + rgs.setTradingClearingRegistry(tcr.getCode()); + } + + rgs.setRegistryStatus(RegistryStatus.PROC.getKey()); + rgs.setSecurityId(statement.getSecurityId()); + if (statement.getSecurityId() != null) { + Security security = securityImdg.getSingleObjectByID(statement.getSecurityId()); + if (security != null) { + rgs.setSecuritySymbol(security.getSecuritySymbol()); + } + } + InOutDirection inOutDirection = IEnumKey.getEnumByKey(InOutDirection.class, statement.getInOutDirection()); + //считаю balance при создании нулевым и исхожу из этого + //При добавлении (на базе изменения statement по sDf57): + //Если значение statement.inOutDirection=IN, то: + //= текущее значение registry.balance + statement.amount + // + //Если значение statement.inOutDirection=OUT, то: + //= текущее значение registry.balance - statement.amount + switch (inOutDirection) { + case in -> rgs.setBalance(statement.getAmount()); + case out -> rgs.setBalance(statement.getAmount().negate()); + } + rgs.setBalanceDimension(BalanceDimension.MONY.getKey()); //fixme ! смотри описание и ссылка на начало html'ки + //fixme !rgs.setSettlementCode(); + rgs.setTradingDate(statement.getSettlementDate()); //fixme ! today ? + rgs.setClearingDate(LocalDate.now()); + //fixme rgs.setRefundDate(); + //fixme rgs.setValueDate(); + rgs.setContract(statement.getContract()); + //создается на базе stmt, companyCred, accountDeb + rgs.setCounterPartyId(statement.getAddresseeId()); + rgs.setCreated(Instant.now()); + return rgs; + } + + private void updateReg(Statement s, Registry r) { + InOutDirection direction = IEnumKey.getEnumByKey(InOutDirection.class, s.getInOutDirection()); + switch (direction) { + case in -> r.setBalance(r.getBalance().add(s.getAmount())); + case out -> r.setBalance(r.getBalance().subtract(s.getAmount())); + } + r.setUpdated(Instant.now()); + } + + private Optional findReg(Statement s, RegistryInstrumentType registryInstrumentType) { + RegistryTradingParams p = new RegistryTradingParams( + RegistryDesignation.A, registryInstrumentType, RegistryCapacity.A, RegistryUnit.T + ); + String sql = RegistryCodeSqlBuilder.getInstance(p).build(); + ImdgPredicateBuilder pb = registryImdg.predicateBuilder(); + ImdgPredicate rgstrPredicate = pb.and(pb.sql(sql), + pb.sql(sql), + pb.equals("accountId", s.getAccountId()), + pb.equals("companyId", s.getAddresseeId()) + ); + return Optional.ofNullable(registryImdg.getSingleObjectByPredicate(rgstrPredicate)); + } } diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/SdfLegacyExecutor.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/SdfLegacyExecutor.java new file mode 100644 index 000000000..c8a5ce1a3 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/SdfLegacyExecutor.java @@ -0,0 +1,215 @@ +package ru.spcex.clearing.service.executors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.account.AccountBalance; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.sdf.SDf01; +import ru.clearing.classes.statics.data.sdf.SDf02; +import ru.clearing.classes.statics.data.statement.Statement; +import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart; +import ru.spcex.clearing.platform.messaging.domain.cud.balance.ExportToFileRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +import ru.spcex.clearing.service.LoggingService; +import ru.spcex.clearing.service.model.Result; +import ru.spcex.clearing.service.validation.ValidationStored; +import ru.spcex.platform.enumeration.*; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.number.BigDecimalUtil; +import ru.spcex.platform.utils.validation.IValidator; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +@Service +public class SdfLegacyExecutor extends AbstractExecutor { + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy"); + private final Imdg statementImdg; + private final Function sDf01Validator; + private final LoggingService errorLogger; + private final Imdg sdf02Imdg; + private final ImdgProvider imdgProvider; + private final IMessageResolver errorResolver; + private final Imdg accountBalanceImdg; + + public SdfLegacyExecutor(@Qualifier("sdf01Validator") Function sDf01Validator, + LoggingService errorLogger, + ImdgProvider imdgProvider, + IMessageResolver errorResolver) { + this.statementImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class); + this.sdf02Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf02, SDf02.class); + this.accountBalanceImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class); + ; + this.sDf01Validator = sDf01Validator; + this.errorLogger = errorLogger; + this.imdgProvider = imdgProvider; + this.errorResolver = errorResolver; + } + + @Override + public String exportTableName() { + return "DF-02"; + } + + @Override + public boolean isNeedToSendCommand() { + return true; + } + + @Override + public void sendCommand(KafkaSender kafkaSender, Result result) { + ExportToFileRequest exportRequest = new ExportToFileRequest(); + exportRequest.setSdfGroupId(result.getGenerationId()); + exportRequest.setNameOfTable(exportTableName()); + kafkaSender.sendRequestToQueue(Consts.EXPORT_PROCESS, exportRequest); + } + + public Result execute(Collection sdf, StatementRequest statementRequest) { + Result result = new Result(); + Long generationIdForGroup = imdgProvider.getImdgIdGenerator().nextId(); + result.setGenerationId(generationIdForGroup); + for (SDf01 sdf01 : sdf) { + IValidator validator = sDf01Validator.apply(sdf01); + Optional error = validator.tillFirstError(); + Company company = validator.getStored(ValidationStored.Company); + if (statementRequest.getAccountCreationResults().size() == 0 + && ClearingError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) { + //на данном шаге company существует -> getId ok + //формируем пакетный запрос на добавление account + //ответ придет в этот же метод, process + result.getAccountRequests().add(createAccountRequestPart(sdf01.getId(), sdf01.getAccount(), company.getId())); + log.info("account {} for sdf01.id={} not found - send request for creation", sdf01.getAccount(), sdf01.getId()); + continue; + } else if (ClearingError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) { + log.error("fatal error: resumed processing after generating accounts, but no account found for sdf01.id={}", sdf01.getId()); + } + if (error.isPresent()) { + errorLogger.logError("sdf01.id={}", error.get(), sdf01.getId()); + sdf02Imdg.insert(createErrorSdf02(sdf01, error.get(), generationIdForGroup)); + continue; + } + Statement statement = statementImdg.getSingleObjectByFieldValues(Map.of("account", sdf01.getAccount())); + if (statement == null) { + statement = createFlow(sdf01, + company, + validator.getStored(ValidationStored.Account)); + } else { + updateFlow(statement, sdf01, + validator.getStored(ValidationStored.Account)); + } + SDf02 sdf02New = createSuccessSdf02(sdf01, generationIdForGroup); + sdf02Imdg.insert(sdf02New); + statement.setOutSDfId(sdf02New.getId()); +// AccountResult accountResult = accountBalanceService.createAccountBalance(statement.getAddresseeId(), statement.getAccountId(), statement.getAmount(), +// null/*statement.getCashMovementCurrencyCode()*/); +// if (accountResult.getError() != null) { +// statement.setErrorCodeId(accountResult.getError().getSubject().getId()); +// todo statement.setErrorText(errorResolver.resolve(accountResult.getError())); +// } else { +// accountBalanceImdg.insert(accountResult.getAccount()); //insert == update? +// statement.setOperationStatus(OperationStatus.Executed.getKey()); +// } + statementImdg.update(statement); + } + return result; + } + + private Statement createFlow(SDf01 sdf01, Company company, Account account) { + Statement statement = new Statement(); + statement.setAddresseeId(company.getId()); + statement.setSenderId(Sender.Prc.getId()); + statement.setCreated(Instant.now()); + statement.setClearingDate(LocalDate.now()); + statement.setStatementType(StatementType.full.getKey()); + statement.setAccountId(account.getId()); + statement.setAccount(sdf01.getAccount()); + statement.setInOutDirection(InOutDirection.in.getKey()); + statement.setSettlementDate(LocalDate.parse(sdf01.getDat(), datFormatter)); + statement.setAmount(BigDecimalUtil.parse(sdf01.getRemainder())); + statement.setOperationStatus(OperationStatus.Pending.getKey()); + statement.setInSDfId(sdf01.getId()); + statement.setInOutSDfType(InOutSDfType.type1.getKey()); + statementImdg.insert(statement); + return statement; + } + + private void updateFlow(Statement statement, SDf01 sdf01, Account account) { + statement.setUpdated(Instant.now()); + statement.setAccountId(account.getId()); + statement.setAccount(sdf01.getAccount()); + statement.setInOutDirection(InOutDirection.in.getKey()); + statement.setSettlementDate(LocalDate.parse(sdf01.getDat(), datFormatter)); + statement.setAmount(BigDecimalUtil.parse(sdf01.getRemainder())); + statementImdg.update(statement); + } + + private AccountSdfRequestPart createAccountRequestPart(Long sdf01Id, String account, Long companyId) { + AccountSdfRequestPart req = new AccountSdfRequestPart(); + req.setAccount(account); + req.setCompanyId(companyId); + req.setAccountType(AccountType.Clrn.getKey()); + req.setSdfId(sdf01Id); + return req; + } + + + private SDf02 createErrorSdf02(SDf01 sdf01, EnumMessage error, Long generationIdForGroup) { + SDf02 sDf02 = new SDf02(); + sDf02.setCurr_code(sdf01.getCurr_code()); + sDf02.setAccount(sdf01.getAccount()); + sDf02.setRemainder(sdf01.getRemainder()); + sDf02.setDeal(sdf01.getDeal()); + sDf02.setAcc_code(sdf01.getAcc_code()); + sDf02.setDat(sdf01.getDat()); + sDf02.setMarket(sdf01.getMarket()); + sDf02.setAcc_name(sdf01.getAcc_name()); + sDf02.setAcc_type(sdf01.getAcc_type()); + sDf02.setSumengage(sdf01.getSumengage()); + sDf02.setSumunblock(sdf01.getSumunblock()); + sDf02.setFile_type(sdf01.getFile_type()); + sDf02.setInSDfId(sdf01.getId()); + String errorId = error.getSubject().getId().toString(); + sDf02.setResult(errorId.substring(errorId.length() - 3)); + sDf02.setGenerationId(generationIdForGroup); + sDf02.setGenerationTime(Instant.now()); + return sDf02; + } + + private SDf02 createSuccessSdf02(SDf01 sdf01, Long generationIdForGroup) { + SDf02 sDf02 = new SDf02(); + sDf02.setCurr_code(sdf01.getCurr_code()); + sDf02.setAccount(sdf01.getAccount()); + sDf02.setRemainder(sdf01.getRemainder()); + sDf02.setDeal(sdf01.getDeal()); + sDf02.setAcc_code(sdf01.getAcc_code()); + sDf02.setDat(sdf01.getDat()); + sDf02.setMarket(sdf01.getMarket()); + sDf02.setAcc_name(sdf01.getAcc_name()); + sDf02.setAcc_type(sdf01.getAcc_type()); + sDf02.setSumengage(sdf01.getSumengage()); + sDf02.setSumunblock(sdf01.getSumunblock()); + sDf02.setFile_type(sdf01.getFile_type()); + sDf02.setInSDfId(sdf01.getId()); + sDf02.setGenerationId(generationIdForGroup); + sDf02.setGenerationTime(Instant.now()); + sDf02.setResult("OK!"); + return sDf02; + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf01NewValidationRule.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf01NewValidationRule.java new file mode 100644 index 000000000..a431286dd --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf01NewValidationRule.java @@ -0,0 +1,93 @@ +package ru.spcex.clearing.service.validation; + +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.sdf.SDf01; +import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.error.ClearingErrorInternal; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.platform.enumeration.AccType; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; +import ru.spcex.platform.utils.text.TextUtil; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Optional; + +public enum Sdf01NewValidationRule implements IValidationRule> { + CompanyPresent() { + @Override + public Optional validate(ImdgValidationContext context) { + SDf01 sdf01 = context.getValidatedObject(); + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + + if (TextUtil.isEmpty(sdf01.getDeal())) { + of(ClearingError.CompanyNotFoundB, sdf01.getDeal()); + } + + Company company = companyImdg.getSingleObjectBySQL("tradingCode = '" + sdf01.getDeal() + "'"); + if (company == null) { + of(ClearingError.CompanyNotFoundB, sdf01.getDeal()); + } + context.storeObject(ValidationStored.Sdf01Company, company); + return empty(); + } + }, AccountType() { + @Override + public Optional validate(ImdgValidationContext context) { + SDf01 sdf01 = context.getValidatedObject(); + + if (!IEnumKey.contains(sdf01.getAcc_type(), AccType.A, AccType.B)) { + of(ClearingError.AccountWrongType, sdf01.getAcc_type()); + } + return empty(); + } + }, AccountPresent() { + @Override + public Optional validate(ImdgValidationContext context) { + SDf01 sdf01 = context.getValidatedObject(); + Imdg accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); + Account acc = accountImdg.getSingleObjectBySQL("account = '" + sdf01.getAccount() + + "' and accountType='" + ru.spcex.platform.enumeration.AccountType.Clrn.getKey() + "'"); + if (acc == null) { + return of (ClearingErrorInternal.AccountNotPresent, sdf01.getAccount()); + } + context.storeObject(ValidationStored.Sdf01Account, acc); + return empty(); + } + }, CurrencyCode() { + @Override + public Optional validate(ImdgValidationContext context) { + SDf01 sdf01 = context.getValidatedObject(); + if (!ru.spcex.platform.enumeration.CurrencyCode.RUR.equalsByKey(sdf01.getCurr_code())) { + return of(ClearingError.CurrencyNotFound, sdf01.getCurr_code()); + } + return empty(); + } + }, DatIsCurrentDt() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yy"); + @Override + public Optional validate(ImdgValidationContext context) { + SDf01 sdf01 = context.getValidatedObject(); + LocalDate parse; + try { + parse = LocalDate.parse(sdf01.getDat(), formatter); + } catch (Exception e) { + return of(ClearingError.OperationCanBeRunForTodayOnly, sdf01.getDat()); + } + if (!LocalDate.now().equals(parse)) { + return of(ClearingError.OperationCanBeRunForTodayOnly, sdf01.getDat()); + } + return empty(); + } + }; + + @Override + public String ruleName() { + return "Sdf01NewValidationRule." + name(); + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java index 861950ecb..aed0a13fe 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java @@ -4,5 +4,7 @@ public enum ValidationStored { STradesCompany, STradesCounterCompany, STradesSecurity, STradesTradingClearingRegistry, Account, Company, - Sdf57CompanyDeb, Sdf57CompanyCred, Sdf57AccountDeb, Sdf57AccountCred + Sdf57CompanyDeb, Sdf57CompanyCred, Sdf57AccountDeb, Sdf57AccountCred, + + Sdf01Company, Sdf01Account } diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/AccType.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/AccType.java new file mode 100644 index 000000000..d9a2b851b --- /dev/null +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/AccType.java @@ -0,0 +1,18 @@ +package ru.spcex.platform.enumeration; + +import ru.spcex.platform.utils.enumeration.IEnumKey; + +public enum AccType implements IEnumKey { + A("A"), B("B"); + + private final String key; + + AccType(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/MarketType.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/MarketType.java index 930e40a2c..cc338474d 100644 --- a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/MarketType.java +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/MarketType.java @@ -3,7 +3,7 @@ package ru.spcex.platform.enumeration; import ru.spcex.platform.utils.enumeration.IEnumKey; public enum MarketType implements IEnumKey { - PRMR("PRMR"); + PRMR("PRMR"), SCND("SCND"); private final String key;