From 0c0bc7d910c64d09be486a0ab116d0b9432adbbd Mon Sep 17 00:00:00 2001 From: ialbert Date: Fri, 11 Aug 2023 19:48:45 +0300 Subject: [PATCH] =?UTF-8?q?IPOT=207=20=D1=88=D0=B0=D0=B3=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8E=20PaymentInstruction=20=D0=BF=D0=BE=20=D0=B1=D1=83?= =?UTF-8?q?=D0=BC=D0=B0=D0=B3=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...aymentInstructionBuilderForSecurities.java | 211 ++++++++++++ .../stage/PrimaryAuctionT0Session.java | 16 +- .../FormingPaymentInstructionSecurities.java | 301 ++++++++++++++++++ .../stage/payment/group/PaymentGroup.java | 38 +++ .../group/RegistryLiabilitiesGroup.java | 65 ++++ 5 files changed, 624 insertions(+), 7 deletions(-) create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/PaymentInstructionBuilderForSecurities.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FormingPaymentInstructionSecurities.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/PaymentGroup.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/RegistryLiabilitiesGroup.java diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/PaymentInstructionBuilderForSecurities.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/PaymentInstructionBuilderForSecurities.java new file mode 100644 index 000000000..55b5bc356 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/PaymentInstructionBuilderForSecurities.java @@ -0,0 +1,211 @@ +package ru.spcex.clearing.service.builder; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.company.CompanySymbols; +import ru.clearing.classes.statics.data.payment.PaymentInstruction; +import ru.clearing.classes.statics.data.registry.Registry; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.platform.enumeration.CompanySymbol; +import ru.spcex.platform.enumeration.CurrencyCode; +import ru.spcex.platform.enumeration.InOutDirection; +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.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; + +public class PaymentInstructionBuilderForSecurities { + private final static Logger log = LoggerFactory.getLogger(PaymentInstructionBuilderForSecurities.class); + private Registry registry; + private ImdgProvider imdgProvider; + private Imdg companyImdg; + private Imdg companySymbolsImdg; + private Long sessionId; + private BigDecimal amount; + private Long creditLegAccountId; + private String creditLegAccount; + private Long debitLegAccountId; + private String debitLegAccount; + + private String purpose; + protected LocalDate documentNumberResetAt; + protected AtomicLong documentNumberId = new AtomicLong(0L); // порядковый номер (сквозной по всем компаниям за день + private static final DateTimeFormatter DATE_FORMATTER_ddMMyy = DateTimeFormatter.ofPattern("ddMMyy"); + private Long senderId; + private Long addresseeId; + + public static PaymentInstructionBuilderForSecurities builder(ImdgProvider imdgProvider) { + return new PaymentInstructionBuilderForSecurities(imdgProvider); + } + + private PaymentInstructionBuilderForSecurities(ImdgProvider imdgProvider) { + this.imdgProvider = imdgProvider; + this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + this.companySymbolsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); + } + + public PaymentInstructionBuilderForSecurities sessionId(Long sessionId) { + this.sessionId = sessionId; + return this; + } + + public PaymentInstructionBuilderForSecurities ls_t(Registry registry) { + this.registry = registry; + return this; + } + + public PaymentInstructionBuilderForSecurities amount(BigDecimal amount) { + this.amount = amount; + return this; + } + + public PaymentInstructionBuilderForSecurities creditLegAccount(String account) { + this.creditLegAccount = account; + return this; + } + + public PaymentInstructionBuilderForSecurities debitLegAccount(String account) { + this.debitLegAccount = account; + return this; + } + + public PaymentInstructionBuilderForSecurities creditLegAccountId(Long accountId) { + this.creditLegAccountId = accountId; + return this; + } + + public PaymentInstructionBuilderForSecurities debitLegAccountId(Long accountId) { + this.debitLegAccountId = accountId; + return this; + } + + public PaymentInstructionBuilderForSecurities purpose(String purpose) { + this.purpose = purpose; + return this; + } + + public PaymentInstructionBuilderForSecurities sender(Long senderId) { + this.senderId = senderId; + return this; + } + + public PaymentInstructionBuilderForSecurities addressee(Long addresseeId) { + this.addresseeId = addresseeId; + return this; + } + + public PaymentInstruction build() { + Instant now = Instant.now(); + PaymentInstruction payment = new PaymentInstruction(); + payment.setCreated(now); + payment.setClearingDate(TimeUtil.toLocalDate(now)); + payment.setSenderId(senderId); + payment.setAddresseeId(addresseeId); +// { +// String tranBic = selectSymbolValue(payment.getAddresseeId(), CompanySymbol.BIC); +// if (tranBic == null) { +// log.warn("CompanySymbols BIC not found for companyId={}", payment.getAddresseeId()); +// } else { +// payment.setAdresseeBic(tranBic); +// } +// } +// { +// Company companyPRC = companyImdg.getSingleObjectByID(Sender.Prc.getId()); // 2 "НКО АО ПРЦ" +// if (companyPRC == null) { +// log.warn("Company.id={} not found", Sender.Prc.getId()); +// } else { +// payment.setPayeeBankName(companyPRC.getShortName()); +// payment.setAddresseeBankName(companyPRC.getShortName()); +// } +// } +// { +// String payeeBic = selectSymbolValue(payment.getSenderId(), CompanySymbol.BIC); +// if (payeeBic == null) { +// log.warn("payeeBic by senderId={} not found", payment.getSenderId()); +// } else { +// payment.setPayeeBic(payeeBic); +// } +// } + + if (registry.getSettlementDate() != null) { + payment.setPaymentDate(TimeUtil.localDateToInstant(registry.getSettlementDate())); + payment.setSettlementDate(registry.getSettlementDate()); + } else { + payment.setPaymentDate(Instant.now()); + payment.setSettlementDate(LocalDate.now()); + } + payment.setPaymentPurpose(purpose); + payment.setCreditLeg_amount(amount); + payment.setDebitLeg_amount(amount); + + { + payment.setCreditLeg_accountId(creditLegAccountId); + payment.setCreditLeg_account(creditLegAccount); + } + + payment.setCredit_csAccount(null); + + { + payment.setDebitLeg_accountId(debitLegAccountId); + payment.setDebitLeg_account(debitLegAccount); + } + + payment.setDebit_csAccount(null); + payment.setCreditLeg_currencyCode(CurrencyCode.RUB.getKey()); + payment.setDebitLeg_currencyCode(CurrencyCode.RUB.getKey()); + payment.setTransactionStatus(TransactionStatus.stld.getKey()); + payment.setDocumentNumber(nextDocumentNumber(registry, payment)); + payment.setCreditLeg_direction(InOutDirection.out.getKey()); + payment.setDebitLeg_direction(InOutDirection.in.getKey()); + payment.setCreditLeg_securityId(registry.getSecurityId()); + payment.setDebitLeg_securityId(registry.getSecurityId()); + payment.setSessionId(sessionId); + return payment; + } + + protected String nextDocumentNumber(Registry rgs, PaymentInstruction paymentInstruction) { + if (StringUtils.isEmpty(rgs.getContract())) { + return ""; + } + LocalDate nowD = LocalDate.now(); + if (documentNumberResetAt == null || documentNumberResetAt.isBefore(nowD)) synchronized (this) { + long oldNum = documentNumberId.get(); // reset optimistic + if (oldNum > 0) { + while (!documentNumberId.compareAndSet(oldNum, 0)) { + oldNum = documentNumberId.get(); + if (oldNum < 2) break; + } + } + documentNumberResetAt = nowD; + } + String paymentDate = DATE_FORMATTER_ddMMyy.format(TimeUtil.toLocalDate(paymentInstruction.getPaymentDate())); + String num = String.format("%s/%s/%s/%s", + rgs.getContract(), paymentDate, + paymentInstruction.getSenderId(), documentNumberId.incrementAndGet() + ); + return num; + } + + protected String selectSymbolValue(Long companyId, CompanySymbol symbol) { + if (companyId == null) { + return null; + } + CompanySymbols cSymbol = companySymbolsImdg.getFirstObjectByFieldValues(Map.of( + "companyId", companyId, + "companySymbol", symbol.getKey())); + if (cSymbol == null) { + return null; + } else { + return cSymbol.getCompanySymbolValue(); + } + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/PrimaryAuctionT0Session.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/PrimaryAuctionT0Session.java index 9cb0d0d8b..badb9f7ef 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/PrimaryAuctionT0Session.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/PrimaryAuctionT0Session.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.execution.ExecutionCommon; import ru.clearing.classes.statics.data.execution.ExecutionFond; import ru.clearing.classes.statics.data.misc.Session; +import ru.clearing.classes.statics.data.payment.PaymentInstruction; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.session.stage.impl.*; @@ -25,6 +26,7 @@ import ru.spcex.platform.utils.enumeration.IMessageResolver; import java.time.Instant; import java.time.LocalDate; +import java.util.Collection; import java.util.List; import java.util.function.Supplier; @@ -39,7 +41,7 @@ public class PrimaryAuctionT0Session extends AbstractSession implements Initiali private final InclusionObligations inclusionObligations; private final InspectionObligations inspectionObligations; private final FormingRegistersOnOS formingRegistersOnOS; - private final FormingPaymentInstructionAssets formingPaymentInstructionAssets; + private final FormingPaymentInstructionSecurities formingPaymentInstruction; // private final FormingPaymentInstruction formingPaymentInstruction; // private final FormingPaymentInstructionDealsFinalMkr formingPaymentInstructionDealsFinalMkr; private final UnlockResources unlockResources; @@ -60,7 +62,7 @@ public class PrimaryAuctionT0Session extends AbstractSession implements Initiali ObligationAdmission obligationsAdmission, InclusionObligations inclusionObligations, FormingRegistersOnOS formingRegistersOnOS, - FormingPaymentInstructionAssets formingPaymentInstructionAssets, + FormingPaymentInstructionSecurities formingPaymentInstruction, // FormingPaymentInstruction formingPaymentInstruction, // FormingPaymentInstructionDealsFinalMkr formingPaymentInstructionDealsFinalMkr, UnlockResources unlockResources, @@ -76,7 +78,7 @@ public class PrimaryAuctionT0Session extends AbstractSession implements Initiali this.obligationsAdmission = obligationsAdmission; this.inclusionObligations = inclusionObligations; this.formingRegistersOnOS = formingRegistersOnOS; - this.formingPaymentInstructionAssets = formingPaymentInstructionAssets; + this.formingPaymentInstruction = formingPaymentInstruction; // this.formingPaymentInstruction = formingPaymentInstruction; this.unlockResources = unlockResources; this.finishingSession = finishingSession; @@ -177,18 +179,18 @@ public class PrimaryAuctionT0Session extends AbstractSession implements Initiali payload.setSessionId(currSession.getId()); runStage(TaskType.FormingRegistersOnOS, payload, formingRegistersOnOS); //returns Collection } - StageResult paymentResult = null; + StageResult> paymentResult = null; { FormingPaymentInstructionPayload payload = new FormingPaymentInstructionPayload(); payload.setSessionId(currSession.getId()); //stage 7 - paymentResult = runStage(TaskType.FormingPaymentInstruction, payload, formingPaymentInstructionAssets); + paymentResult = runStage(TaskType.FormingPaymentInstruction, payload, formingPaymentInstruction); } - if (paymentResult.getStageResult().getPaymentInstructions().isEmpty()) { + if (paymentResult.getStageResult().isEmpty()) { log.info("no payment instructions were created, sending SDF56"); sendSdf56(); } else { - log.info("created {} PaymentInstructions, waiting for SDF04/SDF13", paymentResult.getStageResult().getPaymentInstructions().size()); + log.info("created {} PaymentInstructions, waiting for SDF04/SDF13", paymentResult.getStageResult().size()); this.afterPaymentsSdf4And13Monitor = SessionMonitorFactory.paymentsWereCreated(section()); } } catch (StageException e) { diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FormingPaymentInstructionSecurities.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FormingPaymentInstructionSecurities.java new file mode 100644 index 000000000..20e1ee124 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FormingPaymentInstructionSecurities.java @@ -0,0 +1,301 @@ +package ru.spcex.clearing.session.stage.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.payment.PaymentInstruction; +import ru.clearing.classes.statics.data.registry.Registry; +import ru.clearing.classes.statics.data.sdf.SDf03; +import ru.clearing.classes.statics.data.sdf.SDf12; +import ru.clearing.classes.statics.data.security.Security; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.balance.ExportToFileRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.importexport.SwtExporterRequest; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +import ru.spcex.clearing.service.RegistryManager; +import ru.spcex.clearing.service.Sdf03Creator; +import ru.spcex.clearing.service.builder.PaymentInstructionBuilderForSecurities; +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.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.AccountType; +import ru.spcex.platform.enumeration.InstrumentType; +import 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; +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.imdg.api.predicate.specific.SecuritySelector; +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.time.Instant; +import java.time.LocalDate; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static ru.spcex.platform.enumeration.RegistryTradingParams.*; +import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD; + +@Service +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class FormingPaymentInstructionSecurities implements ISessionStage { + private final Logger log = LoggerFactory.getLogger(getClass()); + //todo remove (set all in single method setImdg(provider -> setImdg1();setIdGenerator();...) + private ImdgProvider imdgProvider; + private ImdgId idGenerator; + private Imdg registryImdg; + private Imdg paymentInstructionImdg; + private Imdg securityImdg; + private Imdg accountImdg; + private Imdg companyImdg; + private Imdg sDf03Imdg; + private Imdg sDf12Imdg; + private KafkaSender kafkaSender; + private final Sdf03Creator sdf03Creator; + private final IMessageResolver msgResolver = new SimpleMessageResolver(); + private final RegistryManager rgsMng; + private final SecuritySelector securitySelector; + + @Autowired + public FormingPaymentInstructionSecurities(ImdgProvider imdgProvider, + KafkaSender kafkaSender, Sdf03Creator sdf03Creator, RegistryManager rgsMng) { + this.kafkaSender = kafkaSender; + this.imdgProvider = imdgProvider; + this.idGenerator = imdgProvider.getImdgIdGenerator(); + this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class); + this.securityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Security, Security.class); + this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class); + this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + this.sDf03Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf03, SDf03.class); + this.sDf12Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf12, SDf12.class); + this.paymentInstructionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class); + this.sdf03Creator = sdf03Creator; + this.rgsMng = rgsMng; + this.securitySelector = new SecuritySelector<>(imdgProvider, Security.class); + } + + @Override + public StageResult submit(Task task) { + FormingPaymentInstructionPayload payload = (FormingPaymentInstructionPayload) task.getData(); + switch (task.getTaskType()) { + case FormingPaymentInstruction -> { + return formingPaymentInstructions(payload.getSessionId(), payload.getPaymentInstructionReturns()); + } + default -> { + throw new IllegalStateException("Unknown task type: " + task.getTaskType()); + } + } + } + + + private Collection selectRegistries() { + ImdgPredicateBuilder rgsPb = registryImdg.predicateBuilder(); + RegistryCodeSqlBuilder registryCodeSqlBuilder = RegistryCodeSqlBuilder.getInstance( + CS_T, LS_T + ); + ImdgPredicate rgsCodePrdct = rgsPb.and( + rgsPb.sql(registryCodeSqlBuilder.build()), + rgsPb.equals("settlementDate", LocalDate.now())); + Collection registries = registryImdg.getCollectionObjectsByPredicate(rgsCodePrdct); + return registries.stream() + .filter(rgs -> Objects.equals(rgs.getValueDate(), rgs.getSettlementDate())) + .collect(Collectors.toList()); + } + + /** + * часть для бумаг по первичке IPO0 IPOT IPOB + * вторичка прошла идеально + * из нее нужно будет взять кусок про деньги + */ + private StageResult formingPaymentInstructions(Long sessionId, Collection paymentInstructionReturns) { + Instant now = Instant.now(); + Collection registries = selectRegistries(); + log.debug("found registries.size() = {}", registries.size()); + //группируем регистры по groupId + Map> groups = registries + .stream() + .collect(Collectors.groupingBy(Registry::getGroupId)); + log.debug("groups.size = {}", groups.size()); + List paymentInstructionDeals = new ArrayList<>(); + Map lstGroups = RegistryLiabilitiesGroup.group(registries); + for (Map.Entry> group : groups.entrySet()) { + Long groupId = group.getKey(); + Function findByCode = rgsCode -> group.getValue() + .stream() + .filter(rgs -> RegistryManager.equalsByCode(rgsCode, rgs)) + .findFirst() + .orElse(null); + //интересуют обязательства и требования по деньгам + Registry cs_t = findByCode.apply(CS_T); + Registry ls_t = findByCode.apply(LS_T); + if (cs_t == null || ls_t == null) { + log.error("groupId {} cmt_t {} ls_t {} - both must be present", groupId, cs_t, ls_t); + continue; + } + PaymentGroup ls_t_group = lstGroups.get(ls_t.getId()); + if (ls_t_group == null) { + log.debug("groupId {} cmt_t {} ls_t {} were included in a group, skipping", groupId, cs_t, ls_t); + continue; + } + + Optional payerAstO = rgsMng.findRelatedAsset( + ls_t.getTradingClearingRegistryId(), + ls_t.getCompanyId(), + ls_t.getSecuritySymbol(), + AS_T + ); + payerAstO.ifPresent(as_t -> { + log.debug("groupId {} cmt_t {} ls_t {} changing AS*T.id={} sender", groupId, cs_t, ls_t, as_t.getId()); + as_t.setSettledDebit(safeBD(as_t.getSettledDebit()).add(safeBD(ls_t_group.getSum()))); + setUpdatedStoreInImdg(as_t, now); + }); + Optional receiverAstO = rgsMng.findRelatedAsset( + cs_t.getTradingClearingRegistryId(), + cs_t.getCompanyId(), + cs_t.getSecuritySymbol(), + AS_T + ); + receiverAstO.ifPresent(as_t -> { + log.debug("groupId {} cmt_t {} ls_t {} changing AS*T.id={} receiver", groupId, cs_t, ls_t, as_t.getId()); + as_t.setSettledCredit(safeBD(as_t.getSettledCredit()).add(safeBD(ls_t_group.getSum()))); + setUpdatedStoreInImdg(as_t, now); + }); + + + log.trace("generating payment instruction for groupId {} cmt_t {} ls_t {}, matched ls_t total {}, total balance {}, LS*T.id={}", + groupId, + cs_t.getId(), + ls_t.getId(), + ls_t_group.getLs_tRegistries().size(), + ls_t_group.getSum(), + ls_t_group.getLs_tRegistries().stream() + .map(Registry::getId) + .map(String::valueOf) + .collect(Collectors.joining(",", "[", "]")) + ); + + PaymentInstruction pmt = PaymentInstructionBuilderForSecurities.builder(imdgProvider) + .ls_t(ls_t) + .creditLegAccountId(ls_t.getAccountId()) + .creditLegAccount(ls_t.getAccount()) + .debitLegAccountId(cs_t.getAccountId()) + .debitLegAccount(cs_t.getAccount()) + .sessionId(sessionId) + .sender(ls_t.getCompanyId()) + .addressee(cs_t.getCompanyId()) + .purpose("Перевод по итогу клиринга") + .amount(ls_t_group.getSum()) + .build(); + + paymentInstructionImdg.insert(pmt); + paymentInstructionDeals.add(pmt); + + log.trace("generated PaymentInstructions for groupId {}: pmtInstr.id={}", groupId, pmt.getId()); + } + + log.debug("PaymentInstructions return size {}, PaymentInstructions deals size {}. sending SDF03", + paymentInstructionReturns.size(), + paymentInstructionDeals.size()); + List returnsAndDeals = Stream.concat(paymentInstructionReturns.stream(), paymentInstructionDeals.stream()).toList(); + sendSdfs(returnsAndDeals, sessionId); + StageResult> stageResult = new StageResult<>(null, true); + stageResult.setStageResult(returnsAndDeals); + return stageResult; + } + + + private void setUpdatedStoreInImdg(Registry rgs, Instant now) { + rgs.setUpdated(now); + registryImdg.update(rgs); + } + + private void sendSdfs(List formedPaymentInstructions, Long sessionId) { + List sDf03Created = new ArrayList<>(); + List sDf12Created = new ArrayList<>(); + for (PaymentInstruction paymentInstruction : formedPaymentInstructions) { + Account account = accountImdg.getSingleObjectByID(paymentInstruction.getCreditLeg_accountId()); + Security security = securityImdg.getSingleObjectByID(paymentInstruction.getCreditLeg_securityId()); + if (List.of(AccountType.Corr, AccountType.Clrn, AccountType.Tran, AccountType.Anlt, AccountType.Info) + .contains(IEnumKey.getEnumByKey(AccountType.class, account.getAccountType()))) { + sDf03Created.add(sdf03Creator.create(paymentInstruction)); + } else if (!InstrumentType.CRNC.equalsByKey(security.getInstrumentType()) && + List.of(AccountType.Depo, AccountType.Dtrn).contains(IEnumKey.getEnumByKey(AccountType.class, account.getAccountType()))) { + sDf12Created.add(newSDf12(paymentInstruction)); + } + } + + Long sdf03GroupId = !sDf03Created.isEmpty() ? imdgProvider.getImdgIdGenerator().nextId() : null; + for (SDf03 sDf03 : sDf03Created) { + sDf03.setGenerationId(sdf03GroupId); + sDf03Imdg.insert(sDf03); + } + + if (sdf03GroupId != null) { + ExportToFileRequest exportToFileRequest = new ExportToFileRequest(); + exportToFileRequest.setNameOfTable("DF-03"); + exportToFileRequest.setSdfGroupId(sdf03GroupId); + kafkaSender.sendRequestToQueue(Consts.EXPORT_PROCESS, exportToFileRequest); + } + + Long sdf12GroupId = null; + Long maxTxNumber = 1L; + if (!sDf12Created.isEmpty()) { + sdf12GroupId = imdgProvider.getImdgIdGenerator().nextId(); + ImdgPredicateBuilder predicateBuilder = sDf12Imdg.predicateBuilder(); + ImdgPredicate notEmptyTransactionNum = predicateBuilder.not(predicateBuilder.equals("transactionNumber", "")); + Long maxId = sDf12Imdg.aggregateLongMax("id", notEmptyTransactionNum); + if (maxId != null) { + SDf12 sDf12 = sDf12Imdg.getSingleObjectByID(maxId); + maxTxNumber = Long.parseLong(sDf12.getTransactionNumber()) + 1; + } + } + for (SDf12 sDf12 : sDf12Created) { + sDf12.setGenerationId(sdf12GroupId); + sDf12.setTransactionNumber(maxTxNumber.toString()); + sDf12.setTransactionQuantity(String.valueOf(sDf12Created.size())); + sDf12Imdg.insert(sDf12); + } + + if (sdf12GroupId != null) { + SwtExporterRequest swtExporterRequest = new SwtExporterRequest(); + swtExporterRequest.setType("SDF_12"); + swtExporterRequest.setGroupId(sdf12GroupId); + swtExporterRequest.setSessionId(sessionId); + kafkaSender.sendRequestToQueue(Consts.SWT_EXPORTER, swtExporterRequest); + } + } + + private SDf12 newSDf12(PaymentInstruction paymentInstruction) { + log.debug("creating sdf12"); + SDf12 sDf12 = new SDf12(); //todo remove + sDf12.setId(idGenerator.nextId()); + sDf12.setOutDocument(sDf12.getId().toString()); + sDf12.setDirection("DELFREE"); + sDf12.setQuantity(BigDecimalUtil.limitDecimalPlaces(paymentInstruction.getCreditLeg_amount().toString(), 2)); + Security security = securitySelector.selectSecurityById(paymentInstruction.getCreditLeg_securityId()); + if (security != null) { + sDf12.setSecurityCode(security.getSecuritySymbol()); + } + sDf12.setDepoCodeSender(paymentInstruction.getCreditLeg_account()); + sDf12.setDepoCodeAdressee(paymentInstruction.getDebitLeg_account()); +// sDf12.setTransactionNumber(); + sDf12.setGenerationTime(Instant.now()); + return sDf12; + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/PaymentGroup.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/PaymentGroup.java new file mode 100644 index 000000000..f4666fef2 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/PaymentGroup.java @@ -0,0 +1,38 @@ +package ru.spcex.clearing.session.stage.payment.group; + +import ru.clearing.classes.statics.data.registry.Registry; + +import java.math.BigDecimal; +import java.util.List; + +public class PaymentGroup { + private List ls_tRegistries; + private BigDecimal sum; + private Long ls_tId; + + public List getLs_tRegistries() { + return ls_tRegistries; + } + + public void setLs_tRegistries(List ls_tRegistries) { + this.ls_tRegistries = ls_tRegistries; + } + + public BigDecimal getSum() { + return sum; + } + + public void setSum(BigDecimal sum) { + this.sum = sum; + } + + public Long getLs_tId() { + return ls_tId; + } + + public void setLs_tId(Long ls_tId) { + this.ls_tId = ls_tId; + } + // private Direction direction; + // +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/RegistryLiabilitiesGroup.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/RegistryLiabilitiesGroup.java new file mode 100644 index 000000000..efd431bb5 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/payment/group/RegistryLiabilitiesGroup.java @@ -0,0 +1,65 @@ +package ru.spcex.clearing.session.stage.payment.group; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.clearing.classes.statics.data.registry.Registry; +import ru.spcex.clearing.service.RegistryManager; + +import java.math.BigDecimal; +import java.util.*; + +import static ru.spcex.platform.enumeration.RegistryTradingParams.LS_T; + +public class RegistryLiabilitiesGroup { + private Logger log = LoggerFactory.getLogger(getClass()); + + public static RegistryLiabilitiesGroup builder() { + return new RegistryLiabilitiesGroup(); + } + + private RegistryLiabilitiesGroup() { + } + + public static Map group(Collection registriesCollection) { + Map result = new HashMap<>(); + List registries = registriesCollection + .stream() + .filter(rgs -> RegistryManager.equalsByCode(LS_T, rgs)) + .toList(); + for (int i = 0; i < registries.size(); i++) { + Registry ls_t = registries.get(i); + if (ls_t == null) { + continue; + } + LinkedList relatedLiabilities = new LinkedList<>(); + relatedLiabilities.add(ls_t); + for (int j = i + 1; j < registries.size(); j++) { + Registry related = registries.get(j); + if (related == null) { + continue; + } + if (rgsOfTheSameAgents(ls_t, related)) { + relatedLiabilities.add(related); + registries.set(j, null); + } + } + PaymentGroup paymentGroup = new PaymentGroup(); + paymentGroup.setLs_tRegistries(relatedLiabilities); + paymentGroup.setLs_tId(ls_t.getId()); + paymentGroup.setSum(relatedLiabilities + .stream() + .map(Registry::getBalance) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add)); + result.put(paymentGroup.getLs_tId(), paymentGroup); + } + return result; + } + + private static boolean rgsOfTheSameAgents(Registry ls_t1, Registry ls_t2) { + return Objects.equals(ls_t1.getSecurityId(), ls_t2.getSecurityId()) + && Objects.equals(ls_t1.getTradingClearingRegistryId(), ls_t2.getTradingClearingRegistryId()) + && Objects.equals(ls_t1.getCompanyId(), ls_t2.getCompanyId()) + && Objects.equals(ls_t1.getCounterPartyId(), ls_t2.getCounterPartyId()); + } +}