FormingPaymentInstructionSecurities to action
This commit is contained in:
parent
d600ddfb52
commit
c88ce7f56f
2 changed files with 313 additions and 0 deletions
|
|
@ -9,5 +9,6 @@ public enum DataEnum {
|
||||||
counterPartyId, //Long
|
counterPartyId, //Long
|
||||||
obligationAdmissionStashedRgs, //Map<Long, Registry>
|
obligationAdmissionStashedRgs, //Map<Long, Registry>
|
||||||
paymentInstructionReturnMkr, //List<PaymentInstruction>
|
paymentInstructionReturnMkr, //List<PaymentInstruction>
|
||||||
|
paymentInstructionSecurity, //List<PaymentInstruction>
|
||||||
paymentInfo,
|
paymentInfo,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,312 @@
|
||||||
|
package ru.spcex.clearing.session.state.action;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.statemachine.StateContext;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.clearing.classes.statics.data.account.Account;
|
||||||
|
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
|
||||||
|
import ru.clearing.classes.statics.data.registry.Registry;
|
||||||
|
import ru.spcex.clearing.component.GroupRgsKey;
|
||||||
|
import ru.spcex.clearing.error.ClearingError;
|
||||||
|
import ru.spcex.clearing.error.ClearingRuntimeException;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
|
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||||
|
import ru.spcex.clearing.service.Sdf03Creator;
|
||||||
|
import ru.spcex.clearing.service.builder.PaymentInstructionBuilderForSecurities;
|
||||||
|
import ru.spcex.clearing.service.builder.PaymentInstructionBuilderV2;
|
||||||
|
import ru.spcex.clearing.service.registry.RegistryManager;
|
||||||
|
import ru.spcex.clearing.session.stage.TaskType;
|
||||||
|
import ru.spcex.clearing.session.stage.impl.Sdf03And12Sender;
|
||||||
|
import ru.spcex.clearing.session.stage.payment.group.PaymentGroup;
|
||||||
|
import ru.spcex.clearing.session.stage.payment.group.RegistryLiabilitiesGroup;
|
||||||
|
import ru.spcex.clearing.session.state.DataEnum;
|
||||||
|
import ru.spcex.clearing.session.state.SsnEvent;
|
||||||
|
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 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.ImdgProvider;
|
||||||
|
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
|
||||||
|
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
|
||||||
|
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
|
||||||
|
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||||
|
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
public class FormingPaymentInstructionSecuritiesAction extends AbstractSessionActionForOkErrorHandling {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
private ImdgProvider imdgProvider;
|
||||||
|
private Imdg<Registry> registryImdg;
|
||||||
|
private Imdg<PaymentInstruction> paymentInstructionImdg;
|
||||||
|
private Imdg<Account> accountImdg;
|
||||||
|
private final RegistryManager rgsMng;
|
||||||
|
private final Sdf03And12Sender sdf03And12Sender;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FormingPaymentInstructionSecuritiesAction(ImdgProvider imdgProvider,
|
||||||
|
KafkaSender kafkaSender,
|
||||||
|
Sdf03Creator sdf03Creator,
|
||||||
|
RegistryManager rgsMng,
|
||||||
|
Sdf03And12Sender sdf03And12Sender) {
|
||||||
|
this.imdgProvider = imdgProvider;
|
||||||
|
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||||
|
this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
|
||||||
|
this.paymentInstructionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class);
|
||||||
|
this.rgsMng = rgsMng;
|
||||||
|
this.sdf03And12Sender = sdf03And12Sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void actualExecute(StateContext<TaskType, SsnEvent> ctx) {
|
||||||
|
Long sessionId = ctx.getExtendedState().get(DataEnum.sessionId, Long.class);
|
||||||
|
|
||||||
|
List<PaymentInstruction> paymentInstructionAll = new ArrayList<>();
|
||||||
|
Instant now = Instant.now();
|
||||||
|
{
|
||||||
|
Collection<Registry> registries = selectSecurityRegistries(sessionId);
|
||||||
|
log.debug("found registries.size() = {}", registries.size());
|
||||||
|
//группируем регистры по groupId и market
|
||||||
|
Map<GroupRgsKey, List<Registry>> groups = registries
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.groupingBy(r -> new GroupRgsKey(r.getGroupId(), r.getMarket())));
|
||||||
|
|
||||||
|
log.debug("groups.size = {}", groups.size());
|
||||||
|
Map<Long, PaymentGroup> lstGroups = RegistryLiabilitiesGroup.group(groups);
|
||||||
|
for (Map.Entry<GroupRgsKey, List<Registry>> group : groups.entrySet()) {
|
||||||
|
Long groupId = group.getKey().groupId();
|
||||||
|
String market = group.getKey().market();
|
||||||
|
Function<RegistryTradingParams, Registry> findByCode = rgsCode -> group.getValue()
|
||||||
|
.stream()
|
||||||
|
.filter(rgs -> RegistryManager.equalsByCode(rgsCode, rgs))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
//интересуют обязательства и требования по деньгам
|
||||||
|
Registry cs_t = findByCode.apply(RegistryTradingParams.TS_T);
|
||||||
|
Registry ls_t = findByCode.apply(RegistryTradingParams.OS_T);
|
||||||
|
if (cs_t == null || ls_t == null) {
|
||||||
|
log.error("groupId/market {}/{} cmt_t {} ls_t {} - both must be present", groupId, market, cs_t, ls_t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PaymentGroup ls_t_group = lstGroups.get(ls_t.getId());
|
||||||
|
if (ls_t_group == null) {
|
||||||
|
log.debug("groupId/market {}/{} cmt_t {} ls_t {} were included in a group, skipping", groupId, market, cs_t, ls_t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Registry> payerAstO = rgsMng.findRelatedAsset(
|
||||||
|
ls_t.getTradingClearingRegistryId(),
|
||||||
|
ls_t.getCompanyId(),
|
||||||
|
ls_t.getSecuritySymbol(),
|
||||||
|
AS_T
|
||||||
|
);
|
||||||
|
payerAstO.ifPresent(as_t -> {
|
||||||
|
log.debug("groupId/market {}/{} cmt_t {} ls_t {} changing AS*T.id={} sender", groupId, market, 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<Registry> receiverAstO = rgsMng.findRelatedAsset(
|
||||||
|
cs_t.getTradingClearingRegistryId(),
|
||||||
|
cs_t.getCompanyId(),
|
||||||
|
cs_t.getSecuritySymbol(),
|
||||||
|
AS_T
|
||||||
|
);
|
||||||
|
receiverAstO.ifPresent(as_t -> {
|
||||||
|
log.debug("groupId/market {}/{} cmt_t {} ls_t {} changing AS*T.id={} receiver", groupId, market, 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);
|
||||||
|
paymentInstructionAll.add(pmt);
|
||||||
|
log.trace("generated PaymentInstructions for groupId/market {}/{}: pmtInstr.id={}", groupId, market, pmt.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Collection<Registry> registries = selectMoneyRegistries(sessionId);
|
||||||
|
Account dtrnAcc = accountImdg.getFirstObjectBySQL("accountType = '%s' and status = '%s' and processingSign = '%s'"
|
||||||
|
.formatted(AccountType.Dtrn.getKey(), AccountStatus.ACTIVE.getKey(), Allowed.ALLOWED.getKey()));
|
||||||
|
|
||||||
|
if (dtrnAcc == null) {
|
||||||
|
throw new ClearingRuntimeException(
|
||||||
|
new EnumMessage(ClearingError.AccountNotPresent, "accountType = %s"
|
||||||
|
.formatted(AccountType.Dtrn.getKey()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
throw new ClearingRuntimeException(
|
||||||
|
new EnumMessage(ClearingError.AccountNotPresent, "accountType = %s"
|
||||||
|
.formatted(AccountType.Tran.getKey()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registry.getBalance().compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
log.debug("Skip creating paymentInstruction by registry with 0 balance");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean isPositiveBalance = registry.getBalance().compareTo(BigDecimal.ZERO) > 0;
|
||||||
|
Account counterAcc = null;
|
||||||
|
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(), "currency", registry.getSecuritySymbol()));
|
||||||
|
}
|
||||||
|
Long senderId;
|
||||||
|
Long addresseeId;
|
||||||
|
Account debitLegAccount;
|
||||||
|
Account creditLegAccount;
|
||||||
|
BigDecimal amount;
|
||||||
|
if (isPositiveBalance) {
|
||||||
|
senderId = registry.getCompanyId();
|
||||||
|
addresseeId = Sender.One.getId();
|
||||||
|
debitLegAccount = tranAcc;
|
||||||
|
creditLegAccount = counterAcc;
|
||||||
|
amount = registry.getBalance() == null ? null : registry.getBalance().abs();
|
||||||
|
Optional<Registry> payerAmtO = rgsMng.findRelatedAssetTran(
|
||||||
|
registry.getTradingClearingRegistryId(),
|
||||||
|
registry.getCompanyId(),
|
||||||
|
registry.getSecuritySymbol(),
|
||||||
|
AM_T);
|
||||||
|
payerAmtO.ifPresent(amt -> {
|
||||||
|
amt.setSettledDebit(safeBD(amt.getSettledDebit()).add(safeBD(registry.getBalance().abs())));
|
||||||
|
setUpdatedStoreInImdg(amt, now);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
senderId = Sender.One.getId();
|
||||||
|
addresseeId = registry.getCompanyId();
|
||||||
|
debitLegAccount = counterAcc;
|
||||||
|
creditLegAccount = tranAcc;
|
||||||
|
amount = registry.getBalance() == null ? null : registry.getBalance().abs();
|
||||||
|
Optional<Registry> payerAmtO = rgsMng.findRelatedAssetTran(
|
||||||
|
registry.getTradingClearingRegistryId(),
|
||||||
|
registry.getCompanyId(),
|
||||||
|
registry.getSecuritySymbol(),
|
||||||
|
AM_T
|
||||||
|
);
|
||||||
|
payerAmtO.ifPresent(amt -> {
|
||||||
|
amt.setSettledCredit(safeBD(amt.getSettledCredit()).add(safeBD(registry.getBalance().abs())));
|
||||||
|
setUpdatedStoreInImdg(amt, now);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PaymentInstructionBuilderV2 paymentInstructionBuilder = PaymentInstructionBuilderV2.builder(imdgProvider)
|
||||||
|
.registry(registry)
|
||||||
|
.sender(senderId)
|
||||||
|
.addressee(addresseeId)
|
||||||
|
.debitLegAccount(debitLegAccount)
|
||||||
|
.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());
|
||||||
|
paymentInstructionImdg.insert(paymentInstruction);
|
||||||
|
registry.setPaymentId(paymentInstruction.getId());
|
||||||
|
registry.setUpdated(now);
|
||||||
|
registryImdg.update(registry);
|
||||||
|
paymentInstructionAll.add(paymentInstruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("PaymentInstruction size {}", paymentInstructionAll.size());
|
||||||
|
sdf03And12Sender.sendSdfs(paymentInstructionAll, sessionId);
|
||||||
|
|
||||||
|
ctx.getExtendedState().getVariables().put(DataEnum.paymentInstructionSecurity, paymentInstructionAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Registry> selectSecurityRegistries(Long sessionId) {
|
||||||
|
ImdgPredicateBuilder rgsPb = registryImdg.predicateBuilder();
|
||||||
|
RegistryCodeSqlBuilder registryCodeSqlBuilder = RegistryCodeSqlBuilder.getInstance(
|
||||||
|
RegistryTradingParams.TS_T, RegistryTradingParams.OS_T
|
||||||
|
);
|
||||||
|
ImdgPredicate rgsCodePrdct = rgsPb.and(
|
||||||
|
rgsPb.sql(registryCodeSqlBuilder.build()),
|
||||||
|
rgsPb.equals("registryStatus", RegistryStatus.OK.getKey()),
|
||||||
|
rgsPb.equals("sessionId", sessionId),
|
||||||
|
rgsPb.equals("settlementDate", LocalDate.now()));
|
||||||
|
Collection<Registry> registries = registryImdg.getCollectionObjectsByPredicate(rgsCodePrdct);
|
||||||
|
return registries.stream()
|
||||||
|
.filter(rgs -> Objects.equals(rgs.getValueDate(), rgs.getSettlementDate()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Registry> selectMoneyRegistries(Long sessionId) {
|
||||||
|
ImdgPredicateBuilder rgsPb = registryImdg.predicateBuilder();
|
||||||
|
RegistryCodeSqlBuilder registryCodeSqlBuilder = RegistryCodeSqlBuilder.getInstance(
|
||||||
|
AM_B
|
||||||
|
);
|
||||||
|
ImdgPredicate prdct = rgsPb.and(
|
||||||
|
rgsPb.sql(registryCodeSqlBuilder.build()),
|
||||||
|
rgsPb.equals("sessionId", sessionId)
|
||||||
|
);
|
||||||
|
Collection<Registry> registries = registryImdg.getCollectionObjectsByPredicate(prdct);
|
||||||
|
return registries.stream()
|
||||||
|
.filter(rgs -> Objects.equals(rgs.getValueDate(), rgs.getSettlementDate()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUpdatedStoreInImdg(Registry rgs, Instant now) {
|
||||||
|
rgs.setUpdated(now);
|
||||||
|
registryImdg.update(rgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue