Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
ialbert
b15c547e6a sdf03 grouping payment instructions 2023-07-27 17:53:16 +03:00
7 changed files with 198 additions and 10 deletions

View file

@ -0,0 +1,107 @@
package ru.spcex.clearing.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.spcex.clearing.service.group.Direction;
import ru.spcex.clearing.service.payment.group.PaymentGroup;
import ru.spcex.platform.enumeration.Sender;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
public class PaymentInstructionGroup {
private Logger log = LoggerFactory.getLogger(getClass());
private Account tranAcc;
public static PaymentInstructionGroup builder() {
return new PaymentInstructionGroup();
}
public PaymentInstructionGroup tran(Account acc) {
this.tranAcc = acc;
return this;
}
private PaymentInstructionGroup() {}
public Collection<PaymentGroup> group(List<PaymentInstruction> pmts) {
Collection<PaymentGroup> result = new ArrayList<>();
pmts = pmts
.stream()
.sorted(Comparator.comparing(PaymentInstruction::getId))
.toList();
for (int i = 0; i < pmts.size(); i++) {
PaymentInstruction pmt = pmts.get(i);
if (pmt == null) {
continue;
}
Direction direction = getDirection(pmt);
if (direction.equals(Direction.unknown)) {
result.add(new PaymentGroup(pmt));
}
LinkedList<PaymentInstruction> relatedPmts = new LinkedList<>();
relatedPmts.add(pmt);
for (int j = i + 1; j < pmts.size(); j++) {
PaymentInstruction related = pmts.get(j);
if (related == null) {
continue;
}
if (pmtsOfTheSameAgentsToSpvb(pmt, related) || pmtsOfTheSameAgentsFromSpvb(pmt, related)) {
relatedPmts.add(related);
pmts.set(j, null);
}
}
PaymentGroup paymentGroup = new PaymentGroup();
paymentGroup.setPaymentInstructions(relatedPmts);
paymentGroup.setDirection(direction);
Function<PaymentInstruction, BigDecimal> amountGetter;
switch (direction) {
case to_spvb -> amountGetter = PaymentInstruction::getCreditLeg_amount;
case from_spvb -> amountGetter = PaymentInstruction::getDebitLeg_amount;
default -> throw new IllegalStateException("Unexpected value: " + direction);
}
paymentGroup.setSum(relatedPmts
.stream()
.map(amountGetter)
.reduce(BigDecimal.ZERO, BigDecimal::add));
result.add(paymentGroup);
}
return result;
}
private boolean pmtsOfTheSameAgentsToSpvb(PaymentInstruction pmt, PaymentInstruction related) {
return addresseeIsSpvb(pmt)
&& addresseeIsSpvb(related)
&& Objects.equals(pmt.getCreditLeg_accountId(), related.getCreditLeg_accountId())
&& Objects.equals(pmt.getPaymentPurpose(), related.getPaymentPurpose());
}
private boolean pmtsOfTheSameAgentsFromSpvb(PaymentInstruction pmt, PaymentInstruction related) {
return senderIsSpvb(pmt)
&& senderIsSpvb(related)
&& Objects.equals(pmt.getDebitLeg_accountId(), related.getDebitLeg_accountId())
&& Objects.equals(pmt.getPaymentPurpose(), related.getPaymentPurpose());
}
private Direction getDirection(PaymentInstruction p) {
if (addresseeIsSpvb(p)) {
return Direction.to_spvb;
} else if (senderIsSpvb(p)) {
return Direction.from_spvb;
} else {
return Direction.unknown;
}
}
private boolean addresseeIsSpvb(PaymentInstruction p) {
return p.getAddresseeId().equals(Sender.One.getId()) && p.getDebitLeg_accountId().equals(tranAcc.getId());
}
private boolean senderIsSpvb(PaymentInstruction p) {
return p.getSenderId().equals(Sender.One.getId()) && p.getCreditLeg_accountId().equals(tranAcc.getId());
}
}

View file

