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 fa6683504..2a028a69b 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 @@ -27,6 +27,8 @@ public enum ClearingError implements IErrorEnumId { AccountNotFoundB(5217L), MarketIsNotMkr(5217L), BalanceInsufficient(5222L), + TCRegistryNotFound(3022L), + WrongField(5004L), ActiveSessionIsPresent(-1L), ; diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/RegistryBuilder.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/RegistryBuilder.java index d0bff81c1..8c2dd9b33 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/RegistryBuilder.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/RegistryBuilder.java @@ -12,6 +12,7 @@ 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.utils.enumeration.IEnumKey; import java.math.BigDecimal; import java.time.Instant; @@ -63,7 +64,7 @@ public class RegistryBuilder { public Registry build() { Registry rgs = new Registry(); - rgs.setCompanyId(statement.getAddresseeId()); + rgs.setCompanyId(company.getId()); rgs.setTradingCode(company.getTradingCode()); rgs.setClearingCode(company.getClearingCode()); rgs.setShortName(company.getShortName()); @@ -74,16 +75,21 @@ public class RegistryBuilder { rgs.setRegistryDesignation(designation.getKey()); rgs.setRegistryInstrumentType(RegistryInstrumentType.M.getKey()); - ClearingAccount accountForStatement = clearingAccountImdg.getSingleObjectByID(statement.getAccountId()); - if (accountForStatement != null) { - rgs.setRegistryCapacity(accountForStatement.getClearingAccountType()); + AccountType accType = IEnumKey.getEnumByKey(AccountType.class, account.getAccountType()); + if (AccountType.Clrn.equals(accType)) { + ClearingAccount accountForStatement = clearingAccountImdg.getSingleObjectByFieldValues(Map.of("accountId", statement.getAccountId())); + if (accountForStatement != null) { + rgs.setRegistryCapacity(accountForStatement.getClearingAccountType()); + } + } else if (AccountType.Info.equals(accType) || AccountType.Anlt.equals(accType)) { + rgs.setRegistryCapacity(RegistryCapacity.A.getKey()); } rgs.setRegistryUnit(RegistryUnit.T.getKey()); rgs.setRegistryCode(RegistryUtil.clearingCode(rgs)); Collection tcrsByAccount = tradingClearingRegistryImdg.getCollectionObjectsByFieldValues(Map.of( - "moneyAccountId", statement.getAccountId(), - "companyId", statement.getAddresseeId(), + "moneyAccountId", account.getId(), + "companyId", company.getId(), "status", ServiceStatus.Active.getKey() )); if (!tcrsByAccount.isEmpty()) { 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 0042d7afe..6d7b62d99 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 @@ -229,7 +229,6 @@ public class Sdf01Executor extends AbstractExecutor { 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()); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java index 5a2712fc6..042019b15 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java @@ -34,7 +34,9 @@ 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.collection.Pair; import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumId; import ru.spcex.platform.utils.enumeration.IEnumKey; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.text.TextUtil; @@ -66,6 +68,8 @@ public class Sdf57Executor extends AbstractExecutor { private final Imdg accountBalanceImdg; private final Imdg clearingAccountImdg; private final Imdg tradingClearingRegistryImdg; + private final Imdg accountImdg; + private final Imdg companyImdg; private final Imdg securityImdg; private final Imdg currencyImdg; private final IMessageResolver messageResolver; @@ -82,6 +86,8 @@ public class Sdf57Executor extends AbstractExecutor { 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.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class); + this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); this.sDf57Validator = sDf57Validator; this.errorLogger = errorLogger; this.imdgProvider = imdgProvider; @@ -174,7 +180,12 @@ public class Sdf57Executor extends AbstractExecutor { return; Optional err = validateActiveness(company, account); if (err.isEmpty()) { - findRegByDesignation(stmt, RegistryTradingParams.AM_T, false, false).ifPresentOrElse(rgs -> { + Optional amtFound = RegistrySearch.builder(registryImdg) + .rgsCode(RegistryTradingParams.AM_T) + .companyId(company.getId()) //раньше было stmt.getAddresseeId() + .accountId(account.getId()) //раньше было stmt.getAccountId() + .find(); + amtFound.ifPresentOrElse(rgs -> { log.debug("stmt.id={}, found AM*T.id={}, updating...", stmt.getId(), rgs.getId()); updateReg(stmt, rgs); //добавил создание если не найдены @@ -228,14 +239,31 @@ public class Sdf57Executor extends AbstractExecutor { //stmt.id=340270002, sdf57.specif=Возврат депозита по договору №DT1000S001U/280623/8/7 new DM*T.id=339610032 //1. у stmt accountId 3021, addresseId 2610034, contract DT1000S001U/280623/8/7 // - Optional dm__Found = findRegByDesignation(stmt, RegistryTradingParams.DM__, true, false); + Optional dm__Found = RegistrySearch.builder(registryImdg) + .rgsCode(RegistryTradingParams.DM__) + .companyId(company.getId()) + .accountId(account.getId()) + .contract(stmt.getContract()) + .find(); Optional om_tFound = Optional.empty(); Optional tm_tFound = Optional.empty(); if (dm__Found.isEmpty()) { - om_tFound = findRegByDesignation(stmt, RegistryTradingParams.OM_T, true, true); + om_tFound = RegistrySearch.builder(registryImdg) + .rgsCode(RegistryTradingParams.OM_T) + .companyId(company.getId()) + .accountId(account.getId()) + .contract(stmt.getContract()) + .status() + .find(); } if (dm__Found.isEmpty() && om_tFound.isEmpty()) { - tm_tFound = findRegByDesignation(stmt, RegistryTradingParams.TM_T, true, true); + tm_tFound = RegistrySearch.builder(registryImdg) + .rgsCode(RegistryTradingParams.TM_T) + .companyId(company.getId()) + .accountId(account.getId()) + .contract(stmt.getContract()) + .status() + .find(); } if (dm__Found.isPresent()) { Registry dm__ = dm__Found.get(); @@ -276,12 +304,109 @@ public class Sdf57Executor extends AbstractExecutor { statementImdg.update(stmt); } }; - statementDeb.ifPresent(stmt -> createRegistryIfNeeded.accept(new StmtCmpAcc(stmt, companyDeb, accountDeb))); - statementCred.ifPresent(stmt -> createRegistryIfNeeded.accept(new StmtCmpAcc(stmt, companyCred, accountCred))); + Consumer registersUpdate = stmtCmpAcc -> { + Statement stmt = stmtCmpAcc.statement(); + Company cmp = stmtCmpAcc.company(); + Account acc = stmtCmpAcc.account(); + createRegistryIfNeeded.accept(stmtCmpAcc); + if (accountIsAnlt(acc)) { + Optional> anltLink = loadByAnlt(stmt.getId(), stmt.getComment()); + //счет оказался биржевым, и удалось найти счет агента по комментарию + anltLink.ifPresent(pair -> { + log.debug("stmt.id={} comment={} is anlt, loaded account.id={}/companyId={}", + stmt.getId(), stmt.getComment(), pair.getSecond().getId(), pair.getFirst().getId()); + createRegistryIfNeeded.accept(new StmtCmpAcc(stmt, anltLink.get().getFirst(), anltLink.get().getSecond())); + }); + //счет оказался биржевым, но не знаем кто адресат, заполняем DMAU + if (anltLink.isEmpty()) { + log.debug("stmt.id={} comment={} account not found. Create DMAU registry", stmt.getId(), stmt.getComment()); + Optional dmau = RegistrySearch.builder(registryImdg) + .rgsCode(RegistryTradingParams.DMAU) + .companyId(cmp.getId()) + .accountId(acc.getId()) + .accountType(AccountType.Anlt) + .find(); + dmau.ifPresentOrElse(rgs -> { + log.debug("stmt.id={} DMAU.id={} found, updating", stmt.getId(), rgs.getId()); + updateDmauReg(stmt, rgs); + registryImdg.update(rgs); + }, () -> { + Registry newDmau = RegistryBuilder.builder(imdgProvider) + .statement(stmt) + .company(cmp) + .account(acc) + .designation(RegistryDesignation.D) + .build(); + newDmau.setRegistryUnit(RegistryUnit.U.getKey()); + newDmau.setRegistryCode(RegistryUtil.clearingCode(newDmau)); + registryImdg.insert(newDmau); + log.debug("stmt.id={} created DMAU.id={}", stmt.getId(), newDmau.getId()); + }); + //DMAU подразумевает увеличение остатка поля balance и credit registry.code=DMAU + } + } + }; + statementDeb.map(stmt -> new StmtCmpAcc(stmt, companyDeb, accountDeb)).ifPresent(registersUpdate); + statementCred.map(stmt -> new StmtCmpAcc(stmt, companyCred, accountCred)).ifPresent(registersUpdate); } return result; } + private boolean accountIsAnlt(Account account) { + if (account == null) return false; + boolean anlt = AccountType.Anlt.getKey().equals(account.getAccountType()); + log.debug("account.id={} type {} is anlt={}", account.getId(), account.getAccountType(), anlt); + return anlt; + } + + @FunctionalInterface + private interface AnltLogger { + void log(IEnumId subject, Object... args); + } + + private Optional> loadByAnlt(Long statementId, String comment) { + String commentTcrStripped = getTkrCodeFromComment(comment); + AnltLogger localLogger = (subject, args) -> log.debug("stmt.id={} comment='{}' error: {}", statementId, commentTcrStripped, messageResolver.resolve(new EnumMessage(subject, args))); + if (commentTcrStripped == null) { + localLogger.log(ClearingError.AccountNotFound, "comment not contain TCR"); + return Optional.empty(); + } + ImdgPredicateBuilder pb = tradingClearingRegistryImdg.predicateBuilder(); + ImdgPredicate tcrPredicate = pb.and( + pb.equals("code", commentTcrStripped), + pb.equals("status", ServiceStatus.Active.getKey()) + ); + + TradingClearingRegistry tcr = tradingClearingRegistryImdg.getSingleObjectByPredicate(tcrPredicate); + if (tcr == null) { + localLogger.log(ClearingError.TCRegistryNotFound, commentTcrStripped); + return Optional.empty(); + } + + if (tcr.getMoneyAccountId() == null) { + localLogger.log(ClearingError.WrongField, "moneyAccountId"); + return Optional.empty(); + } + + Account infoAcc = accountImdg.getSingleObjectByID(tcr.getMoneyAccountId()); + if (infoAcc == null) { + localLogger.log(ClearingError.AccountNotFound, "moneyAccountId"); + return Optional.empty(); + } + + if (!infoAcc.getAccountType().equals(AccountType.Info.getKey())) { + localLogger.log(ClearingError.AccountNotFound, "accountType"); + return Optional.empty(); + } + + Company company = companyImdg.getSingleObjectByID(tcr.getCompanyId()); + if (company == null) { + localLogger.log(ClearingError.CompanyNotFoundB, tcr.getCompanyId()); + return Optional.empty(); + } + return Optional.of(new Pair<>(company, infoAcc)); + } + private Registry copyRegB(Registry rgs) { Registry rgsB = rgs.clone(); rgsB.setRegistryUnit(RegistryUnit.B.getKey()); @@ -333,6 +458,7 @@ public class Sdf57Executor extends AbstractExecutor { statement.setSenderId(Sender.Prc.getId()); statement.setStatementType(StatementType.incr.getKey()); statement.setContract(getContractFromSpecif(sdf57.getSpecif())); + statement.setComment(sdf57.getSpecif()); statement.setAccountId(accountDeb.getId()); Currency currency = currencyImdg.getSingleObjectByFieldValues(Map.of("currencyCode", "RUB")); @@ -371,6 +497,10 @@ public class Sdf57Executor extends AbstractExecutor { rgs.setDebit(statement.getAmount().negate()); } } + AccountType accType = IEnumKey.getEnumByKey(AccountType.class, rgs.getAccountType()); + if (!AccountType.Info.equals(accType)) { + rgs.setDiffBalance(safeBD(rgs.getBalance()).subtract(safeBD(rgs.getCheckBalance()))); + } rgs.setDiffBalance(safeBD(rgs.getBalance()).subtract(safeBD(rgs.getCheckBalance()))); rgs.setBalanceDimension(BalanceDimension.MONY.getKey()); //fixme ! смотри описание и ссылка на начало html'ки } @@ -387,7 +517,25 @@ public class Sdf57Executor extends AbstractExecutor { r.setDebit(safeBD(r.getDebit()).add(safeBD(s.getAmount()))); } } - r.setDiffBalance(safeBD(r.getBalance()).subtract(safeBD(r.getCheckBalance()))); + AccountType accType = IEnumKey.getEnumByKey(AccountType.class, r.getAccountType()); + if (!AccountType.Info.equals(accType)) { + r.setDiffBalance(safeBD(r.getBalance()).subtract(safeBD(r.getCheckBalance()))); + } + r.setUpdated(Instant.now()); + } + + private void updateDmauReg(Statement s, Registry r) { + InOutDirection direction = IEnumKey.getEnumByKey(InOutDirection.class, s.getInOutDirection()); + switch (direction) { + case in -> { + r.setBalance(safeBD(r.getBalance()).add(safeBD(s.getAmount()))); + r.setCredit(safeBD(r.getCredit()).add(safeBD(s.getAmount()))); + } + case out -> { + r.setBalance(safeBD(r.getBalance()).subtract(safeBD(s.getAmount()))); + r.setDebit(safeBD(r.getDebit()).add(safeBD(s.getAmount()))); + } + } r.setUpdated(Instant.now()); } @@ -415,6 +563,61 @@ public class Sdf57Executor extends AbstractExecutor { return Optional.ofNullable(registryImdg.getSingleObjectByPredicate(rgstrPredicate)); } + private static class RegistrySearch { + private final ImdgPredicateBuilder pb; + private final Imdg registryImdg; + private ImdgPredicate predicate; + + private RegistrySearch(Imdg registryImdg) { + this.registryImdg = registryImdg; + this.pb = registryImdg.predicateBuilder(); + } + + private static RegistrySearch builder(Imdg registryImdg) { + RegistrySearch registrySearch = new RegistrySearch(registryImdg); + registrySearch.predicate = registrySearch.pb.alwaysTrue(); + return registrySearch; + } + + private RegistrySearch rgsCode(RegistryTradingParams rgsCode) { + String sql = RegistryCodeSqlBuilder.getInstance(rgsCode).build(); + predicate = pb.and(predicate, pb.sql(sql)); + return this; + } + + private RegistrySearch companyId(Long companyId) { + predicate = pb.and(predicate, pb.equals("companyId", companyId)); + return this; + } + + private RegistrySearch accountType(AccountType accountType) { + predicate = pb.and(predicate, pb.equals("accountType", accountType.getKey())); + return this; + } + + private RegistrySearch accountId(Long accountId) { + predicate = pb.and(predicate, pb.equals("accountId", accountId)); + return this; + } + + private RegistrySearch contract(String contract) { + predicate = pb.and(predicate, pb.equals("contract", contract)); + return this; + } + + private RegistrySearch status() { + predicate = pb.and(predicate, pb.or( + pb.equals("registryStatus", RegistryStatus.PROC.getKey()), + pb.equals("registryStatus", RegistryStatus.MNG.getKey()) + )); + return this; + } + + private Optional find() { + return Optional.ofNullable(registryImdg.getSingleObjectByPredicate(predicate)); + } + } + private Optional findRegByUnit(Statement s, Registry registry, RegistryUnit unit) { RegistryTradingParams p = new RegistryTradingParams( IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation()), @@ -445,6 +648,19 @@ public class Sdf57Executor extends AbstractExecutor { return LocalDate.parse(payDate, payDateFormatter); } + private static String getTkrCodeFromComment(String comment) { + if (comment == null) { + return null; + } + comment = comment.toUpperCase(); + int tcrIndex = comment.indexOf("ТКР"); + if (tcrIndex == -1) { + return null; + } + comment = comment.substring(tcrIndex + 3); + return comment.replaceAll("\\s+", ""); + } + private String getContractFromSpecif(String specif) { if (specif == null) { return null; diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java index 03512296f..dd751417e 100644 --- a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java @@ -36,6 +36,7 @@ public record RegistryTradingParams(RegistryDesignation registryDesignation, public final static RegistryTradingParams AS__; public final static RegistryTradingParams CM__; public final static RegistryTradingParams LM__; + public final static RegistryTradingParams DMAU; static { OS_T = new RegistryTradingParams(RegistryDesignation.O, @@ -127,6 +128,10 @@ public record RegistryTradingParams(RegistryDesignation registryDesignation, RegistryInstrumentType.M, null, null); + DMAU = new RegistryTradingParams(RegistryDesignation.D, + RegistryInstrumentType.M, + RegistryCapacity.A, + RegistryUnit.U); } } diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryUnit.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryUnit.java index 230107b42..14215bf26 100644 --- a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryUnit.java +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryUnit.java @@ -9,6 +9,7 @@ public enum RegistryUnit implements IEnumKey { F("F"), B("B"), X("X"), + U("U"), ; private final String key;