From fa0b7ba7878b64335617f19f58304a4fbfd8d387 Mon Sep 17 00:00:00 2001 From: ialbert Date: Thu, 1 Dec 2022 11:15:46 +0300 Subject: [PATCH] http://jira.mfd.msk:8088/browse/CLS-130 sdf03 sdf11 --- clearing-parent/clearing-service/pom.xml | 10 +++ .../spcex/clearing/error/ClearingError.java | 2 - .../clearing/service/ClearingService.java | 86 ++++++++++++++----- .../clearing/service/PaymentBatchInfo.java | 23 +++++ ...sor.java => PaymentInstructionSorter.java} | 86 ++++++++----------- .../spcex/clearing/service/Sdf03Builder.java | 53 ++++++++++++ .../spcex/clearing/service/Sdf11Builder.java | 53 ++++++++++++ .../ru/spcex/clearing/service/SpecifUtil.java | 21 +++++ .../clearing/service/SpecifUtilTest.java | 76 ++++++++++++++++ .../enumeration/TransactionStatus.java | 2 +- .../platform/messaging/domain/Consts.java | 2 + .../cud/clearing/SdfClearingRequest.java | 16 ++++ 12 files changed, 355 insertions(+), 75 deletions(-) rename clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/{PaymentBatchProcessor.java => PaymentInstructionSorter.java} (55%) create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf03Builder.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf11Builder.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/SpecifUtil.java create mode 100644 clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/SpecifUtilTest.java create mode 100644 platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/clearing/SdfClearingRequest.java 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