diff --git a/clearing-parent/clearing-service/pom.xml b/clearing-parent/clearing-service/pom.xml
index 2c40979e9..aa206dcf4 100644
--- a/clearing-parent/clearing-service/pom.xml
+++ b/clearing-parent/clearing-service/pom.xml
@@ -41,6 +41,16 @@
ru.spcex.platform
platform-enum
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java
index 9e30eb31a..24106521d 100644
--- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java
@@ -5,8 +5,6 @@ import ru.spcex.platform.utils.enumeration.IEnumId;
public enum ClearingError implements IEnumId {
CompanyCreditCheck(10012L),
CompanyDebitCheck(10013L),
- //if ever happens, ask to add
- ClearingMemberCategoryUnknown(19999L),
;
private final Long id;
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/ClearingService.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/ClearingService.java
index 64eabf711..1103e95a6 100644
--- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/ClearingService.java
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/ClearingService.java
@@ -7,7 +7,12 @@ import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
+import ru.clearing.classes.statics.data.sdf.SDf03;
+import ru.clearing.classes.statics.data.sdf.SDf11;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
+import ru.spcex.clearing.platform.messaging.domain.Consts;
+import ru.spcex.clearing.platform.messaging.domain.cud.clearing.SdfClearingRequest;
+import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.enumeration.TransactionStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
@@ -28,13 +33,19 @@ public class ClearingService {
private final Imdg paymentImdgs;
private final ExecutorService executor;
private final ImdgId idGenerator;
- private final PaymentBatchProcessor senderGroupProcessor;
+ private final PaymentInstructionSorter senderGroupSorter;
+ private final Imdg sdf03Imdg;
+ private final Imdg sdf11Imdg;
+ private final KafkaSender kafkaSender;
@Autowired
- public ClearingService(ImdgProvider imdgProvider, PaymentBatchProcessor senderGroupProcessor) {
+ public ClearingService(ImdgProvider imdgProvider, PaymentInstructionSorter senderGroupSorter, KafkaSender kafkaSender) {
this.paymentImdgs = imdgProvider.getImdg(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class);
+ this.sdf03Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf03, SDf03.class);
+ this.sdf11Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf11, SDf11.class);
this.idGenerator = imdgProvider.getImdgIdGenerator();
- this.senderGroupProcessor = senderGroupProcessor;
+ this.senderGroupSorter = senderGroupSorter;
+ this.kafkaSender = kafkaSender;
this.executor = Executors.newSingleThreadExecutor();
}
@@ -44,34 +55,69 @@ public class ClearingService {
}
private void createSdfFromPaymentInstructionSTLD() {
- //выгружаем PaymentInstructions с нужным статусом, группируем по компаниям
- Map> pmtInsBySender = paymentImdgs.getCollectionObjectsByFieldValues(
- Map.of("transactionStatus", TransactionStatus.stld.getKey()))
- .stream()
- .sorted(Comparator.comparing(PaymentInstruction::getSenderId))
- .collect(Collectors.groupingBy(PaymentInstruction::getSenderId));
+ final boolean[] anyError = {false};
//generationId для созадаваемых Sdf03/Sdf11
Long generationId = idGenerator.nextId();
- //результатом работы senderGroupProcessor будет Map PaymentBatchInfo>
- //PaymentBatchInfo содержит возможную ошибку, при необходимости отсортированные Payment
- //тип ClearingMemberCategory
- Map processResults = pmtInsBySender
+ //выгружаем PaymentInstructions с нужным статусом
+ Map paymentBySender = paymentImdgs.getCollectionObjectsByFieldValues(
+ Map.of("transactionStatus", TransactionStatus.stld.getKey()))
+ .stream()
+ //группируем по компаниям (fixme sorted убрать?)
+ .sorted(Comparator.comparing(PaymentInstruction::getSenderId))
+ .collect(Collectors.groupingBy(PaymentInstruction::getSenderId))
.entrySet()
.stream()
+ //результатом работы senderGroupSorter будет Map PaymentBatchInfo>
+ //PaymentBatchInfo содержит возможную ошибку, при необходимости отсортированные Payment
+ //тип ClearingMemberCategory
.map(entry -> {
Long senderId = entry.getKey();
List pmtInstrcs = entry.getValue();
- return new AbstractMap.SimpleEntry<>(senderId, senderGroupProcessor.processSingleCompanyPayments(generationId, senderId, pmtInstrcs));
+ PaymentBatchInfo senderInfo = senderGroupSorter.sortCompanyPayments(generationId, senderId, pmtInstrcs);
+ if (senderInfo.getError() != null) {
+ anyError[0] = true;
+ }
+ return new AbstractMap.SimpleEntry<>(senderId, senderInfo);
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
-
- //todo export
- //set status
+ //save SDF03/SDF11
+ for (var entry : paymentBySender.entrySet()) {
+ PaymentBatchInfo senderPayments = entry.getValue();
+ saveSdfAnSendToKafka(senderPayments, generationId);
+ }
+ //update PaymentInstruction.transactionStatus
+ for (var entry : paymentBySender.entrySet()) {
+ PaymentBatchInfo batch = entry.getValue();
+ //все PaymentInstruction.transactionStatus в batch с error != null
+ //уже проапдейтились в методе sortCompanyPayments
+ if (batch.getError() == null) {
+ TransactionStatus stat = anyError[0] ? TransactionStatus.notSent : TransactionStatus.sent;
+ batch.getOrderedPaymentInstructions()
+ .forEach(paymentInstruction -> {
+ paymentInstruction.setTransactionStatus(stat.getKey());
+ paymentImdgs.update(paymentInstruction);
+ });
+ }
+ }
}
- private void processSingleCompanyPayments(Long generationId, Long senderId, List payments) {
- log.info("processing PaymentInstruction's generationId={} senderId={} size={}", generationId, senderId, payments.size());
-
+ private void saveSdfAnSendToKafka(PaymentBatchInfo batch, Long generationId) {
+ SdfClearingRequest kafkaMessage = new SdfClearingRequest();
+ kafkaMessage.setGroupId(generationId);
+ switch (batch.getCategoryD()) {
+ case I -> {
+ batch.getOrderedPaymentInstructions()
+ .map(paymentInstruction -> Sdf03Builder.buildSdf03(paymentInstruction, generationId))
+ .forEach(sdf03Imdg::insert);
+ kafkaSender.sendRequestToQueue(Consts.SDF03_PROCESS, kafkaMessage);
+ }
+ case B -> {
+ batch.getOrderedPaymentInstructions()
+ .map(paymentInstruction -> Sdf11Builder.buildSdf11(paymentInstruction, generationId))
+ .forEach(sdf11Imdg::insert);
+ kafkaSender.sendRequestToQueue(Consts.SDF11_PROCESS, kafkaMessage);
+ }
+ }
}
}
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentBatchInfo.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentBatchInfo.java
index 77ba4ad1a..fff82f55c 100644
--- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentBatchInfo.java
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentBatchInfo.java
@@ -4,14 +4,29 @@ import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.spcex.platform.enumeration.ClearingMemberCategoryD;
import ru.spcex.platform.utils.enumeration.EnumMessage;
+import java.util.Collection;
import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Stream;
public class PaymentBatchInfo {
+ private List initialOrder;
private List fromClearingToBank;
private List fromBankToClearing;
private ClearingMemberCategoryD categoryD;
private EnumMessage error;
+ public Stream getOrderedPaymentInstructions() {
+ Function, Stream> safeStream
+ = paymentInstructions -> paymentInstructions != null ? paymentInstructions.stream() : Stream.empty();
+ if (categoryD.equals(ClearingMemberCategoryD.B)) {
+ return safeStream.apply(initialOrder);
+ } else {
+ return Stream.concat(safeStream.apply(fromClearingToBank), safeStream.apply(fromBankToClearing));
+ }
+ }
+
+
public List getFromClearingToBank() {
return fromClearingToBank;
}
@@ -43,4 +58,12 @@ public class PaymentBatchInfo {
public void setError(EnumMessage error) {
this.error = error;
}
+
+ public List getInitialOrder() {
+ return initialOrder;
+ }
+
+ public void setInitialOrder(List initialOrder) {
+ this.initialOrder = initialOrder;
+ }
}
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentBatchProcessor.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentInstructionSorter.java
similarity index 55%
rename from clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentBatchProcessor.java
rename to clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentInstructionSorter.java
index bdd1b5dcb..c618bad8f 100644
--- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentBatchProcessor.java
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/PaymentInstructionSorter.java
@@ -11,6 +11,7 @@ import ru.spcex.clearing.error.ClearingError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ClearingMemberCategoryD;
+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.enumeration.EnumMessage;
@@ -23,47 +24,39 @@ import java.util.Map;
import java.util.function.Function;
@Component
-public class PaymentBatchProcessor {
+public class PaymentInstructionSorter {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg clrngMmbrImdg;
private final Imdg accImdg;
private final IMessageResolver messageResolver;
+ private final Imdg pmtInstrctnsImdg;
@Autowired
- public PaymentBatchProcessor(ImdgProvider imdgProvider, IMessageResolver messageResolver) {
+ public PaymentInstructionSorter(ImdgProvider imdgProvider, IMessageResolver messageResolver) {
this.clrngMmbrImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
+ this.pmtInstrctnsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class);
this.accImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
-
this.messageResolver = messageResolver;
}
- PaymentBatchInfo processSingleCompanyPayments(Long generationId, Long senderId, List payments) {
+ PaymentBatchInfo sortCompanyPayments(Long generationId, Long senderId, List payments) {
PaymentBatchInfo batchInfo = new PaymentBatchInfo();
log.info("processing PaymentInstruction's generationId={} senderId={} size={}", generationId, senderId, payments.size());
ClearingMemberCategory category = clrngMmbrImdg.getSingleObjectByFieldValues(Map.of("companyId", senderId));
- ClearingMemberCategoryD categoryValue;
- if (category == null || (categoryValue =
- IEnumKey.getEnumByKey(ClearingMemberCategoryD.class, category.getClearingMemberCategory())) == null) {
- log.warn("processing PaymentInstructions generationId={} senderId={}: " +
- "ClearingMemberCategory {}, ClearingMemberCategory.clearingMemberCategory {}",
- generationId, senderId,
- category == null ? "null" : "is not null",
- category == null ? "null" : category.getClearingMemberCategory()
- );
- batchInfo.setError(new EnumMessage(ClearingError.ClearingMemberCategoryUnknown));
- return batchInfo;
- }
+ ClearingMemberCategoryD categoryValue = IEnumKey.getEnumByKey(ClearingMemberCategoryD.class, category.getClearingMemberCategory());
batchInfo.setCategoryD(categoryValue);
if (ClearingMemberCategoryD.I.equals(categoryValue)) {
+ EnumMessage error = null;
List aList = new ArrayList<>();
List bList = new ArrayList<>();
for (PaymentInstruction payment : payments) {
Account creditLegAcc = accImdg.getSingleObjectByID(payment.getCreditLegAccountId());
Account debitLegAcc = accImdg.getSingleObjectByID(payment.getDebitLegAccountId());
if (creditLegAcc == null || debitLegAcc == null) {
- log.warn("generationId={}, senderId={} payment.id={} cannot find account CreditLegAccountId/DebitLegAccountId {}/{}",
- generationId, senderId, payment.getId(), payment.getCreditLegAccountId(), payment.getDebitLegAccountId());
+ String message = String.format("cannot find account CreditLegAccountId/DebitLegAccountId %d/%d", payment.getCreditLegAccountId(), payment.getDebitLegAccountId());
+ log.error("generationId={}, senderId={} payment.id={} {}",
+ generationId, senderId, payment.getId(), message);
continue;
}
if (AccountType.Clrn.equalsByKey(creditLegAcc.getAccountType())
@@ -73,9 +66,10 @@ public class PaymentBatchProcessor {
&& AccountType.Clrn.equalsByKey(debitLegAcc.getAccountType())) {
bList.add(payment);
} else {
- log.warn("generationId={} senderId={} cannot sort payment.id={}, creditLegAccount.type={}, debitLegAccount.type={}",
- generationId, senderId, payment.getId(),creditLegAcc.getAccountType(), debitLegAcc.getAccountType());
- continue;
+ String message = String.format("cannot sort creditLegAccount.type=%s, debitLegAccount.type=%s", creditLegAcc.getAccountType(), debitLegAcc.getAccountType());
+ log.error("generationId={}, senderId={} payment.id={} {}",
+ generationId, senderId, payment.getId(), message);
+ //continue;
}
}
Function, Long> creditAmountSum = paymentInstructions -> paymentInstructions
@@ -84,55 +78,43 @@ public class PaymentBatchProcessor {
.reduce(0L, Long::sum);
Function, Long> debitAmountSum = paymentInstructions -> paymentInstructions
.stream()
- .map(PaymentInstruction::getCreditLegAmount)
+ .map(PaymentInstruction::getDebitLegAmount)
.reduce(0L, Long::sum);
Long fromClearingToBankCreditAmount = creditAmountSum.apply(aList);
Long fromBankToClearingCreditAmount = creditAmountSum.apply(bList);
Long fromClearingToBankDebitAmount = debitAmountSum.apply(aList);
Long fromBankToClearingDebitAmount = debitAmountSum.apply(bList);
if (!fromClearingToBankCreditAmount.equals(fromBankToClearingCreditAmount)) {
- log.info("processing PaymentInstruction's generationId={} senderId={} [fromClearingToBankCreditAmount={}, " +
- "fromBankToClearingCreditAmount={}, " +
- "fromClearingToBankDebitAmount={}, " +
- "fromBankToClearingDebitAmount={}] error {}", generationId, senderId,
- fromClearingToBankCreditAmount,
- fromBankToClearingCreditAmount,
- fromClearingToBankDebitAmount,
- fromBankToClearingDebitAmount,
- messageResolver.resolve(new EnumMessage(ClearingError.CompanyCreditCheck, senderId.toString())));
- batchInfo.setError(new EnumMessage(ClearingError.CompanyCreditCheck, senderId.toString()));
- return batchInfo;
+ error = new EnumMessage(ClearingError.CompanyCreditCheck, senderId.toString());
} else if (!fromClearingToBankDebitAmount.equals(fromBankToClearingDebitAmount)) {
- log.info("processing PaymentInstruction's generationId={} senderId={} [fromClearingToBankCreditAmount={}, " +
+ error = new EnumMessage(ClearingError.CompanyDebitCheck, senderId.toString());
+ }
+ log.info("processing PaymentInstruction's generationId={} senderId={} [fromClearingToBankCreditAmount={}, " +
"fromBankToClearingCreditAmount={}, " +
"fromClearingToBankDebitAmount={}, " +
- "fromBankToClearingDebitAmount={}] error {}", generationId, senderId,
+ "fromBankToClearingDebitAmount={}] {}", generationId, senderId,
fromClearingToBankCreditAmount,
fromBankToClearingCreditAmount,
fromClearingToBankDebitAmount,
fromBankToClearingDebitAmount,
- messageResolver.resolve(new EnumMessage(ClearingError.CompanyDebitCheck, senderId.toString())));
- batchInfo.setError(new EnumMessage(ClearingError.CompanyDebitCheck, senderId.toString()));
+ error != null ? ("error " + messageResolver.resolve(error)) : "ok");
+ if (error != null) {
+ batchInfo.setError(error);
+ payments.forEach(pmt -> {
+ pmt.setTransactionStatus(TransactionStatus.cher.getKey());
+ pmtInstrctnsImdg.update(pmt);
+ });
+ return batchInfo;
+ } else {
+ batchInfo.setFromClearingToBank(aList);
+ batchInfo.setFromBankToClearing(bList);
return batchInfo;
}
- log.debug("processing PaymentInstruction's generationId={} senderId={} [fromClearingToBankCreditAmount={}, " +
- "fromBankToClearingCreditAmount={}, " +
- "fromClearingToBankDebitAmount={}, " +
- "fromBankToClearingDebitAmount={}]", generationId, senderId,
- fromClearingToBankCreditAmount,
- fromBankToClearingCreditAmount,
- fromClearingToBankDebitAmount,
- fromBankToClearingDebitAmount);
- batchInfo.setFromClearingToBank(aList);
- batchInfo.setFromBankToClearing(bList);
- return batchInfo;
} else if (ClearingMemberCategoryD.B.equals(categoryValue)) {
+ batchInfo.setInitialOrder(payments);
return batchInfo;
} else {
- log.warn("PaymentInstructions generationId={} senderId={} fail - unknown category ",
- generationId, senderId);
- batchInfo.setError(new EnumMessage(ClearingError.ClearingMemberCategoryUnknown));
- return batchInfo;
+ throw new IllegalStateException("unknown clearing member category");
}
}
}
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf03Builder.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf03Builder.java
new file mode 100644
index 000000000..fc32df0e2
--- /dev/null
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf03Builder.java
@@ -0,0 +1,53 @@
+package ru.spcex.clearing.service;
+
+import ru.clearing.classes.statics.data.payment.PaymentInstruction;
+import ru.clearing.classes.statics.data.sdf.SDf03;
+import ru.spcex.platform.enumeration.Sender;
+import ru.spcex.platform.utils.time.TimeUtil;
+
+import java.time.Instant;
+import java.time.LocalDate;
+
+public class Sdf03Builder {
+ public static SDf03 buildSdf03(PaymentInstruction paymentInstruction, Long generationId) {
+ SDf03 sDf03 = new SDf03();
+ sDf03.setSeg_type("S");
+ sDf03.setDoc_type("002");
+ sDf03.setDocnm_ref(paymentInstruction.getId().toString());
+ sDf03.setPriority("9");
+ sDf03.setSbankcode(Sender.Prc.equalsById(paymentInstruction.getSenderId()) ? "@09999" : "@0");
+ sDf03.setC_acc_deb(paymentInstruction.getDebitLegAccount());
+ sDf03.setSbanknam1(paymentInstruction.getPayeeBankName());
+ // =@00100, если ?;
+ // =@00000, если ?.
+ sDf03.setRbankcode(Sender.Prc.equalsById(paymentInstruction.getSenderId()) ? "@09999" : "@0");
+ sDf03.setC_acc_cred(paymentInstruction.getCreditLegAccount());
+ sDf03.setRbanknam1(paymentInstruction.getAddresseeBankName());
+ sDf03.setPay_date(LocalDate.now().format(TimeUtil.PROPERTY_DATE_FORMATTER));
+ sDf03.setPay_val("RUR");
+ sDf03.setSum_deb(paymentInstruction.getDebitLegAmount() != null ? paymentInstruction.getDebitLegAmount().toString() : null);
+ //37 sp_code varchar(2) Код назначения платежа
+ String[] splitPaymentPurpose = SpecifUtil.splitPaymentPurpose(paymentInstruction.getPaymentPurpose());
+ for (int i = 0; i < splitPaymentPurpose.length; i++) {
+ String specif = splitPaymentPurpose[i];
+ if (i == 0) {
+ sDf03.setSpecif_1(specif);
+ } else if (i == 1) {
+ sDf03.setSpecif_2(specif);
+ } else if (i == 2) {
+ sDf03.setSpecif_3(specif);
+ } else if (i == 3) {
+ sDf03.setSpecif_4(specif);
+ } else if (i == 4) {
+ sDf03.setSpecif_5(specif);
+ } else if (i == 5) {
+ sDf03.setSpecif_6(specif);
+ }
+ }
+ sDf03.setGenerationTime(Instant.now());
+ sDf03.setGenerationId(generationId);
+ //todo
+// sDf03.setPaymentInstructionId(paymentInstruction.getId());
+ return sDf03;
+ }
+}
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf11Builder.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf11Builder.java
new file mode 100644
index 000000000..2d37e878b
--- /dev/null
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf11Builder.java
@@ -0,0 +1,53 @@
+package ru.spcex.clearing.service;
+
+import ru.clearing.classes.statics.data.payment.PaymentInstruction;
+import ru.clearing.classes.statics.data.sdf.SDf11;
+import ru.spcex.platform.enumeration.Sender;
+import ru.spcex.platform.utils.time.TimeUtil;
+
+import java.time.Instant;
+import java.time.LocalDate;
+
+public class Sdf11Builder {
+ public static SDf11 buildSdf11(PaymentInstruction paymentInstruction, Long generationId) {
+ SDf11 sDf11 = new SDf11();
+ sDf11.setSeg_type("S");
+ sDf11.setDoc_type("002");
+ sDf11.setDocnm_ref(paymentInstruction.getId().toString());
+ sDf11.setPriority("9");
+ sDf11.setSbankcode(Sender.Prc.equalsById(paymentInstruction.getSenderId()) ? "@09999" : "@0");
+ sDf11.setC_acc_deb(paymentInstruction.getDebitLegAccount());
+ sDf11.setSbanknam1(paymentInstruction.getPayeeBankName());
+ // =@00100, если ?;
+ // =@00000, если ?.
+ sDf11.setRbankcode(Sender.Prc.equalsById(paymentInstruction.getSenderId()) ? "@09999" : "@0");
+ sDf11.setC_acc_cred(paymentInstruction.getCreditLegAccount());
+ sDf11.setRbanknam1(paymentInstruction.getAddresseeBankName());
+ sDf11.setPay_date(LocalDate.now().format(TimeUtil.PROPERTY_DATE_FORMATTER));
+ sDf11.setPay_val("RUR");
+ sDf11.setSum_deb(paymentInstruction.getDebitLegAmount() != null ? paymentInstruction.getDebitLegAmount().toString() : null);
+ //37 sp_code varchar(2) Код назначения платежа
+ String[] splitPaymentPurpose = SpecifUtil.splitPaymentPurpose(paymentInstruction.getPaymentPurpose());
+ for (int i = 0; i < splitPaymentPurpose.length; i++) {
+ String specif = splitPaymentPurpose[i];
+ if (i == 0) {
+ sDf11.setSpecif_1(specif);
+ } else if (i == 1) {
+ sDf11.setSpecif_2(specif);
+ } else if (i == 2) {
+ sDf11.setSpecif_3(specif);
+ } else if (i == 3) {
+ sDf11.setSpecif_4(specif);
+ } else if (i == 4) {
+ sDf11.setSpecif_5(specif);
+ } else if (i == 5) {
+ sDf11.setSpecif_6(specif);
+ }
+ }
+ sDf11.setGenerationTime(Instant.now());
+ sDf11.setGenerationId(generationId);
+ //todo
+// sDf03.setPaymentInstructionId(paymentInstruction.getId());
+ return sDf11;
+ }
+}
diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/SpecifUtil.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/SpecifUtil.java
new file mode 100644
index 000000000..79ac236da
--- /dev/null
+++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/SpecifUtil.java
@@ -0,0 +1,21 @@
+package ru.spcex.clearing.service;
+
+public class SpecifUtil {
+ public static String[] splitPaymentPurpose(String paymentPurpose) {
+ if (paymentPurpose == null || paymentPurpose.length() < 1) return new String[0];
+ int specifSize = divisionRoundUp(paymentPurpose.length(), 35);
+ specifSize = Math.min(specifSize, 6);
+ String[] res = new String[specifSize];
+ for (int i = 0; i < res.length; i++) {
+ int startIndex = i * 35;
+ int endIndex = Math.min(35 * (i + 1), paymentPurpose.length());
+ res[i] = paymentPurpose.substring(startIndex, endIndex);
+ }
+ return res;
+ }
+
+ public static int divisionRoundUp(int a, int b) {
+ int ostatok = a % b;
+ return a / b + (ostatok > 0 ? 1 : 0);
+ }
+}
diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/SpecifUtilTest.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/SpecifUtilTest.java
new file mode 100644
index 000000000..a53305668
--- /dev/null
+++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/SpecifUtilTest.java
@@ -0,0 +1,76 @@
+package ru.spcex.clearing.service;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class SpecifUtilTest {
+ @Test
+ public void testDivideRoundUp() {
+ Assertions.assertEquals(2, SpecifUtil.divisionRoundUp(36, 35));
+ Assertions.assertEquals(2, SpecifUtil.divisionRoundUp(70, 35));
+ Assertions.assertEquals(3, SpecifUtil.divisionRoundUp(71, 35));
+ }
+
+ @Test
+ public void testSplit() {
+ {
+ //40 symbols
+ String[] splitted = SpecifUtil.splitPaymentPurpose("0123456789012345678901234567890123456789");
+ Assertions.assertEquals(2, splitted.length);
+ Assertions.assertEquals("01234567890123456789012345678901234", splitted[0]);
+ Assertions.assertEquals("56789", splitted[1]);
+ }
+
+ {
+ //40 symbols
+ String[] splitted = SpecifUtil.splitPaymentPurpose("01234567890123456789012345678901234");
+ Assertions.assertEquals(1, splitted.length);
+ Assertions.assertEquals("01234567890123456789012345678901234", splitted[0]);
+ }
+
+ {
+ //10 symbols
+ String[] splitted = SpecifUtil.splitPaymentPurpose("0123456789");
+ Assertions.assertEquals(1, splitted.length);
+ Assertions.assertEquals("0123456789", splitted[0]);
+ }
+
+ {
+ //0 symbols
+ String[] splitted = SpecifUtil.splitPaymentPurpose("");
+ Assertions.assertEquals(0, splitted.length);
+ }
+
+ {
+ //80 symbols
+ String[] splitted = SpecifUtil.splitPaymentPurpose("0123456789012345678901234567890123456789" +
+ "0123456789012345678901234567890123456789");
+ Assertions.assertEquals(3, splitted.length);
+ Assertions.assertEquals("01234567890123456789012345678901234", splitted[0]);
+ Assertions.assertEquals("56789012345678901234567890123456789", splitted[1]);
+ Assertions.assertEquals("0123456789", splitted[2]);
+ }
+
+ {
+ //maximum symbols
+ String[] splitted = SpecifUtil.splitPaymentPurpose("01234567890123456789012345678912345" +
+ "01234567890123456789012345678912345" +
+ "01234567890123456789012345678912345" +
+ "01234567890123456789012345678912345" +
+ "01234567890123456789012345678912345" +
+ "01234567890123456789012345678912345" +
+ "outside of scope"
+ );
+ Assertions.assertEquals(6, splitted.length);
+ for (String s : splitted) {
+ Assertions.assertEquals("01234567890123456789012345678912345", s);
+ }
+ }
+
+
+
+// "";
+ }
+
+
+}
\ No newline at end of file
diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/TransactionStatus.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/TransactionStatus.java
index 812d075bd..2d97429b9 100644
--- a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/TransactionStatus.java
+++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/TransactionStatus.java
@@ -3,7 +3,7 @@ package ru.spcex.platform.enumeration;
import ru.spcex.platform.utils.enumeration.IEnumKey;
public enum TransactionStatus implements IEnumKey {
- stld("STLD");
+ stld("STLD"), notSent("NSNT"), cher("CHER"), sent("SENT");
private final String key;
diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java
index df5ac80b5..baf2b5080 100644
--- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java
+++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java
@@ -35,6 +35,8 @@ public interface Consts {
//todo
String STATEMENT_PROCESS = "statement-process";
String SDF04_PROCESS = "sdf04-process";
+ String SDF03_PROCESS = "sdf03-process";
+ String SDF11_PROCESS = "sdf11-process";
String EXPORT_PROCESS = "export-process";
String ACCOUNT_NEW = "account-new";
String BALANCE_ACCOUNT_NEW = "balance-account-new";
diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/clearing/SdfClearingRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/clearing/SdfClearingRequest.java
new file mode 100644
index 000000000..164e9c15d
--- /dev/null
+++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/clearing/SdfClearingRequest.java
@@ -0,0 +1,16 @@
+package ru.spcex.clearing.platform.messaging.domain.cud.clearing;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class SdfClearingRequest {
+ @JsonProperty
+ private Long groupId;
+
+ public Long getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(Long groupId) {
+ this.groupId = groupId;
+ }
+}
\ No newline at end of file