1. Sessions currency (TRAN/ANLT accounts) fixes

2. ExecutionDeposit/ExecutionFond SettlementCurrency fix
3. payment-outbound dm*i search currency
4. TcrListNew validation - already present TcrList for specified currency
5. account-service do not create accounts for 'not-found' currencies
This commit is contained in:
ialbert 2024-05-08 17:57:56 +03:00
parent da63e9c236
commit 23604146f8
18 changed files with 286 additions and 122 deletions

View file

@ -1,5 +1,12 @@
package ru.spcex.clearing.account.config.validation;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -28,11 +35,6 @@ import ru.spcex.platform.utils.validation.IValidationRule;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@Configuration
public class TradingClearingRegistryListValidationConfig {
@ -64,7 +66,8 @@ public class TradingClearingRegistryListValidationConfig {
ServiceStatusDictionary.class,
AccountError.RequiredFieldEmpty,
AccountError.DictionaryNotFound,
false)
false),
NotAlreadyPresent.instance
);
};
}
@ -121,6 +124,32 @@ public class TradingClearingRegistryListValidationConfig {
};
}
public static class NotAlreadyPresent implements IValidationRule<ImdgValidationContext<TradingClearingRegistryListNewRequest>> {
private static final NotAlreadyPresent instance = new NotAlreadyPresent();
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<TradingClearingRegistryListNewRequest> ctx) {
TradingClearingRegistryListNewRequest tcrListReq = ctx.getValidatedObject();
Long accountId = tcrListReq.getAccountId();
Imdg<TradingClearingRegistryList> tcrListImdg = ctx.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class);
ImdgPredicateBuilder pb = tcrListImdg.predicateBuilder();
Collection<TradingClearingRegistryList> tcrLists = tcrListImdg.getCollectionObjectsByPredicate(
pb.and(
pb.equals("tradingClearingRegistryId", tcrListReq.getTradingClearingRegistryId()),
pb.equals("status", WorkflowStatus.Active.getKey())
)
);
if (tcrLists.stream().anyMatch(tcrList -> Objects.equals(accountId, tcrList.getAccountId()))) {
return of(AccountError.AccountForTradingClearingRegistryAlreadyUsed, accountId);
}
return empty();
}
@Override
public String ruleName() {
return "TradingClearingRegistryList.AlreadyPresent";
}
}
public static class ExistAllAccountId<R> implements IValidationRule<ImdgValidationContext<R>> {
String fieldName;

View file

@ -275,18 +275,27 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
for (AccountSdfRequestPart accountReq : req.getAccounts()) {
Instant now = Instant.now();
Account account = new Account();
try {
Long currencyId = Long.valueOf(accountReq.getAccount().substring(5, 8));
Currency currency = currImdg.getSingleObjectByID(currencyId);
account.setCurrency(currency.getCurrencyCode());
} catch (Throwable e) {
AccountSdfToStatementRequestPart responsePart = new AccountSdfToStatementRequestPart();
responsePart.setSdfId(accountReq.getSdfId());
responsePart.setErrorCode(AccountError.DictionaryNotFound.getId()); // see accountService.fillAccountFromRelation
responsePart.setErrorText("couldn't extract currency from '%s' account".formatted(accountReq.getAccount()));
accountToStatement.add(responsePart);
log.info("sdf.id={} companyId={} accountType={} couldn't find currency for account {}",
accountReq.getSdfId(),
accountReq.getCompanyId(),
accountReq.getAccountType(),
accountReq.getAccount());
continue accountsLoop;
}
account.setAccount(accountReq.getAccount());
account.setAccountType(AccountType.Clrn.getKey());
account.setStatus(ServiceStatus.Active.getKey());
account.setCompanyId(accountReq.getCompanyId());
if (!TextUtil.isEmpty(accountReq.getAccount()) && accountReq.getAccount().length() >= 7) {
try {
Long currencyId = Long.valueOf(accountReq.getAccount().substring(5, 8));
Currency currency = currImdg.getSingleObjectByID(currencyId);
account.setCurrency(currency.getCurrencyCode());
} catch (Throwable e) {
}
}
if (TextUtil.isEmpty(account.getCurrency())) {
log.warn("Sdf52: Wrong accountValue=\"{}\" - can not parse for get currency", accountReq.getAccount());
}
@ -621,6 +630,7 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
request.setGroupId(groupingSdf01Id);
request.setChildGenerationId(groupSdf02Id);
request.setAccountCreationResults(results);
request.setFromAccount(true);
request.setContinueSdf(true);
request.setTable(SdfTable.SDF_01); // по нему запрос получили
log.debug("Send message to kafka \"{}\": {}", destination, LogFormatter.toStringWrapper(request));

View file

@ -1,5 +1,9 @@
package ru.spcex.clearing.account.service;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
@ -24,17 +28,18 @@ 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.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.DepoAccountType;
import ru.spcex.platform.enumeration.ObjectType;
import ru.spcex.platform.enumeration.Priority;
import ru.spcex.platform.enumeration.SdfTable;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
@Service
public class DepoAccountService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
@ -241,6 +246,7 @@ public class DepoAccountService extends QueueConsumer implements InitializingBea
request.setChildGenerationId(groupingSdf02Id);
request.setContinueSdf(true);
request.setAccountCreationResults(results);
request.setFromAccount(true);
request.setTable(SdfTable.SDF_08); // по нему запрос получили
log.debug("Send message to kafka \"{}\": {}", Consts.STATEMENT_PROCESS, LogFormatter.toStringWrapper(request));
kafkaSender.sendRequestToQueue(Consts.STATEMENT_PROCESS, request);

View file

@ -162,7 +162,7 @@ public class AnltSearcher {
this.company = company;
this.tcr = tcr;
this.tcrList = tcrList;
this.currency = CurrencyCode.RUB.getKey();
this.currency = currency;
}
public boolean isFound() {

View file

@ -231,14 +231,14 @@ public class RegistryService {
registries.size(), tcr.getId(), tcr.getMoneyAccountId());
}
Account acc = ref.tcrList == null ? accImdg.getSingleObjectByID(tcr.getMoneyAccountId())
: accImdg.getSingleObjectByID(ref.tcrList.getAccountId());
Long searchAccId = ref.tcrList == null ? tcr.getMoneyAccountId() : ref.tcrList.getAccountId();
Account acc = accImdg.getSingleObjectByID(searchAccId);
Currency currency = ref.tcrList == null ? currImdg.getFirstObjectBySQL("currencyCode = '%s'".formatted(CurrencyCode.RUB.getKey()))
: ref.currency;
Company cmp = cmpImdg.getSingleObjectByID(tcr.getCompanyId());
if (acc == null) {
log.warn("TCR#id={} account {} not found", tcr.getId(), tcr.getMoneyAccountId());
log.warn("TCR#id={} account {} not found", tcr.getId(), searchAccId);
return;
}
if (currency == null) {

View file

@ -42,8 +42,8 @@ public class Sdf03Creator {
String c_acc_deb = null;
String c_acc_cred = null;
if (AccountType.Info.equals(creditAccType) ^ AccountType.Info.equals(debAccType)) {
Account anltAcc = accountImdg.getFirstObjectBySQL("accountType = '%s' and status = '%s'"
.formatted(AccountType.Anlt.getKey(), Status.Active.getKey()));
Account anltAcc = accountImdg.getFirstObjectBySQL("accountType = '%s' and status = '%s' and currency = '%s'"
.formatted(AccountType.Anlt.getKey(), Status.Active.getKey(), paymentInstruction.getCreditLeg_currencyCode()));
if (anltAcc == null) {
throw new IllegalStateException("SDF03 creation error: paymentInstruction.creditLeg_accountId="
+ paymentInstruction.getCreditLeg_accountId() + " accountType 'Info' but no 'ANLT' account found");

View file

@ -1,5 +1,8 @@
package ru.spcex.clearing.service;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@ -11,18 +14,19 @@ import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.sdf.SDf54;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.CompanySymbol;
import ru.spcex.platform.enumeration.Sender;
import ru.spcex.platform.enumeration.Status;
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.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.IEnumKey;
import ru.spcex.platform.utils.number.BigDecimalUtil;
import ru.spcex.platform.utils.time.TimeUtil;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Map;
@Component
public class Sdf54Creator {
private Logger log = LoggerFactory.getLogger(getClass());
@ -30,6 +34,7 @@ public class Sdf54Creator {
private final Imdg<Company> companyImdg;
private final Imdg<CompanySymbols> companySymbolImdg;
private final Imdg<Account> accountImdg;
private final Imdg<SDf54> sdf54Imdg;
private final Imdg<BankAccount> bankAccountImdg;
private final ImdgId idGenerator;
private static DateTimeFormatter payDateFormatter = DateTimeFormatter.ofPattern("dd.MM.yy");
@ -40,6 +45,7 @@ public class Sdf54Creator {
this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
this.companySymbolImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
this.bankAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_BankAccount, BankAccount.class);
this.sdf54Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf54, SDf54.class);
this.idGenerator = imdgProvider.getImdgIdGenerator();
}
@ -103,9 +109,17 @@ public class Sdf54Creator {
sDf54.setInn_cred(bnkAcc.getTaxpayerIdentificationNumber());
sDf54.setKpp_cred(bnkAcc.getTaxRegistrationReasonCode());
c_acc_cred = bnkAcc.getCorrespondentAccount();
sDf54.setSwift_ben(bnkAcc.getSwiftCode());
} else {
log.warn("Bank account not found for DebitLeg_accountId={}", paymentInstruction.getDebitLeg_accountId());
}
sDf54.setDoc_Num(String.valueOf(nextDocNum()));
BankAccount prcBankAcc = bankAccountImdg.getFirstObjectBySQL("companyId = %d".formatted(Sender.Prc.getId()));
if (prcBankAcc != null) {
sDf54.setSwift_int(prcBankAcc.getSwiftCode());
}
sDf54.setDoc_Date(null);
sDf54.setValue_date(null);
sDf54.setAcc_kr_1(paymentInstruction.getDebitLeg_account());
{
@ -161,7 +175,7 @@ public class Sdf54Creator {
}
sDf54.setPay_date(payDateFormatter.format(TimeUtil.toLocalDate(paymentInstruction.getPaymentDate())));
sDf54.setPay_val(CurrencyCode.RUB.getKey());
sDf54.setPay_val(paymentInstruction.getCreditLeg_currencyCode());
String sumDeb = paymentInstruction.getDebitLeg_amount() != null ? paymentInstruction.getDebitLeg_amount().toString() : "";
sDf54.setSum_deb(BigDecimalUtil.limitDecimalPlaces(sumDeb, 2));
sDf54.setSpecif_1(paymentInstruction.getPaymentPurpose());
@ -175,6 +189,26 @@ public class Sdf54Creator {
return IEnumKey.getEnumByKey(AccountType.class, account.getAccountType());
}
private int nextDocNum() {
ImdgPredicateBuilder pb = sdf54Imdg.predicateBuilder();
SDf54 sDf54 = sdf54Imdg.aggregateByMax(
"id", pb.and(
pb.greatEqual("generationTime", TimeUtil.today()),
pb.notNull("Doc_Num")
)
);
if (sDf54 != null) {
try {
int num = Integer.parseInt(sDf54.getDoc_Num());
return ++num;
} catch (Throwable e) {
log.error("couldn't parse sdf54.id={} doc_num {}", sDf54.getId(), sDf54.getDoc_Num());
return 1;
}
}
return 1;
}
protected String selectSymbolValue(Long companyId, CompanySymbol symbol) {
if (companyId == null) {
return null;

View file

@ -1,5 +1,11 @@
package ru.spcex.clearing.service.builder;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -10,19 +16,20 @@ import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.security.Security;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.Allowed;
import ru.spcex.platform.enumeration.CompanySymbol;
import ru.spcex.platform.enumeration.CurrencyCode;
import ru.spcex.platform.enumeration.InOutDirection;
import ru.spcex.platform.enumeration.Sender;
import ru.spcex.platform.enumeration.Status;
import ru.spcex.platform.enumeration.TransactionStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.collection.Pair;
import ru.spcex.platform.utils.text.TextUtil;
import ru.spcex.platform.utils.time.TimeUtil;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* Builder для кейса итоговой сессии МКР, 7 шаг, кейс - по сделкам
*/
@ -44,6 +51,7 @@ public class PaymentInstructionBuilderFinalMkrDeals {
protected AtomicLong documentNumberId = new AtomicLong(0L); // порядковый номер (сквозной по всем компаниям за день
private static final DateTimeFormatter DATE_FORMATTER_ddMMyy = DateTimeFormatter.ofPattern("ddMMyy");
private String purpose;
private String currency;
private String lmtPurpose = null;
public static PaymentInstructionBuilderFinalMkrDeals builder(ImdgProvider imdgProvider) {
@ -92,6 +100,11 @@ public class PaymentInstructionBuilderFinalMkrDeals {
return this;
}
public PaymentInstructionBuilderFinalMkrDeals currency(String currency) {
this.currency = currency;
return this;
}
public Pair<PaymentInstruction, PaymentInstruction> build() {
PaymentInstruction payment1;
@ -165,8 +178,13 @@ public class PaymentInstructionBuilderFinalMkrDeals {
}
payment1.setDebit_csAccount(null);
payment1.setCreditLeg_currencyCode(CurrencyCode.RUB.getKey());
payment1.setDebitLeg_currencyCode(CurrencyCode.RUB.getKey());
if (TextUtil.isEmpty(currency)) {
payment1.setCreditLeg_currencyCode(CurrencyCode.RUB.getKey());
payment1.setDebitLeg_currencyCode(CurrencyCode.RUB.getKey());
} else {
payment1.setCreditLeg_currencyCode(currency);
payment1.setDebitLeg_currencyCode(currency);
}
payment1.setTransactionStatus(TransactionStatus.stld.getKey());
payment1.setDocumentNumber(nextDocumentNumber(lm_t, payment1));
payment1.setCreditLeg_direction(InOutDirection.out.getKey());
@ -221,8 +239,13 @@ public class PaymentInstructionBuilderFinalMkrDeals {
payment2.setDocumentNumber(nextDocumentNumber(cm_t, payment2));
payment2.setCreditLeg_direction(InOutDirection.out.getKey());
payment2.setDebitLeg_direction(InOutDirection.in.getKey());
payment2.setCreditLeg_currencyCode(CurrencyCode.RUB.getKey());
payment2.setDebitLeg_currencyCode(CurrencyCode.RUB.getKey());
if (TextUtil.isEmpty(currency)) {
payment2.setCreditLeg_currencyCode(CurrencyCode.RUB.getKey());
payment2.setDebitLeg_currencyCode(CurrencyCode.RUB.getKey());
} else {
payment2.setCreditLeg_currencyCode(currency);
payment2.setDebitLeg_currencyCode(currency);
}
payment2.setCreditLeg_securityId(lm_t.getSecurityId());
payment2.setDebitLeg_securityId(lm_t.getSecurityId());
payment2.setSessionId(sessionId);

View file

@ -1,5 +1,13 @@
package ru.spcex.clearing.service.execution;
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.Function;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -22,7 +30,9 @@ import ru.spcex.clearing.platform.messaging.domain.cud.registry.DealRegisterNewR
import ru.spcex.clearing.platform.messaging.domain.cud.registry.ExecutionType;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.service.validation.ValidationStored;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.enumeration.MoneyFlowSide;
import ru.spcex.platform.enumeration.Section;
import ru.spcex.platform.enumeration.Side;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
@ -34,15 +44,6 @@ import ru.spcex.platform.utils.log.ExceptionUtils;
import ru.spcex.platform.utils.time.TimeUtil;
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.Function;
/**
* 1.35. executionDeposit - Сделки
* I - Изменение executionDeposit при получении новых сделок из ТС (s_trade)
@ -212,7 +213,7 @@ public class ExecutionDepositComponent {
}
}
}
eDeposit.setSettlementCurrency(CurrencyCode.RUB.getKey());
eDeposit.setSettlementCurrency(sTrades.getSettleCurrency());
eDeposit.setCompanyId(company.getId());
eDeposit.setDuration(sTrades.getRepoTerm());
eDeposit.setFirstLegSettlementDate(sTrades.getSettleDate());

View file

@ -53,10 +53,10 @@ import ru.spcex.platform.utils.enumeration.IEnumKey;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.enumeration.SimpleMessageResolver;
import ru.spcex.platform.utils.log.ExceptionUtils;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
import ru.spcex.platform.utils.text.TextUtil;
import ru.spcex.platform.utils.time.TimeUtil;
import ru.spcex.platform.utils.validation.IValidator;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
@Component
@EnableScheduling
@ -224,7 +224,7 @@ public class ExecutionFondComponent {
}
}
//fixme символьный код по справочнику currencyCode, соответствующий значению из sTrades.settleCurrency
eFond.setSettlementCurrency(CurrencyCode.RUB.getKey());
eFond.setSettlementCurrency(sTrades.getSettleCurrency());
//fixme micro vs milli
eFond.setExchangeExecutionMicroseconds(Instant.ofEpochMilli(sTrades.getTradeTimeMs()));
eFond.setCompanyId(company.getId());

View file

@ -131,7 +131,7 @@ public class Sdf01Executor extends AbstractExecutor<SDf01> {
Optional<EnumMessage> error = validator.tillFirstError();
Company company = validator.getStored(ValidationStored.Sdf01Company);
Account account = validator.getStored(ValidationStored.Sdf01Account);
if (statementRequest.getAccountCreationResults().size() == 0
if (!statementRequest.isFromAccount()
&& ClearingError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
//на данном шаге company существует -> getId ok
//формируем пакетный запрос на добавление account

View file

@ -1,5 +1,9 @@
package ru.spcex.clearing.service.executors;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Optional;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
@ -21,13 +25,9 @@ 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.text.TextUtil;
import ru.spcex.platform.utils.validation.IValidator;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Optional;
import java.util.function.Function;
@Service
public class Sdf55Executor {
private final Logger log = LoggerFactory.getLogger(getClass());
@ -68,7 +68,8 @@ public class Sdf55Executor {
pmt.setTransactionStatus(TransactionStatus.ok.getKey());
pmt.setUpdated(Instant.now());
pmtImdg.update(pmt);
dmiService.setContract(tcr.getId(), CurrencyCode.RUB.getKey(), sDf54.getDocnm_ref(), sDf55.getDocnmprev());
String curr = TextUtil.isEmpty(sDf55.getPay_val()) ? CurrencyCode.RUB.getKey() : sDf55.getPay_val();
dmiService.setContract(tcr.getId(), curr, sDf54.getDocnm_ref(), sDf55.getDocnmprev());
assets.process(assetTrio.a__b(),
assetTrio.a__t(),
assetTrio.a__f(),

View file

@ -52,6 +52,7 @@ import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
import ru.spcex.platform.utils.text.TextUtil;
import ru.spcex.platform.utils.validation.IValidator;
@Service
@ -151,7 +152,8 @@ public class PaymentInstructionOutboundService {
pmt.setAddresseeBankName(bnkAcc.getBankName());
pmt.setDebit_csAccount(bnkAcc.getCorrespondentAccount());
}
Currency currency = currImdg.getFirstObjectBySQL("currencyCode = '%s'".formatted(CurrencyCode.RUB.getKey()));
String curr = TextUtil.isEmpty(accCred.getCurrency()) ? CurrencyCode.RUB.getKey() : accCred.getCurrency();
Currency currency = currImdg.getFirstObjectBySQL("currencyCode = '%s'".formatted(curr));
if (currency != null) {
pmt.setCreditLeg_securityId(currency.getId());
pmt.setDebitLeg_securityId(currency.getId());
@ -178,7 +180,7 @@ public class PaymentInstructionOutboundService {
sdf54Imdg.insert(sDf54);
log.debug("new sdf54.id: {}", sDf54.getId());
dmiService.setProcComment(tcr.getId(),
CurrencyCode.RUB.getKey(),
curr,
safeBD(amount).negate(),
sDf54.getDocnm_ref());
assetsMng.process(assets.get().a__b(), assets.get().a__t(), assets.get().a__f(), BigDecimal.ZERO);

View file

@ -1,5 +1,14 @@
package ru.spcex.clearing.session.stage.impl;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -32,6 +41,7 @@ import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.Allowed;
import ru.spcex.platform.enumeration.RegistryStatus;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
@ -42,14 +52,6 @@ import ru.spcex.platform.utils.collection.Pair;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumKey;
import ru.spcex.platform.utils.number.BigDecimalUtil;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
@Service
@ -107,13 +109,6 @@ public class FormingPaymentInstructionDepositReturn implements ISessionStage {
private StageResult formingPaymentInstruction(Long sessionId) {
Instant now = Instant.now();
Account tranAcc = accountImdg.getFirstObjectBySQL("accountType = '%s' and status = '%s' and processingSign = '%s'"
.formatted(AccountType.Tran.getKey(), AccountStatus.ACTIVE.getKey(), Allowed.ALLOWED.getKey()));
if (tranAcc == null) {
return new StageResult<>(
new EnumMessage(ClearingError.AccountNotPresent, "accountType = " + AccountType.Tran.getKey()),
false);
}
RegistryCodeSqlBuilder registryCodeSqlBuilder = RegistryCodeSqlBuilder.getInstance(LM_T,CM_T, LS_T, CS_T);
String registryCodeCondition = registryCodeSqlBuilder.build();
@ -145,6 +140,19 @@ public class FormingPaymentInstructionDepositReturn implements ISessionStage {
}
Registry lm_t = lmtO.get(); //obligation by money
Registry cm_t = cmtO.get();
Account tranAcc = accountImdg.getFirstObjectBySQL(("accountType = '%s'" +
" and status = '%s'" +
" and processingSign = '%s'" +
" and currency = '%s'")
.formatted(AccountType.Tran.getKey(),
AccountStatus.ACTIVE.getKey(),
Allowed.ALLOWED.getKey(),
lm_t.getSecuritySymbol()));
if (tranAcc == null) {
return new StageResult<>(
new EnumMessage(ClearingError.AccountNotPresent, "accountType = " + AccountType.Tran.getKey()),
false);
}
Optional<Registry> dmx = rgsMng.searchDmxByCounterPartyNotOk(lm_t);
if (dmx.isPresent()) {
log.debug("groupId {} LM*T#id={}, DM*X#id={} found, no action needed, skipping liability",
@ -165,6 +173,7 @@ public class FormingPaymentInstructionDepositReturn implements ISessionStage {
.sessionId(sessionId)
.paymentPurposeLmt("Возврат депозита " + lm_t.getContract() + " по ТКР " + lm_t.getTradingClearingRegistry())
.paymentPurpose("Возврат депозита " + cm_t.getContract() + " по ТКР " + cm_t.getTradingClearingRegistry())
.currency(lm_t.getSecuritySymbol())
.build();
Pair.forEach(pmts, paymentInstructionImdg::insert);
Pair.forEach(pmts, pmtCreated::add);
@ -224,13 +233,12 @@ public class FormingPaymentInstructionDepositReturn implements ISessionStage {
.sessionId(sessionId)
.paymentPurpose("Возврат депозита " + cm_t.getContract() + " по ТКР " + cm_t.getTradingClearingRegistry())
.paymentPurposeLmt("Возврат депозита " + lm_t.getContract() + " по ТКР " + lm_t.getTradingClearingRegistry())
.currency(lm_t.getSecuritySymbol())
.build();
paymentInstructionImdg.insert(pmts.getFirst());
paymentInstructionImdg.insert(pmts.getSecond());
Pair.forEach(pmts, paymentInstructionImdg::insert);
Pair.forEach(pmts, pmtCreated::add);
log.debug("groupId {} LM*T#id={}, CM*T#id={} found, PaymentInstruction id={} and id={} created",
lm_t.getGroupId(), lm_t.getId(), cm_t.getId(), pmts.getFirst().getId(), pmts.getSecond().getId());
pmtCreated.add(pmts.getFirst());
pmtCreated.add(pmts.getSecond());
dmtClnr.get().setRegistryStatus(RegistryStatus.OK.getKey());
setUpdatedStoreInImdg(dmtClnr.get(), now);
}

View file

@ -1,5 +1,15 @@
package ru.spcex.clearing.session.stage.impl;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -28,7 +38,17 @@ import ru.spcex.clearing.session.stage.ISessionStage;
import ru.spcex.clearing.session.stage.StageResult;
import ru.spcex.clearing.session.stage.Task;
import ru.spcex.clearing.session.stage.task.FormingPaymentInstructionPayload;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.Allowed;
import ru.spcex.platform.enumeration.InstrumentType;
import ru.spcex.platform.enumeration.RegistryCapacity;
import ru.spcex.platform.enumeration.RegistryDesignation;
import ru.spcex.platform.enumeration.RegistryInstrumentType;
import ru.spcex.platform.enumeration.RegistryStatus;
import ru.spcex.platform.enumeration.RegistryTradingParams;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
import ru.spcex.platform.enumeration.RegistryUnit;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
@ -41,14 +61,6 @@ import ru.spcex.platform.utils.enumeration.IEnumKey;
import ru.spcex.platform.utils.number.BigDecimalUtil;
import ru.spcex.platform.utils.time.TimeUtil;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class FormingPaymentInstructionReturnMkr implements ISessionStage {
@ -160,8 +172,14 @@ public class FormingPaymentInstructionReturnMkr implements ISessionStage {
continue;
}
Optional<Registry> dmtClnr = rgsMng.searchDmtClrnNotOk(lm_t);
Account tranAcc = accountImdg.getFirstObjectBySQL("accountType = '%s' and status = '%s' and processingSign = '%s'"
.formatted(AccountType.Tran.getKey(), AccountStatus.ACTIVE.getKey(), Allowed.ALLOWED.getKey()));
Account tranAcc = accountImdg.getFirstObjectBySQL(("accountType = '%s'" +
" and status = '%s'" +
" and processingSign = '%s'" +
" and currency = '%s'")
.formatted(AccountType.Tran.getKey(),
AccountStatus.ACTIVE.getKey(),
Allowed.ALLOWED.getKey(),
lm_t.getSecuritySymbol()));
if (tranAcc == null) {
return new StageResult<>(
new EnumMessage(ClearingError.AccountNotPresent, "accountType = " + AccountType.Tran.getKey()),
@ -188,13 +206,12 @@ public class FormingPaymentInstructionReturnMkr implements ISessionStage {
.sessionId(sessionId)
.paymentPurpose("Возврат депозита " + cm_t.getContract() + " по ТКР " + cm_t.getTradingClearingRegistry())
.paymentPurposeLmt("Возврат депозита " + lm_t.getContract() + " по ТКР " + lm_t.getTradingClearingRegistry())
.build();
paymentInstructionImdg.insert(pmts.getFirst());
paymentInstructionImdg.insert(pmts.getSecond());
.currency(lm_t.getSecuritySymbol())
.build();
Pair.forEach(pmts, paymentInstructionImdg::insert);
Pair.forEach(pmts, pmtCreated::add);
log.debug("LM*T#id={}, CM*T#id={} found, PaymentInstruction id={} and id={} created",
lm_t.getId(), cm_t.getId(), pmts.getFirst().getId(), pmts.getSecond().getId());
pmtCreated.add(pmts.getFirst());
pmtCreated.add(pmts.getSecond());
if (dmtClnr.isPresent()) {
dmtClnr.get().setRegistryStatus(RegistryStatus.OK.getKey());
setUpdatedStoreInImdg(dmtClnr.get(), now);

View file

@ -1,5 +1,16 @@
package ru.spcex.clearing.session.stage.impl;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -29,7 +40,13 @@ import ru.spcex.clearing.session.stage.Task;
import ru.spcex.clearing.session.stage.payment.group.PaymentGroup;
import ru.spcex.clearing.session.stage.payment.group.RegistryLiabilitiesGroup;
import ru.spcex.clearing.session.stage.task.FormingPaymentInstructionPayload;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.Allowed;
import ru.spcex.platform.enumeration.InstrumentType;
import ru.spcex.platform.enumeration.RegistryTradingParams;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
import ru.spcex.platform.enumeration.Sender;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
@ -42,15 +59,6 @@ import ru.spcex.platform.utils.enumeration.IEnumKey;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.enumeration.SimpleMessageResolver;
import ru.spcex.platform.utils.number.BigDecimalUtil;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
@Service
@ -231,21 +239,36 @@ public class FormingPaymentInstructionSecurities implements ISessionStage {
}
{
Collection<Registry> registries = selectMoneyRegistries(sessionId);
Account tranAcc = accountImdg.getFirstObjectBySQL("accountType = '%s' and status = '%s' and processingSign = '%s'"
.formatted(AccountType.Tran.getKey(), AccountStatus.ACTIVE.getKey(), Allowed.ALLOWED.getKey()));
Account dtrnAcc = accountImdg.getFirstObjectBySQL("accountType = '%s' and status = '%s' and processingSign = '%s'"
.formatted(AccountType.Dtrn.getKey(), AccountStatus.ACTIVE.getKey(), Allowed.ALLOWED.getKey()));
if (tranAcc == null || dtrnAcc == null) {
if (dtrnAcc == null) {
return new StageResult<>(
new EnumMessage(ClearingError.AccountNotPresent, "accountType = %s/%s"
.formatted(AccountType.Tran.getKey(), AccountType.Dtrn.getKey())),
new EnumMessage(ClearingError.AccountNotPresent, "accountType = %s"
.formatted(AccountType.Dtrn.getKey())),
false);
}
log.debug("found AS*B.size() = {}", registries.size());
log.debug("found AM*B.size() = {}", registries.size());
//группируем регистры по groupId
for (Registry registry : registries) {
Account tranAcc = accountImdg.getFirstObjectBySQL(("accountType = '%s'" +
" and status = '%s'" +
" and processingSign = '%s'" +
" and currency = '%s'")
.formatted(AccountType.Tran.getKey(),
AccountStatus.ACTIVE.getKey(),
Allowed.ALLOWED.getKey(),
registry.getSecuritySymbol()));
if (tranAcc == null) {
log.error("{} account not found for {}", AccountType.Tran.getKey(), registry.getSecuritySymbol());
return new StageResult<>(
new EnumMessage(ClearingError.AccountNotPresent, "accountType = %s"
.formatted(AccountType.Tran.getKey())),
false);
}
if (registry.getBalance().compareTo(BigDecimal.ZERO) == 0) {
log.debug("Skip creating paymentInstruction by registry with 0 balance");
continue;
@ -255,7 +278,7 @@ public class FormingPaymentInstructionSecurities implements ISessionStage {
if (AccountType.Clrn.equalsByKey(registry.getAccountType())) {
counterAcc = accountImdg.getSingleObjectByID(registry.getAccountId());
} else if (AccountType.Info.equalsByKey(registry.getAccountType())) {
counterAcc = accountImdg.getFirstObjectByFieldValues(Map.of("companyId", 1L, "accountType", AccountType.Anlt.getKey()));
counterAcc = accountImdg.getFirstObjectByFieldValues(Map.of("companyId", 1L, "accountType", AccountType.Anlt.getKey(), "currency", registry.getSecuritySymbol()));
}
Long senderId;
Long addresseeId;
@ -302,6 +325,7 @@ public class FormingPaymentInstructionSecurities implements ISessionStage {
.creditLegAccount(creditLegAccount)
.amount(amount)
.sessionId(sessionId)
.currency(registry.getSecuritySymbol())
.purpose(String.format("Перевод по итогу клиринга по ТКР %s", registry.getTradingClearingRegistry()));
PaymentInstruction paymentInstruction = paymentInstructionBuilder.build();
log.debug("Created paymentInstruction by registry.id: {}", registry.getId());

View file

@ -239,7 +239,7 @@ public class StatementServiceV2 {
}
AbstractExecutor service = sdf01Executor;
Result sdf01Res = service.execute(sdfGroup, sdf01);
if (sdf01Res.getAccountRequests().size() != 0) {
if (sdf01Res.getAccountRequests().size() != 0 && !sdf01.isFromAccount()) {
kafkaSender.sendRequestToQueue(Consts.ACCOUNT_NEW_SDF01, StatementService.createAccountsRequest(sdf01.getGroupId(), sdf01Res.getAccountRequests(), sdf01Res.getChildGenerationId()));
} else if (service.isNeedToSendCommand()) {
service.sendCommand(kafkaSender, sdf01Res);

View file

@ -1,10 +1,9 @@
package ru.spcex.clearing.platform.messaging.domain.cud.balance;
import com.fasterxml.jackson.annotation.JsonProperty;
import ru.spcex.platform.enumeration.SdfTable;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import ru.spcex.platform.enumeration.SdfTable;
public class StatementRequest {
@JsonProperty
@ -16,6 +15,8 @@ public class StatementRequest {
@JsonProperty
List<AccountSdfToStatementRequestPart> accountCreationResults = new ArrayList<>();
@JsonProperty
boolean fromAccount = false;
@JsonProperty
private Long childGenerationId;
@JsonProperty
private boolean continueSdf = false;
@ -59,4 +60,12 @@ public class StatementRequest {
public void setChildGenerationId(Long childGenerationId) {
this.childGenerationId = childGenerationId;
}
public boolean isFromAccount() {
return fromAccount;
}
public void setFromAccount(boolean fromAccount) {
this.fromAccount = fromAccount;
}
}