@ -9,6 +9,7 @@ import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.sdf.SDf03;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.service.payment.group.PaymentGroup;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.Status;
import ru.spcex.platform.imdg.api.Imdg;
@ -20,6 +21,7 @@ import ru.spcex.platform.utils.time.TimeUtil;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
@Component
public class Sdf03Creator {
@ -114,6 +116,17 @@ public class Sdf03Creator {
return sDf03;
}
public SDf03 create(PaymentGroup group) {
Optional<PaymentInstruction> pmt = group.getPaymentInstructions().stream().findFirst();
if (pmt.isEmpty()) {
throw new IllegalStateException("empty group"); //never
}
SDf03 sDf03 = create(pmt.get());
String sumDeb = group.getSum() != null ? group.getSum().toString() : "";
sDf03.setSum_deb(BigDecimalUtil.limitDecimalPlaces(sumDeb, 2));
return sDf03;
}
private AccountType getAccountType(Long accountId) {
Account account = accountImdg.getSingleObjectByID(accountId);
return IEnumKey.getEnumByKey(AccountType.class, account.getAccountType());

View file

@ -0,0 +1,48 @@
package ru.spcex.clearing.service.payment.group;
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.spcex.clearing.service.group.Direction;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
public class PaymentGroup {
private List<PaymentInstruction> paymentInstructions;
private BigDecimal sum;
private Direction direction;
public PaymentGroup() {
}
public PaymentGroup(PaymentInstruction pmt) {
this.paymentInstructions = Collections.singletonList(pmt);
//fixme в старом заполнении нашел только поле sDf03.setSum_deb (pmt.getDebitLeg_amount)
this.sum = pmt.getDebitLeg_amount();
this.direction = Direction.unknown;
}
public List<PaymentInstruction> getPaymentInstructions() {
return paymentInstructions;
}
public void setPaymentInstructions(List<PaymentInstruction> paymentInstructions) {
this.paymentInstructions = paymentInstructions;
}
public BigDecimal getSum() {
return sum;
}
public void setSum(BigDecimal sum) {
this.sum = sum;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
}

View file

@ -19,9 +19,11 @@ 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.PaymentInstructionGroup;
import ru.spcex.clearing.service.RegistryManager;
import ru.spcex.clearing.service.Sdf03Creator;
import ru.spcex.clearing.service.builder.PaymentInstructionBuilderFinalMkrDeals;
import ru.spcex.clearing.service.payment.group.PaymentGroup;
import ru.spcex.clearing.session.stage.ISessionStage;
import ru.spcex.clearing.session.stage.StageResult;
import ru.spcex.clearing.session.stage.Task;
@ -194,7 +196,7 @@ public class FormingPaymentInstructionDealsFinalMkr implements ISessionStage {
cm_t.getId(),
lm_t.getId());
String paymentPurpose = section != null && section == Section.FOND ? "" :
"Размещение депозита " + lm_t.getContract() + " по ТКР " + lm_t.getTradingClearingRegistry();
"Перевод по итогу клиринга по ТКР " + lm_t.getTradingClearingRegistry();
Pair<PaymentInstruction, PaymentInstruction> pmtInstrs = PaymentInstructionBuilderFinalMkrDeals
.builder(imdgProvider)
.cm_t(cm_t)
@ -218,7 +220,7 @@ public class FormingPaymentInstructionDealsFinalMkr implements ISessionStage {
paymentInstructionDeals.size());
List<PaymentInstruction> returnsAndDeals = Stream.concat(paymentInstructionReturns.stream(), paymentInstructionDeals.stream()).toList();
if (sendSdfs) {
sendSdfs(returnsAndDeals);
sendSdfs(returnsAndDeals, tranAcc);
}
StageResult<Collection<PaymentInstruction>> stageResult = new StageResult<>(null, true);
stageResult.setStageResult(returnsAndDeals);
@ -231,26 +233,39 @@ public class FormingPaymentInstructionDealsFinalMkr implements ISessionStage {
registryImdg.update(rgs);
}
private void sendSdfs(List<PaymentInstruction> formedPaymentInstructions) {
List<SDf03> sDf03Created = new ArrayList<>();
private void sendSdfs(List<PaymentInstruction> formedPaymentInstructions, Account tranAcc) {
List<SDf12> sDf12Created = new ArrayList<>();
List<PaymentInstruction> forSdf03 = 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()))) {
//если info подставить anlt (единственный счет в системе)
sDf03Created.add(sdf03Creator.create(paymentInstruction));
forSdf03.add(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) {
Long sdf03GroupId = !forSdf03.isEmpty() ? imdgProvider.getImdgIdGenerator().nextId() : null;
Collection<PaymentGroup> groups = PaymentInstructionGroup.builder()
.tran(tranAcc)
.group(forSdf03);
for(PaymentGroup group : groups) {
SDf03 sDf03 = sdf03Creator.create(group);
sDf03.setGenerationId(sdf03GroupId);
sDf03Imdg.insert(sDf03);
log.debug("created SDF03.groupId/id={}/{} for {} by paymentInstructions: {} ",
sdf03GroupId,
sDf03.getId(),
group.getPaymentInstructions().size(),
group.getPaymentInstructions()
.stream()
.map(PaymentInstruction::getId)
.map(String::valueOf)
.collect(Collectors.joining(",", "[", "]"))
);
}
if (sdf03GroupId != null) {

View file

@ -189,7 +189,7 @@ public class FormingPaymentInstructionDepositReturn implements ISessionStage {
.cm_t(cm_t)
.tranAcc(tranAcc)
.sessionId(sessionId)
.paymentPurpose("Возврат депозита " + cm_t.getContract() + " по ТКР " + cm_t.getTradingClearingRegistry())
.paymentPurpose("Перевод по итогу клиринга по ТКР " + cm_t.getTradingClearingRegistry())
.build();
paymentInstructionImdg.insert(pmts.getFirst());
paymentInstructionImdg.insert(pmts.getSecond());

View file

@ -195,7 +195,7 @@ public class FormingPaymentInstructionReturnMkr implements ISessionStage {
.cm_t(cm_t)
.tranAcc(tranAcc)
.sessionId(sessionId)
.paymentPurpose("Возврат депозита " + cm_t.getContract() + " по ТКР " + cm_t.getTradingClearingRegistry())
.paymentPurpose("Перевод по итогу клиринга по ТКР " + cm_t.getTradingClearingRegistry())
.build();
paymentInstructionImdg.insert(pmts.getFirst());
paymentInstructionImdg.insert(pmts.getSecond());

View file

@ -0,0 +1,5 @@
package ru.spcex.clearing.service.group;
public enum Direction {
to_spvb, from_spvb, unknown;
}