SDF57 обработка

1. DMAU регистры
2. поиск счетов для кейса accountType=ANLT
This commit is contained in:
ialbert 2023-07-07 19:22:06 +03:00
parent 075591d2ea
commit 28102d34af
6 changed files with 243 additions and 14 deletions

View file

@ -27,6 +27,8 @@ public enum ClearingError implements IErrorEnumId {
AccountNotFoundB(5217L),
MarketIsNotMkr(5217L),
BalanceInsufficient(5222L),
TCRegistryNotFound(3022L),
WrongField(5004L),
ActiveSessionIsPresent(-1L),
;

View file

@ -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<TradingClearingRegistry> tcrsByAccount = tradingClearingRegistryImdg.getCollectionObjectsByFieldValues(Map.of(
"moneyAccountId", statement.getAccountId(),
"companyId", statement.getAddresseeId(),
"moneyAccountId", account.getId(),
"companyId", company.getId(),
"status", ServiceStatus.Active.getKey()
));
if (!tcrsByAccount.isEmpty()) {

View file

@ -229,7 +229,6 @@ public class Sdf01Executor extends AbstractExecutor<SDf01> {
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());

View file

@ -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<SDf57> {
private final Imdg<AccountBalance> accountBalanceImdg;
private final Imdg<ClearingAccount> clearingAccountImdg;
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private final Imdg<Account> accountImdg;
private final Imdg<Company> companyImdg;
private final Imdg<Security> securityImdg;
private final Imdg<Currency> currencyImdg;
private final IMessageResolver messageResolver;
@ -82,6 +86,8 @@ public class Sdf57Executor extends AbstractExecutor<SDf57> {
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<SDf57> {
return;
Optional<EnumMessage> err = validateActiveness(company, account);
if (err.isEmpty()) {
findRegByDesignation(stmt, RegistryTradingParams.AM_T, false, false).ifPresentOrElse(rgs -> {
Optional<Registry> 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<SDf57> {
//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<Registry> dm__Found = findRegByDesignation(stmt, RegistryTradingParams.DM__, true, false);
Optional<Registry> dm__Found = RegistrySearch.builder(registryImdg)
.rgsCode(RegistryTradingParams.DM__)
.companyId(company.getId())
.accountId(account.getId())
.contract(stmt.getContract())
.find();
Optional<Registry> om_tFound = Optional.empty();
Optional<Registry> 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<SDf57> {
statementImdg.update(stmt);
}
};
statementDeb.ifPresent(stmt -> createRegistryIfNeeded.accept(new StmtCmpAcc(stmt, companyDeb, accountDeb)));
statementCred.ifPresent(stmt -> createRegistryIfNeeded.accept(new StmtCmpAcc(stmt, companyCred, accountCred)));
Consumer<StmtCmpAcc> registersUpdate = stmtCmpAcc -> {
Statement stmt = stmtCmpAcc.statement();
Company cmp = stmtCmpAcc.company();
Account acc = stmtCmpAcc.account();
createRegistryIfNeeded.accept(stmtCmpAcc);
if (accountIsAnlt(acc)) {
Optional<Pair<Company, Account>> 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<Registry> 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<Pair<Company, Account>> 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<SDf57> {
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<SDf57> {
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<SDf57> {
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<SDf57> {
return Optional.ofNullable(registryImdg.getSingleObjectByPredicate(rgstrPredicate));
}
private static class RegistrySearch {
private final ImdgPredicateBuilder pb;
private final Imdg<Registry> registryImdg;
private ImdgPredicate predicate;
private RegistrySearch(Imdg<Registry> registryImdg) {
this.registryImdg = registryImdg;
this.pb = registryImdg.predicateBuilder();
}
private static RegistrySearch builder(Imdg<Registry> 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<Registry> find() {
return Optional.ofNullable(registryImdg.getSingleObjectByPredicate(predicate));
}
}
private Optional<Registry> 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<SDf57> {
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;

View file

@ -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);
}
}

View file

@ -9,6 +9,7 @@ public enum RegistryUnit implements IEnumKey {
F("F"),
B("B"),
X("X"),
U("U"),
;
private final String key;