diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/InformationAccountService.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/InformationAccountService.java index afb85ec6f..61d80a88d 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/InformationAccountService.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/service/InformationAccountService.java @@ -1,5 +1,6 @@ package ru.spcex.clearing.account.service; +import org.apache.commons.lang3.StringUtils; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.producer.Producer; import org.slf4j.Logger; @@ -31,12 +32,16 @@ import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.log.ExceptionUtils; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; import java.util.Collection; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; @Service public class InformationAccountService extends QueueConsumer implements InitializingBean { @@ -50,6 +55,11 @@ public class InformationAccountService extends QueueConsumer implements Initiali private final Function infoAccountNewRequestValidator; private final Imdg informationAccountImdg; private final Imdg accountImdg; + /** + * Кэш-счётчик сквозных номеров счетов. + * См. accountNextId() + */ + protected AtomicLong infoCounter; @Autowired public InformationAccountService(Consumer kafkaQueue, @@ -61,7 +71,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali AccountService accountService, RequestHelper requestHelper, @Qualifier("informationAccountNewRequestValidator") - Function infoAccountNewRequestValidator) { + Function infoAccountNewRequestValidator) { super(kafkaQueue, kafkaResponseQueue); this.kafkaSender = kafkaSender; this.messageResolver = messageResolver; @@ -96,7 +106,9 @@ public class InformationAccountService extends QueueConsumer implements Initiali if (requestInfoUpdate != null) return requestInfoUpdate; Long newId = informationAccountImdg.nextIDSequenceFor(); - String accountValue = generateInfoAccount(newId); + Long infoSequenceId = accountNextId(); + String accountValue = generateInfoAccount(infoSequenceId); + log.trace("New info-account id={}, sequenceId={}, account={}", newId, infoSequenceId, accountValue); ImdgPredicateBuilder accountPredicateBuilder = accountImdg.predicateBuilder(); ImdgPredicate companyIdPredicate = accountPredicateBuilder.equals("companyId", 1L); @@ -184,7 +196,9 @@ public class InformationAccountService extends QueueConsumer implements Initiali // todo требуется последовательность n+1 Long newId = informationAccountImdg.nextIDSequenceFor(); - String accountValue = generateInfoAccount(newId); + Long infoSequenceId = accountNextId(); + String accountValue = generateInfoAccount(infoSequenceId); + log.trace("New info-account id={}, sequenceId={}, account={}", newId, infoSequenceId, accountValue); ImdgPredicate andPredicate = pb.and( pb.equals("companyId", 1L), @@ -251,4 +265,48 @@ public class InformationAccountService extends QueueConsumer implements Initiali return "%d%d%08d%d".formatted(39911, 810, id, 7000); } + + /** + * Сквозной номер инфо-счетов + * + * @return infoCounter++ + */ + protected Long accountNextId() { + if (infoCounter == null) synchronized (this) { + if (infoCounter == null) { + log.debug("Init account-information counter."); + Collection allInfoAcc = accountImdg.getCollectionObjectsByFieldValues(Map.of("accountType", AccountType.Info.getKey())); + if (allInfoAcc.isEmpty()) { + infoCounter = new AtomicLong(1); + log.debug("No account information on map. n={}", infoCounter.get()); + } else { + Pattern accPattern = Pattern.compile("39911810([0-9]{8})7000"); + int maxN = 1; + int parsedCount = 0; + for (Account acc : allInfoAcc) { + try { + String number = acc.getAccount(); + if (StringUtils.isEmpty(number)) continue; + Matcher m = accPattern.matcher(number); + if (m.find()) { + String seqNumber = m.group(1); + if (StringUtils.isNotEmpty(seqNumber)) { + int accN = Integer.parseInt(seqNumber); + if (accN > maxN) maxN = accN; + } + parsedCount++; + } + } catch (Exception errParse) { + log.warn("Error parse account {}: {}", acc.getId(), ExceptionUtils.getStackTrace(errParse)); + } + } + infoCounter = new AtomicLong(maxN); + log.debug("Parsed {} information accounts ({} pattern match) in map. n={}", + allInfoAcc.size(), parsedCount, infoCounter.get()); + } + } + } + return infoCounter.getAndIncrement(); + } + } diff --git a/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/InformationAccountServiceTest.java b/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/InformationAccountServiceTest.java index 1b52c1d3f..1c0202ca3 100644 --- a/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/InformationAccountServiceTest.java +++ b/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/InformationAccountServiceTest.java @@ -4,6 +4,7 @@ import org.apache.kafka.clients.consumer.MockConsumer; import org.apache.kafka.clients.producer.MockProducer; import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.ProducerRecord; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -32,6 +33,7 @@ import ru.spcex.clearing.test.config.ImdgTestConfig; import ru.spcex.clearing.test.config.KafkaTestConfig; import ru.spcex.platform.enumeration.*; import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; import javax.annotation.PostConstruct; @@ -179,4 +181,29 @@ class InformationAccountServiceTest { accountImdg.delete(resultAccountNew); } + @Autowired ImdgProvider imdgProvider; + @Test + void accountIncrementSequence() { + Imdg accountInfoImdg = hazelcastServiceTest.getImdg( IMDGDistributedNames.Map_InformationAccount, InformationAccount.class ); + + { + Account account = new Account(); + account.setId(120L); + account.setAccountType(AccountType.Info.getKey()); + account.setCompanyId(10L); + account.setAccount("39911810000000127000"); + accountImdg.insert(account); + InformationAccount accountInfo = new InformationAccount(); + accountInfo.setId(121L); + accountInfo.setAccountId(account.getId()); + accountInfo.setCompanyId(account.getCompanyId()); + accountInfoImdg.insert(accountInfo); + } + InformationAccountService infoAccSvc=new InformationAccountService(null,null,null, + null, imdgProvider, null, null, null, null); + Long n = infoAccSvc.accountNextId(); + Assertions.assertEquals(12L, n); + n = infoAccSvc.accountNextId(); + Assertions.assertEquals(13L, n); + } } \ No newline at end of file