http://jira.mfd.msk:8088/browse/CLS-130 sdf03 sdf11
This commit is contained in:
parent
ce767ceae1
commit
fa0b7ba787
12 changed files with 355 additions and 75 deletions
|
|
@ -41,6 +41,16 @@
|
|||
<groupId>ru.spcex.platform</groupId>
|
||||
<artifactId>platform-enum</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<PaymentInstruction> paymentImdgs;
|
||||
private final ExecutorService executor;
|
||||
private final ImdgId idGenerator;
|
||||
private final PaymentBatchProcessor senderGroupProcessor;
|
||||
private final PaymentInstructionSorter senderGroupSorter;
|
||||
private final Imdg<SDf03> sdf03Imdg;
|
||||
private final Imdg<SDf11> 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<Long, List<PaymentInstruction>> 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<senderId -> PaymentBatchInfo>
|
||||
//PaymentBatchInfo содержит возможную ошибку, при необходимости отсортированные Payment
|
||||
//тип ClearingMemberCategory
|
||||
Map<Long, PaymentBatchInfo> processResults = pmtInsBySender
|
||||
//выгружаем PaymentInstructions с нужным статусом
|
||||
Map<Long, PaymentBatchInfo> 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<senderId -> PaymentBatchInfo>
|
||||
//PaymentBatchInfo содержит возможную ошибку, при необходимости отсортированные Payment
|
||||
//тип ClearingMemberCategory
|
||||
.map(entry -> {
|
||||
Long senderId = entry.getKey();
|
||||
List<PaymentInstruction> 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<PaymentInstruction> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PaymentInstruction> initialOrder;
|
||||
private List<PaymentInstruction> fromClearingToBank;
|
||||
private List<PaymentInstruction> fromBankToClearing;
|
||||
private ClearingMemberCategoryD categoryD;
|
||||
private EnumMessage error;
|
||||
|
||||
public Stream<PaymentInstruction> getOrderedPaymentInstructions() {
|
||||
Function<Collection<PaymentInstruction>, Stream<PaymentInstruction>> 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<PaymentInstruction> getFromClearingToBank() {
|
||||
return fromClearingToBank;
|
||||
}
|
||||
|
|
@ -43,4 +58,12 @@ public class PaymentBatchInfo {
|
|||
public void setError(EnumMessage error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public List<PaymentInstruction> getInitialOrder() {
|
||||
return initialOrder;
|
||||
}
|
||||
|
||||
public void setInitialOrder(List<PaymentInstruction> initialOrder) {
|
||||
this.initialOrder = initialOrder;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ClearingMemberCategory> clrngMmbrImdg;
|
||||
private final Imdg<Account> accImdg;
|
||||
private final IMessageResolver messageResolver;
|
||||
private final Imdg<PaymentInstruction> 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<PaymentInstruction> payments) {
|
||||
PaymentBatchInfo sortCompanyPayments(Long generationId, Long senderId, List<PaymentInstruction> 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<PaymentInstruction> aList = new ArrayList<>();
|
||||
List<PaymentInstruction> 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<List<PaymentInstruction>, Long> creditAmountSum = paymentInstructions -> paymentInstructions
|
||||
|
|
@ -84,55 +78,43 @@ public class PaymentBatchProcessor {
|
|||
.reduce(0L, Long::sum);
|
||||
Function<List<PaymentInstruction>, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// "";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue