Compare commits
7 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e7bfa51a0 | ||
|
|
99222c740e | ||
|
|
5dc5e72496 | ||
|
|
b85cda38ef | ||
|
|
14138b4455 | ||
|
|
786cc89718 | ||
|
|
6b0f8668ae |
98 changed files with 847 additions and 4892 deletions
|
|
@ -8,9 +8,9 @@ server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b
|
||||||
# datasources
|
# datasources
|
||||||
# indic
|
# indic
|
||||||
ct.indic-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver
|
ct.indic-data-source-settings.driver=com.ibm.db2.jcc.DB2Driver
|
||||||
ct.indic-data-source-settings.url=${DB_URL_INDIC:jdbc:db2://10.230.227.100:2668/cprosd22:currentSchema=INDIC;}
|
ct.indic-data-source-settings.url=${DB_URL_INDIC:jdbc:db2://10.230.227.101:2668/cprosd22:currentSchema=INDIC;}
|
||||||
ct.indic-data-source-settings.username=${USERNAME_INDIC:ros9appl}
|
ct.indic-data-source-settings.username=${USERNAME_INDIC:tester}
|
||||||
ct.indic-data-source-settings.password=${PASSWORD_INDIC:R0s9Appl}
|
ct.indic-data-source-settings.password=${PASSWORD_INDIC:tester}
|
||||||
ct.indic-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_INDIC:10}
|
ct.indic-data-source-settings.maximum-pool-size=${MAXIMUM_POOL_SIZE_INDIC:10}
|
||||||
ct.indic-data-source-settings.minimum-idle=${MINIMUM_IDLE_INDIC:10}
|
ct.indic-data-source-settings.minimum-idle=${MINIMUM_IDLE_INDIC:10}
|
||||||
ct.indic-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_INDIC:10000}
|
ct.indic-data-source-settings.connection-timeout=${CONNECTION_TIMEOUT_INDIC:10000}
|
||||||
|
|
@ -60,18 +60,13 @@ ct.signals-root-uri=${SIGNALS_ROOT_URI:http://10.230.227.102:11094/signalRUalfa/
|
||||||
ct.signals-token=${SIGNALS_TOKEN:gttcHxwcGojoAvZK}
|
ct.signals-token=${SIGNALS_TOKEN:gttcHxwcGojoAvZK}
|
||||||
ct.signals-user=${SIGNALS_USER:0001ZZ000001}
|
ct.signals-user=${SIGNALS_USER:0001ZZ000001}
|
||||||
|
|
||||||
#ct.load-dir=/opt/app/reports
|
ct.load-dir=/opt/app/reports
|
||||||
ct.load-dir=D:\\folder_name\\signals
|
#ct.load-dir=D:\\folder_name\\signals
|
||||||
|
|
||||||
# min
|
# min
|
||||||
ct.monitoring-interval=${MONITORING_INTERVAL:15}
|
ct.monitoring-interval=${MONITORING_INTERVAL:15}
|
||||||
# days
|
# days
|
||||||
ct.update-flags-interval=${UPDATE_FLAGS_INTERVAL:1}
|
ct.update-flags-cron-expression=${UPDATE_FLAGS_CRON_EXPRESSION:0 0 22 * * *}
|
||||||
ct.days-to-update-flags=${DAYS_TO_UPDATE_FLAGS:30}
|
ct.days-to-update-flags=${DAYS_TO_UPDATE_FLAGS:30}
|
||||||
|
|
||||||
ct.encoding=windows-1251
|
ct.encoding=windows-1251
|
||||||
|
|
||||||
#Batch size and global pipeline timeout
|
|
||||||
ct.batchSize=1000
|
|
||||||
#in minute
|
|
||||||
ct.timeout=30
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#commons
|
#commons
|
||||||
APP_VERSION=1.20
|
APP_VERSION=1.24
|
||||||
REGISTRY_URL=rh8-vm3.nbki.msk:5000
|
REGISTRY_URL=rh8-vm3.nbki.msk:5000
|
||||||
JMX_PORT=
|
JMX_PORT=
|
||||||
JMX_HOSTNAME=
|
JMX_HOSTNAME=
|
||||||
|
|
@ -71,7 +71,7 @@ SIGNALS_USER=0001ZZ000001
|
||||||
# min
|
# min
|
||||||
MONITORING_INTERVAL=15
|
MONITORING_INTERVAL=15
|
||||||
# days
|
# days
|
||||||
UPDATE_FLAGS_INTERVAL=1
|
UPDATE_FLAGS_CRON_EXPRESSION=0 22 * * *
|
||||||
DAYS_TO_UPDATE_FLAGS=30
|
DAYS_TO_UPDATE_FLAGS=30
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
8
pom.xml
8
pom.xml
|
|
@ -10,12 +10,12 @@
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>ru.nbch</groupId>
|
<groupId>ru.nbch</groupId>
|
||||||
<artifactId>credit-tracker</artifactId>
|
<artifactId>credit-tracker</artifactId>
|
||||||
<version>2.0</version>
|
<version>1.24</version>
|
||||||
<name>credit_tracker</name>
|
<name>credit_tracker</name>
|
||||||
<description>Credit Tracker Application</description>
|
<description>Credit Tracker Application</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>21</java.version>
|
<java.version>17</java.version>
|
||||||
<git.info.prefix>git_info</git.info.prefix>
|
<git.info.prefix>git_info</git.info.prefix>
|
||||||
<git.info.filename>git.properties</git.info.filename>
|
<git.info.filename>git.properties</git.info.filename>
|
||||||
<registry.url>10.230.238.56:5000</registry.url>
|
<registry.url>10.230.238.56:5000</registry.url>
|
||||||
|
|
@ -41,10 +41,6 @@
|
||||||
<artifactId>postgresql</artifactId>
|
<artifactId>postgresql</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
|
||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ibm.db2</groupId>
|
<groupId>com.ibm.db2</groupId>
|
||||||
<artifactId>jcc</artifactId>
|
<artifactId>jcc</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,21 @@ package ru.nbch.credit_tracker;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import ru.nbch.credit_tracker.service.MonitoringService;
|
||||||
|
import ru.nbch.credit_tracker.service.UpdateProcessingPackagesService;
|
||||||
|
import ru.nbch.credit_tracker.service.UpdatingFlagsService;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class CreditTrackerApplication {
|
public class CreditTrackerApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ConfigurableApplicationContext ctx = SpringApplication.run(CreditTrackerApplication.class, args);
|
ConfigurableApplicationContext ctx = SpringApplication.run(CreditTrackerApplication.class, args);
|
||||||
// UpdateProcessingPackagesService updateProcessingPackagesService = ctx.getBean(UpdateProcessingPackagesService.class);
|
UpdateProcessingPackagesService updateProcessingPackagesService = ctx.getBean(UpdateProcessingPackagesService.class);
|
||||||
// MonitoringService monitoringService = ctx.getBean(MonitoringService.class);
|
MonitoringService monitoringService = ctx.getBean(MonitoringService.class);
|
||||||
// UpdatingFlagsService updatingFlagsService = ctx.getBean(UpdatingFlagsService.class);
|
UpdatingFlagsService updatingFlagsService = ctx.getBean(UpdatingFlagsService.class);
|
||||||
// updateProcessingPackagesService.run();
|
monitoringService.run();
|
||||||
// monitoringService.run();
|
updatingFlagsService.run();
|
||||||
// updatingFlagsService.run();
|
updateProcessingPackagesService.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.builder;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Person;
|
|
||||||
import ru.nbch.credit_tracker.model.IdData;
|
|
||||||
import ru.nbch.credit_tracker.model.NameData;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class PersonFactoryBuilderV2 {
|
|
||||||
private final static DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd.MM.yyyy");
|
|
||||||
|
|
||||||
private final static String DEFAULT_DATE = "01.01.2000";
|
|
||||||
private final static String IP = "0";
|
|
||||||
private final static String OKSM = "999";
|
|
||||||
private final static String CONSENT_PURPOSE = "16";
|
|
||||||
private final static String REPORT_USER = "АО «НБКИ»";
|
|
||||||
private final static String LIABILITY = "1";
|
|
||||||
private final static String CONSENT_PERIOD = "3";
|
|
||||||
private final static String REPORT_USER_REG_NUM = "1057746710713";
|
|
||||||
private final static String REPORT_USER_TAX_ID = "7703548386";
|
|
||||||
private final static String CONSENT_HASH = "hash";
|
|
||||||
private final static String CONSENT_DIV_CODE = "000-000";
|
|
||||||
private final static String INQ_PURPOSE = "16";
|
|
||||||
private final static String ODT = "Иной документ";
|
|
||||||
private final static String CONSENT_ISSUE_AUTHORITY = "Кем выдан";
|
|
||||||
|
|
||||||
|
|
||||||
private SubjectProfile personData;
|
|
||||||
private Long uid;
|
|
||||||
|
|
||||||
public static PersonFactoryBuilderV2 builder() {
|
|
||||||
return new PersonFactoryBuilderV2();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PersonFactoryBuilderV2 personData(SubjectProfile personData) {
|
|
||||||
this.personData = personData;
|
|
||||||
//todo откуда брать этот id
|
|
||||||
// this.uid = personData.getIdentifier();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Person build() {
|
|
||||||
if (personData == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
NameData nameData = personData.getNameData();
|
|
||||||
IdData passportData = personData.getIdData();
|
|
||||||
Person person = new Person();
|
|
||||||
person.setS(nameData.getLastName());
|
|
||||||
person.setN(nameData.getFirstName());
|
|
||||||
person.setM(StringUtils.isNotBlank(nameData.getMiddleName()) ? nameData.getMiddleName() : null);
|
|
||||||
person.setD(DATE_FORMAT.format(nameData.getBirthDate()));
|
|
||||||
|
|
||||||
person.setPn(getPn(passportData.getSerNum(), passportData.getIdNum()));
|
|
||||||
person.setPd(DATE_FORMAT.format(LocalDate.now())); // Do not use passport iss_date. Signal service could reject the package
|
|
||||||
person.setDt(getDt(passportData.getIdType(), passportData.getIdType2()));
|
|
||||||
if (person.getDt() != null && person.getDt().equals("999")) {
|
|
||||||
person.setOdt(ODT);
|
|
||||||
person.setConsentOdt(ODT);
|
|
||||||
}
|
|
||||||
person.setIp(IP);
|
|
||||||
person.setUid(uid);
|
|
||||||
person.setOksm(OKSM);
|
|
||||||
person.setConsentDate(DATE_FORMAT.format(LocalDate.now()));
|
|
||||||
person.setConsentPurpose(CONSENT_PURPOSE);
|
|
||||||
person.setReportUser(REPORT_USER);
|
|
||||||
person.setLiability(LIABILITY);
|
|
||||||
person.setConsentPeriod(CONSENT_PERIOD);
|
|
||||||
person.setAgrDate(DATE_FORMAT.format(LocalDate.now()));
|
|
||||||
person.setReportUserRegNum(REPORT_USER_REG_NUM);
|
|
||||||
person.setReportUserTaxID(REPORT_USER_TAX_ID);
|
|
||||||
person.setConsentHash(CONSENT_HASH);
|
|
||||||
|
|
||||||
person.setCs(person.getS());
|
|
||||||
person.setConsentN(person.getN());
|
|
||||||
person.setConsentM(person.getM());
|
|
||||||
person.setConsentBd(person.getD());
|
|
||||||
person.setConsentPn(person.getPn());
|
|
||||||
person.setConsentPd(person.getPd());
|
|
||||||
person.setConsentDivCode(CONSENT_DIV_CODE);
|
|
||||||
person.setConsentDt(person.getDt());
|
|
||||||
person.setConsentIssueAuthority(CONSENT_ISSUE_AUTHORITY);
|
|
||||||
person.setInqPurpose(INQ_PURPOSE);
|
|
||||||
return person;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPn(String serNum, String idNum) {
|
|
||||||
String normSerNum = CTUtil.normalize(serNum);
|
|
||||||
String normIdNum = CTUtil.normalize(idNum);
|
|
||||||
return StringUtils.isNotBlank(normSerNum) ? normSerNum + normIdNum : normIdNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDt(String idType, String idType2) {
|
|
||||||
if (StringUtils.isNotBlank(idType2)) {
|
|
||||||
return idType2;
|
|
||||||
} else {
|
|
||||||
return switch (idType) {
|
|
||||||
case "21" -> "21";
|
|
||||||
case "22" -> "22.1";
|
|
||||||
case "09" -> "22.2";
|
|
||||||
case "26" -> "23";
|
|
||||||
case "04" -> "24";
|
|
||||||
case "07" -> "25";
|
|
||||||
case "14", "03" -> "27";
|
|
||||||
case "10" -> "31";
|
|
||||||
case "15" -> "32";
|
|
||||||
case "13" -> "37";
|
|
||||||
case "06", "27" -> "28";
|
|
||||||
case "01", "02" -> "999";
|
|
||||||
default -> {
|
|
||||||
log.warn("ID_TYPE2 is blank and no matching found for ID_TYPE {}", idType);
|
|
||||||
yield "";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.component;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
|
||||||
import ru.nbch.credit_tracker.enums.SignalError;
|
|
||||||
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
|
|
||||||
import ru.nbch.credit_tracker.exceptions.SignalException;
|
|
||||||
import ru.nbch.credit_tracker.model.MonitoringValidationError;
|
|
||||||
import ru.nbch.credit_tracker.model.ValidationResult;
|
|
||||||
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
|
|
||||||
import ru.nbch.credit_tracker.utils.ValidationService;
|
|
||||||
import ru.nbch.credit_tracker.utils.ZipUtils;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
|
|
||||||
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
|
|
||||||
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
public class MonitoringRequestValidator {
|
|
||||||
private final CreditTrackerSettings config;
|
|
||||||
private final ValidationService validationService;
|
|
||||||
private final StaxXmlProcessor staxXmlProcessor;
|
|
||||||
|
|
||||||
public MonitoringRequestValidator(CreditTrackerSettings config,
|
|
||||||
ValidationService validationService,
|
|
||||||
StaxXmlProcessor staxXmlProcessor) {
|
|
||||||
this.config = config;
|
|
||||||
this.validationService = validationService;
|
|
||||||
this.staxXmlProcessor = staxXmlProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateZipContent(MultipartFile file) {
|
|
||||||
log.trace("Validating zip content");
|
|
||||||
if (file.isEmpty() || !ZipUtils.isZipFile(file)) {
|
|
||||||
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Валидация Архива на количетсво файлов, размер и расширение
|
|
||||||
try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream())) {
|
|
||||||
Optional<ZipEntry> xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream);
|
|
||||||
if (xmlFileEntry.isEmpty()) {
|
|
||||||
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
|
|
||||||
}
|
|
||||||
long maxXmlFileSize = config.getMaxXmlFileSize() * 1024 * 1024;
|
|
||||||
if (xmlFileEntry.get().getSize() > maxXmlFileSize) {
|
|
||||||
throw clientExcp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
|
||||||
}
|
|
||||||
log.trace("Validated zip content ok!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValidationResult readAndValidateMonitoringRequest(String filePath) {
|
|
||||||
log.debug("Validating monitoring request...");
|
|
||||||
ValidationResult validationResult = new ValidationResult();
|
|
||||||
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
|
|
||||||
staxXmlProcessor.read(in, MonitoringRequest.class,
|
|
||||||
request -> {
|
|
||||||
try {
|
|
||||||
validationService.validateMonitoringRequest(request);
|
|
||||||
if (request.getPackageName() != null && validationResult.getPackageName() == null) {
|
|
||||||
validationResult.setPackageName(request.getPackageName());
|
|
||||||
}
|
|
||||||
if (request.getUserId() != null && validationResult.getUserId() == null) {
|
|
||||||
validationResult.setUserId(request.getUserId());
|
|
||||||
}
|
|
||||||
if (request.getPassword() != null && validationResult.getPassword() == null) {
|
|
||||||
validationResult.setPassword(request.getPassword());
|
|
||||||
}
|
|
||||||
request.getSubjects().getSubject().clear();
|
|
||||||
} catch (SignalException e) {
|
|
||||||
validationResult.addError(new MonitoringValidationError(-1, "", e));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
request -> request.getSubjects().getSubject().isEmpty(),
|
|
||||||
40000, "/MonitoringRequest/Subjects/Subject");
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Error while parsing and validating monitoring request", e);
|
|
||||||
}
|
|
||||||
log.debug("Validating monitoring request {}!", validationResult.getValidationErrors().isEmpty() ? "ok" : "fail");
|
|
||||||
return validationResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.component;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
|
||||||
import org.aspectj.lang.annotation.Around;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Aspect
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class RepositoryTimingAspect {
|
|
||||||
@Around("within(@org.springframework.stereotype.Repository *)")
|
|
||||||
public Object timeMapper(ProceedingJoinPoint pjp) throws Throwable {
|
|
||||||
long start = System.nanoTime();
|
|
||||||
try {
|
|
||||||
return pjp.proceed();
|
|
||||||
} finally {
|
|
||||||
long tookMs = (System.nanoTime() - start) / 1_000_000;
|
|
||||||
String method = pjp.getSignature().toShortString();
|
|
||||||
if (tookMs > 1000) {
|
|
||||||
log.warn("Slow jdbc template call {} took {} ms", method, tookMs);
|
|
||||||
} else {
|
|
||||||
log.debug("Jdbc template call {} took {} ms", method, tookMs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,8 +4,6 @@ import com.zaxxer.hikari.HikariDataSource;
|
||||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||||
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
|
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
public class DatabaseConfig {
|
public class DatabaseConfig {
|
||||||
|
|
||||||
protected HikariDataSource createDataSource(DataSourceSettings settings) {
|
protected HikariDataSource createDataSource(DataSourceSettings settings) {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
|
import ru.nbch.credit_tracker.config.settings.DataSourceSettings;
|
||||||
|
|
||||||
|
|
@ -61,10 +60,5 @@ public class IndicDataSourceConfig extends DatabaseConfig {
|
||||||
sqlSessionFactoryBean.setTypeHandlersPackage("ru.nbch.credit_tracker.config.datasource.handlers");
|
sqlSessionFactoryBean.setTypeHandlersPackage("ru.nbch.credit_tracker.config.datasource.handlers");
|
||||||
return sqlSessionFactoryBean.getObject();
|
return sqlSessionFactoryBean.getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "jdbcTemplateIndic")
|
|
||||||
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(@Qualifier("indicDataSource") DataSource dataSource) {
|
|
||||||
return new NamedParameterJdbcTemplate(dataSource);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.config.datasource.handlers;
|
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Types;
|
|
||||||
import java.util.UUID;
|
|
||||||
import org.apache.ibatis.type.JdbcType;
|
|
||||||
import org.apache.ibatis.type.MappedTypes;
|
|
||||||
import org.apache.ibatis.type.TypeHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
@MappedTypes({UUID.class})
|
|
||||||
public class UUIDTypeHandler implements TypeHandler<UUID> {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(UUIDTypeHandler.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException {
|
|
||||||
if (parameter == null) {
|
|
||||||
ps.setObject(i, null, Types.OTHER);
|
|
||||||
} else {
|
|
||||||
ps.setObject(i, parameter.toString(), Types.OTHER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getResult(ResultSet rs, String columnName) throws SQLException {
|
|
||||||
return toUUID(rs.getString(columnName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getResult(ResultSet rs, int columnIndex) throws SQLException {
|
|
||||||
return toUUID(rs.getString(columnIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getResult(CallableStatement cs, int columnIndex) throws SQLException {
|
|
||||||
return toUUID(cs.getString(columnIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UUID toUUID(String val) {
|
|
||||||
if (val != null && !val.isEmpty() && !val.isBlank()) {
|
|
||||||
try {
|
|
||||||
return UUID.fromString(val);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
log.warn("Bad UUID found: {}", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.config.mdc;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import ru.nbch.credit_tracker.utils.LogUtil;
|
|
||||||
|
|
||||||
// Annotation to only clear the MDC key at method exit
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
public @interface ClearMdc {
|
|
||||||
String key() default LogUtil.mdcKey;
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +1,18 @@
|
||||||
package ru.nbch.credit_tracker.config.mdc;
|
package ru.nbch.credit_tracker.config.mdc;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import org.slf4j.MDC;
|
||||||
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
||||||
import ru.nbch.credit_tracker.utils.LogUtil;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Aspect
|
@Aspect
|
||||||
public class MdcAspect {
|
public class MdcAspect {
|
||||||
|
|
||||||
// For methods that only require clearing the MDC at the end
|
|
||||||
@Around("@annotation(clearMdc)")
|
|
||||||
public Object clearMdcAdvice(ProceedingJoinPoint pjp, ClearMdc clearMdc) throws Throwable {
|
|
||||||
try {
|
|
||||||
return pjp.proceed();
|
|
||||||
} finally {
|
|
||||||
LogUtil.removeMdcLogKey(clearMdc.key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For methods that set an MDC value (from a method argument) and then clear it at the end
|
// For methods that set an MDC value (from a method argument) and then clear it at the end
|
||||||
@Around("@annotation(setAndClearMdc)")
|
@Around("@annotation(setAndClearMdc)")
|
||||||
public Object setAndClearMdcAdvice(ProceedingJoinPoint pjp, SetAndClearMdc setAndClearMdc) throws Throwable {
|
public Object setAndClearMdcAdvice(ProceedingJoinPoint pjp, SetAndClearMdc setAndClearMdc) throws Throwable {
|
||||||
|
|
@ -29,18 +20,30 @@ public class MdcAspect {
|
||||||
int index = setAndClearMdc.argIndex();
|
int index = setAndClearMdc.argIndex();
|
||||||
Object obj = (args != null && args.length > index) ? args[index] : null;
|
Object obj = (args != null && args.length > index) ? args[index] : null;
|
||||||
if (obj instanceof MonitoringRequest request) {
|
if (obj instanceof MonitoringRequest request) {
|
||||||
LogUtil.addMdcLogKey(setAndClearMdc.key(), request.getPackageName());
|
if (request.getPackageName() != null) {
|
||||||
|
putMdcValue(setAndClearMdc.key(), request.getPackageName());
|
||||||
|
}
|
||||||
} else if (obj instanceof UserPackage userPackage) {
|
} else if (obj instanceof UserPackage userPackage) {
|
||||||
LogUtil.addMdcLogKey(setAndClearMdc.key(), userPackage.getPackageName());
|
if (userPackage.getPackageName() != null) {
|
||||||
|
putMdcValue(setAndClearMdc.key(), userPackage.getPackageName());
|
||||||
|
}
|
||||||
} else if (obj instanceof String packageName) {
|
} else if (obj instanceof String packageName) {
|
||||||
LogUtil.addMdcLogKey(setAndClearMdc.key(), packageName);
|
putMdcValue(setAndClearMdc.key(), packageName);
|
||||||
} else {
|
} else {
|
||||||
log.debug("no packageName found for for {}", pjp.toShortString());
|
log.debug("no packageName found for for {}", pjp.toShortString());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return pjp.proceed();
|
return pjp.proceed();
|
||||||
} finally {
|
} finally {
|
||||||
LogUtil.removeMdcLogKey(setAndClearMdc.key());
|
MDC.remove(setAndClearMdc.key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putMdcValue(String key, String value) {
|
||||||
|
try {
|
||||||
|
MDC.put(key, "[" + value + "] ");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("{}", ExceptionUtils.getStackTrace(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,12 @@ import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
import ru.nbch.credit_tracker.utils.LogUtil;
|
|
||||||
|
|
||||||
// Annotation to set an MDC key based on a method argument and clear it after method execution
|
// Annotation to set an MDC key based on a method argument and clear it after method execution
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface SetAndClearMdc {
|
public @interface SetAndClearMdc {
|
||||||
String key() default LogUtil.mdcKey;
|
String key() default "ru.nbch.credit_tracker.log.mdc.key";
|
||||||
// The index of the method argument to use for the MDC value (defaults to the first argument)
|
// The index of the method argument to use for the MDC value (defaults to the first argument)
|
||||||
int argIndex() default 0;
|
int argIndex() default 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package ru.nbch.credit_tracker.config.rest;
|
package ru.nbch.credit_tracker.config.rest;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
@ -10,19 +9,15 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
import ru.nbch.credit_tracker.entities.user_response.errors.CommonError;
|
import ru.nbch.credit_tracker.entities.user_response.errors.*;
|
||||||
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringActivePackagesError;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringAllPackagesError;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringDownloadError;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringError;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringPackageDeleteError;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringReportListError;
|
|
||||||
import ru.nbch.credit_tracker.enums.SignalError;
|
import ru.nbch.credit_tracker.enums.SignalError;
|
||||||
import ru.nbch.credit_tracker.exceptions.SignalClientException;
|
import ru.nbch.credit_tracker.exceptions.SignalClientException;
|
||||||
import ru.nbch.credit_tracker.exceptions.SignalException;
|
import ru.nbch.credit_tracker.exceptions.SignalException;
|
||||||
import ru.nbch.credit_tracker.exceptions.SignalServerException;
|
import ru.nbch.credit_tracker.exceptions.SignalServerException;
|
||||||
import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver;
|
import ru.nbch.credit_tracker.utils.error.SimpleMessageResolver;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
@ -47,33 +42,34 @@ public class GlobalExceptionHandler {
|
||||||
return new ResponseEntity<>(error, headers, HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(error, headers, HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(value = SignalClientException.class, produces = MediaType.APPLICATION_XML_VALUE)
|
@ExceptionHandler(value = SignalException.class, produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
public ResponseEntity<CommonError> handleClientException(SignalClientException ex) {
|
public ResponseEntity<CommonError> handleClientException(SignalException ex) {
|
||||||
CommonError err = getCommonError(ex);
|
|
||||||
String packageName = ex.getPackageName();
|
|
||||||
if(packageName != null ) {
|
|
||||||
log.warn("Response error: {}. PackageName: {}", err.getErrorText(), packageName);
|
|
||||||
} else {
|
|
||||||
log.warn("Response error: {}", err.getErrorText());
|
|
||||||
}
|
|
||||||
return new ResponseEntity<>(err, xmlHeaders(), HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(value = SignalServerException.class, produces = MediaType.APPLICATION_XML_VALUE)
|
|
||||||
public ResponseEntity<CommonError> handleServerException(SignalServerException ex) {
|
|
||||||
CommonError commonError = getCommonError(ex);
|
|
||||||
Exception cause = ex.getCause();
|
|
||||||
log.error(cause.getMessage(), cause);
|
|
||||||
return new ResponseEntity<>(commonError, xmlHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpHeaders xmlHeaders() {
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(new MediaType("application", "xml", Charset.forName(encoding)));
|
headers.setContentType(new MediaType("application", "xml", Charset.forName(encoding)));
|
||||||
return headers;
|
|
||||||
|
String errorText = messageResolver.resolve(ex.getErrorMessage());
|
||||||
|
|
||||||
|
CommonError commonError = getCommonError(ex);
|
||||||
|
commonError.setStatus("error");
|
||||||
|
commonError.setErrorCode(ex.getErrorMessage().getSubject().getCode());
|
||||||
|
commonError.setErrorText(errorText);
|
||||||
|
|
||||||
|
if (ex instanceof SignalClientException) {
|
||||||
|
String packageName = ((SignalClientException) ex).getPackageName();
|
||||||
|
if(packageName != null ) {
|
||||||
|
log.warn("Response error: {}. PackageName: {}", errorText, packageName);
|
||||||
|
} else {
|
||||||
|
log.warn("Response error: {}", errorText);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(commonError, headers, HttpStatus.BAD_REQUEST);
|
||||||
|
} else {
|
||||||
|
Exception cause = ((SignalServerException) ex).getCause();
|
||||||
|
log.error(cause.getMessage(), cause);
|
||||||
|
return new ResponseEntity<>(commonError, headers, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommonError getCommonError(SignalException ex) {
|
private static CommonError getCommonError(SignalException ex) {
|
||||||
CommonError commonError;
|
CommonError commonError;
|
||||||
switch (ex.getErrorFormat()) {
|
switch (ex.getErrorFormat()) {
|
||||||
case MonitoringError -> commonError = new MonitoringError();
|
case MonitoringError -> commonError = new MonitoringError();
|
||||||
|
|
@ -84,10 +80,6 @@ public class GlobalExceptionHandler {
|
||||||
case MonitoringPackageDeleteError -> commonError = new MonitoringPackageDeleteError();
|
case MonitoringPackageDeleteError -> commonError = new MonitoringPackageDeleteError();
|
||||||
default -> throw new IllegalStateException("Unsupported error format: " + ex.getErrorFormat());
|
default -> throw new IllegalStateException("Unsupported error format: " + ex.getErrorFormat());
|
||||||
}
|
}
|
||||||
commonError.setStatus("error");
|
|
||||||
commonError.setErrorCode(ex.getErrorMessage().getSubject().getCode());
|
|
||||||
String errorText = messageResolver.resolve(ex.getErrorMessage());
|
|
||||||
commonError.setErrorText(errorText);
|
|
||||||
return commonError;
|
return commonError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,8 @@ public class CreditTrackerSettings {
|
||||||
private Long maxXmlFileSize;
|
private Long maxXmlFileSize;
|
||||||
private String loadDir;
|
private String loadDir;
|
||||||
private Long monitoringInterval;
|
private Long monitoringInterval;
|
||||||
private Long updateFlagsInterval;
|
private String updateFlagsCronExpression;
|
||||||
private Long daysToUpdateFlags;
|
private Long daysToUpdateFlags;
|
||||||
|
|
||||||
private String encoding;
|
private String encoding;
|
||||||
|
|
||||||
private Integer batchSize;
|
|
||||||
private Integer timeout;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.config.task;
|
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.PartFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.FlagsService2;
|
|
||||||
import ru.nbch.credit_tracker.service.task.impl.FlagsEnricher;
|
|
||||||
import ru.nbch.credit_tracker.service.task.impl.KickPipeLineImpl;
|
|
||||||
import ru.nbch.credit_tracker.service.task.impl.XmlMergeCoordinator;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineStarter;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
|
|
||||||
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class PipelineStarterConfig {
|
|
||||||
@Bean
|
|
||||||
public BiFunction<Long, String, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory(StaxXmlProcessor xml, CreditTrackerSettings creditTrackerSettings) {
|
|
||||||
return (packageId, packageName) -> new KickPipeLineImpl(xml, packageId, packageName, creditTrackerSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory(CreditTrackerSettings creditTrackerSettings) {
|
|
||||||
return () -> new XmlMergeCoordinator(creditTrackerSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Supplier<FlagsEnricher> flagEnricherFactory(FlagsService2 flagsService, PhoneFidMapMapper mapper) {
|
|
||||||
return () -> new FlagsEnricher(flagsService, mapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.config.task;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.PartFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class StageConfig {
|
|
||||||
|
|
||||||
@Bean("saveSubjectQueueFactory")
|
|
||||||
public StageQueueFactory<SubjectPayload> saveSubjectQueueFactory() {
|
|
||||||
return new StageQueueFactory<>(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean("idEnricherQueueFactory")
|
|
||||||
public StageQueueFactory<SubjectPayload> idEnricherQueueFactory() {
|
|
||||||
return new StageQueueFactory<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean("partFileQueueFactory")
|
|
||||||
public StageQueueFactory<PartFilePayload> partFileQueueFactory() {
|
|
||||||
return new StageQueueFactory<>(10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.config.task;
|
|
||||||
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
|
|
||||||
public class StageQueueFactory<T extends StagePayload> implements FactoryBean<BlockingQueue<T>> {
|
|
||||||
|
|
||||||
private final int capacity;
|
|
||||||
public StageQueueFactory(int capacity) {
|
|
||||||
this.capacity = capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StageQueueFactory() {
|
|
||||||
this(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockingQueue<T> getObject() throws Exception {
|
|
||||||
return new LinkedBlockingQueue<>(capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getObjectType() {
|
|
||||||
return BlockingQueue.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSingleton() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,14 +3,8 @@ package ru.nbch.credit_tracker.controller;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import ru.nbch.credit_tracker.config.mdc.ClearMdc;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest;
|
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest;
|
||||||
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest;
|
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest;
|
||||||
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse;
|
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse;
|
||||||
|
|
@ -18,70 +12,47 @@ import ru.nbch.credit_tracker.entities.user_response.all_packages.MonitoringAllP
|
||||||
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringPackageDeleteResponse;
|
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringPackageDeleteResponse;
|
||||||
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringReportListResponse;
|
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringReportListResponse;
|
||||||
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
|
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
|
||||||
import ru.nbch.credit_tracker.enums.SignalError;
|
import ru.nbch.credit_tracker.facade.SignalFacade;
|
||||||
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
|
|
||||||
import ru.nbch.credit_tracker.exceptions.SignalException;
|
|
||||||
import ru.nbch.credit_tracker.facade.SignalFacadeV3;
|
|
||||||
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/signal")
|
@RequestMapping("/api/v1/signal")
|
||||||
public class SignalControllerV3 {
|
public class SignalController {
|
||||||
|
|
||||||
private final SignalFacadeV3 signalFacadeV3;
|
private final SignalFacade signalFacade;
|
||||||
|
|
||||||
public SignalControllerV3(SignalFacadeV3 signalFacadeV3) {
|
public SignalController(SignalFacade signalFacade) {
|
||||||
this.signalFacadeV3 = signalFacadeV3;
|
this.signalFacade = signalFacade;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE)
|
@PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
@ClearMdc
|
|
||||||
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(@RequestParam("file") MultipartFile file) {
|
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(@RequestParam("file") MultipartFile file) {
|
||||||
signalFacadeV3.setupMonitoringRequest(file);
|
return signalFacade.setupMonitoring(file);
|
||||||
return ResponseEntity.ok().body(new MonitoringSetupResponse());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/active_packages", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
|
@PostMapping(value = "/active_packages", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(@RequestBody MonitoringActivePackagesRequest activePackagesRequest) {
|
public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(@RequestBody MonitoringActivePackagesRequest activePackagesRequest) {
|
||||||
try {
|
return signalFacade.findActivePackages(activePackagesRequest);
|
||||||
return signalFacadeV3.findActivePackages(activePackagesRequest);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throwOrWrap(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/all_packages", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
|
@PostMapping(value = "/all_packages", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
public ResponseEntity<MonitoringAllPackagesResponse> findAllPackages(@RequestBody MonitoringAllPackagesRequest allPackagesRequest) {
|
public ResponseEntity<MonitoringAllPackagesResponse> findAllPackages(@RequestBody MonitoringAllPackagesRequest allPackagesRequest) {
|
||||||
try {
|
return signalFacade.findAllPackages(allPackagesRequest);
|
||||||
return signalFacadeV3.findAllPackages(allPackagesRequest);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throwOrWrap(SignalError.ERROR_013, XmlErrorFormat.MonitoringAllPackagesError, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@PostMapping(value = "/delete", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE)
|
@PostMapping(value = "/delete", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
public ResponseEntity<MonitoringPackageDeleteResponse> deletePackage(@RequestParam("username") String username, @RequestParam("packageName") String packageName) {
|
public ResponseEntity<MonitoringPackageDeleteResponse> deletePackage(@RequestParam("username") String username, @RequestParam("packageName") String packageName) {
|
||||||
return signalFacadeV3.deletePackage(username, packageName);
|
return signalFacade.deletePackage(username, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/report_list", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE)
|
@GetMapping(value = "/report_list", params = {"username", "packageName"}, produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
public ResponseEntity<MonitoringReportListResponse> getReportList(@RequestParam("username") String username, @RequestParam("packageName") String packageName) {
|
public ResponseEntity<MonitoringReportListResponse> getReportList(@RequestParam("username") String username, @RequestParam("packageName") String packageName) {
|
||||||
return signalFacadeV3.getReportList(username, packageName);
|
return signalFacade.getReportList(username, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/download", params = "file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
@GetMapping(value = "/download", params = "file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||||
public ResponseEntity<Resource> downloadFile(@RequestParam("file") String file) {
|
public ResponseEntity<Resource> downloadFile(@RequestParam("file") String file) {
|
||||||
return signalFacadeV3.downloadFile(file);
|
return signalFacade.downloadFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void throwOrWrap(SignalError error, XmlErrorFormat specific, Exception ex) {
|
|
||||||
if (ex instanceof SignalException) {
|
|
||||||
throw (SignalException) ex;
|
|
||||||
}
|
|
||||||
throw serverExcp(error, specific, ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.entities.app;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Builder
|
|
||||||
public class PhoneFidMap {
|
|
||||||
private Long id;
|
|
||||||
private Long packageId;
|
|
||||||
private UUID recUuid;
|
|
||||||
private String subjectId;
|
|
||||||
private String phone;
|
|
||||||
private Integer fid;
|
|
||||||
private Integer flagDebt5000;
|
|
||||||
private Integer flag90days;
|
|
||||||
private LocalDateTime calculatedAt;
|
|
||||||
private String errorText;
|
|
||||||
|
|
||||||
// NAME data
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
private String middleName;
|
|
||||||
private LocalDate birthDate;
|
|
||||||
private LocalDate fileSinceDate;
|
|
||||||
//ID data
|
|
||||||
private String serNum;
|
|
||||||
private String idNum;
|
|
||||||
private LocalDate issDate;
|
|
||||||
private String idType;
|
|
||||||
private String idType2;
|
|
||||||
private LocalDate IdfileSinceDate;
|
|
||||||
|
|
||||||
boolean isFullFilled = false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package ru.nbch.credit_tracker.entities.app;
|
package ru.nbch.credit_tracker.entities.dto;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package ru.nbch.credit_tracker.entities.dto;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class PhoneFidMap {
|
||||||
|
private Long id;
|
||||||
|
private Long packageId;
|
||||||
|
private String subjectId;
|
||||||
|
private String phone;
|
||||||
|
private Integer fid;
|
||||||
|
private Integer flagDebt5000;
|
||||||
|
private Integer flag90days;
|
||||||
|
private LocalDateTime calculatedAt;
|
||||||
|
private String errorText;
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package ru.nbch.credit_tracker.entities.app;
|
package ru.nbch.credit_tracker.entities.dto;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.entities.indic;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@Builder
|
|
||||||
public class Name {
|
|
||||||
private Integer fid;
|
|
||||||
private String number;
|
|
||||||
private LocalDate fileSinceDate;
|
|
||||||
private String first;
|
|
||||||
private String last;
|
|
||||||
private String middle;
|
|
||||||
private LocalDate birthDate;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.entities.indic;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class PaymentsFlag {
|
|
||||||
private Integer fid;
|
|
||||||
private Integer flag;
|
|
||||||
}
|
|
||||||
|
|
@ -4,5 +4,4 @@ public interface CommonError {
|
||||||
void setStatus(String status);
|
void setStatus(String status);
|
||||||
void setErrorCode(String errorCode);
|
void setErrorCode(String errorCode);
|
||||||
void setErrorText(String errorText);
|
void setErrorText(String errorText);
|
||||||
String getErrorText();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
436
src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java
Normal file
436
src/main/java/ru/nbch/credit_tracker/facade/SignalFacade.java
Normal file
|
|
@ -0,0 +1,436 @@
|
||||||
|
package ru.nbch.credit_tracker.facade;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
import org.springframework.aop.framework.AopContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
import org.springframework.core.io.FileUrlResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
|
||||||
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.active_packages.Package;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.active_packages.Packages;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.all_packages.MonitoringAllPackagesResponse;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.all_packages.PackageAll;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.all_packages.PackagesAll;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringPackageDeleteResponse;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringReportListResponse;
|
||||||
|
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
|
||||||
|
import ru.nbch.credit_tracker.enums.SignalError;
|
||||||
|
import ru.nbch.credit_tracker.enums.Status;
|
||||||
|
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
|
||||||
|
import ru.nbch.credit_tracker.exceptions.SignalClientException;
|
||||||
|
import ru.nbch.credit_tracker.service.MonitoringErrorProcesingService;
|
||||||
|
import ru.nbch.credit_tracker.service.SignalService;
|
||||||
|
import ru.nbch.credit_tracker.service.scoring.AuthorizationService;
|
||||||
|
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
||||||
|
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
|
||||||
|
import ru.nbch.credit_tracker.utils.CTUtil;
|
||||||
|
import ru.nbch.credit_tracker.utils.ValidationService;
|
||||||
|
import ru.nbch.credit_tracker.utils.ZipUtils;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
|
||||||
|
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||||
|
public class SignalFacade {
|
||||||
|
|
||||||
|
private SignalFacade self;
|
||||||
|
|
||||||
|
private final CreditTrackerSettings config;
|
||||||
|
private final AuthorizationService authorizationService;
|
||||||
|
private final SignalService signalService;
|
||||||
|
private final SignalRestService signalRestService;
|
||||||
|
private final MonitoringErrorProcesingService monitoringErrorProcesingService;
|
||||||
|
private final ValidationService validationService;
|
||||||
|
private final StaxXmlProcessor staxXmlProcessor;
|
||||||
|
|
||||||
|
private final ExecutorService executor;
|
||||||
|
private final long maxXmlFileSize;
|
||||||
|
|
||||||
|
|
||||||
|
public SignalFacade(CreditTrackerSettings config,
|
||||||
|
AuthorizationService authorizationService,
|
||||||
|
SignalService signalService,
|
||||||
|
SignalRestService signalRestService,
|
||||||
|
MonitoringErrorProcesingService monitoringErrorProcesingService,
|
||||||
|
ValidationService validationService,
|
||||||
|
StaxXmlProcessor staxXmlProcessor,
|
||||||
|
@Qualifier("executorService") ExecutorService executor) {
|
||||||
|
this.config = config;
|
||||||
|
this.authorizationService = authorizationService;
|
||||||
|
this.signalService = signalService;
|
||||||
|
this.signalRestService = signalRestService;
|
||||||
|
this.monitoringErrorProcesingService = monitoringErrorProcesingService;
|
||||||
|
this.validationService = validationService;
|
||||||
|
this.staxXmlProcessor = staxXmlProcessor;
|
||||||
|
this.executor = executor;
|
||||||
|
this.maxXmlFileSize = config.getMaxXmlFileSize() * 1024 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(MultipartFile file) {
|
||||||
|
// первичные валидации
|
||||||
|
if (file.isEmpty() || !isZipFile(file)) {
|
||||||
|
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Валидация Архива на количетсво файлов, размер и расширение
|
||||||
|
MonitoringRequest monitoringRequest;
|
||||||
|
Long packageId;
|
||||||
|
ZipInputStream zipInputStream = null;
|
||||||
|
String filePath;
|
||||||
|
try {
|
||||||
|
zipInputStream = new ZipInputStream(file.getInputStream());
|
||||||
|
Optional<ZipEntry> xmlFileEntry = ZipUtils.extractValidEntry(zipInputStream);
|
||||||
|
if (xmlFileEntry.isEmpty()) {
|
||||||
|
throw clientExcp(SignalError.ERROR_001, XmlErrorFormat.MonitoringError);
|
||||||
|
}
|
||||||
|
if (xmlFileEntry.get().getSize() > maxXmlFileSize) {
|
||||||
|
throw clientExcp(SignalError.ERROR_009, XmlErrorFormat.MonitoringError);
|
||||||
|
}
|
||||||
|
|
||||||
|
zipInputStream.close();
|
||||||
|
zipInputStream = new ZipInputStream(file.getInputStream());
|
||||||
|
zipInputStream.getNextEntry();
|
||||||
|
|
||||||
|
filePath = writeTmpFile(zipInputStream);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
||||||
|
} finally {
|
||||||
|
if (zipInputStream != null) {
|
||||||
|
try {
|
||||||
|
zipInputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// валидация xml
|
||||||
|
try {
|
||||||
|
monitoringRequest = readAndValidateMonitoringRequest(filePath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
CTUtil.removeFile(filePath);
|
||||||
|
if (e.getCause() instanceof XMLStreamException) {
|
||||||
|
throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError);
|
||||||
|
}
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// проверка авторизации
|
||||||
|
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(monitoringRequest.getUserId(), monitoringRequest.getPassword());
|
||||||
|
if (!authResult.isSuccess()) {
|
||||||
|
signalService.rejectPackage(monitoringRequest);
|
||||||
|
throw clientExcp(authResult.getError(), monitoringRequest.getPackageName(), XmlErrorFormat.MonitoringError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// проверка на уникальность пакета
|
||||||
|
if (signalService.isPackageNotUnique(monitoringRequest)) {
|
||||||
|
signalService.rejectPackage(monitoringRequest);
|
||||||
|
throw clientExcp(SignalError.ERROR_007, monitoringRequest.getPackageName(), XmlErrorFormat.MonitoringError);
|
||||||
|
}
|
||||||
|
|
||||||
|
packageId = signalService.registerPackage(monitoringRequest);
|
||||||
|
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
|
||||||
|
} catch (Exception e) {
|
||||||
|
CTUtil.removeFile(filePath);
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// в отдельном потоке запускаем регистрацию субъектов, поиск фидов и расчет флагов просрочек
|
||||||
|
getCurrentProxy().registerFidsAndDebts(packageId, monitoringRequest.getPackageName(), filePath);
|
||||||
|
|
||||||
|
return ResponseEntity.ok().body(new MonitoringSetupResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
private MonitoringRequest readAndValidateMonitoringRequest(String filePath) {
|
||||||
|
MonitoringRequest monitoringRequest;
|
||||||
|
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
|
||||||
|
monitoringRequest = staxXmlProcessor.read(in, MonitoringRequest.class,
|
||||||
|
request -> {
|
||||||
|
try {
|
||||||
|
validationService.validateMonitoringRequest(request);
|
||||||
|
} catch (SignalClientException e) {
|
||||||
|
if (request != null) {
|
||||||
|
signalService.rejectPackage(request);
|
||||||
|
}
|
||||||
|
request = null;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
request.getSubjects().getSubject().clear();
|
||||||
|
},
|
||||||
|
request -> request.getSubjects().getSubject().isEmpty()
|
||||||
|
,
|
||||||
|
40000, "/MonitoringRequest/Subjects/Subject");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Error while parsing and validating monitoring request", e);
|
||||||
|
}
|
||||||
|
return monitoringRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String writeTmpFile(ZipInputStream zipInputStream) throws IOException {
|
||||||
|
String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator;
|
||||||
|
String filePath = folderPath + UUID.randomUUID() + "monitoring_request.xml";
|
||||||
|
CTUtil.createFolder(folderPath);
|
||||||
|
|
||||||
|
try (OutputStream out = Files.newOutputStream(Path.of(filePath))) {
|
||||||
|
|
||||||
|
byte[] buffer = new byte[8 * 1024 * 1024];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = zipInputStream.read(buffer)) > 0) {
|
||||||
|
out.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SetAndClearMdc(argIndex = 1)
|
||||||
|
public void registerFidsAndDebts(Long packageId, String packageName, String filePath) {
|
||||||
|
Map<String, String> context = MDC.getCopyOfContextMap();
|
||||||
|
executor.execute(() -> {
|
||||||
|
if (context != null) {
|
||||||
|
MDC.setContextMap(context);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
signalService.registerSubjects(filePath, packageId);
|
||||||
|
CTUtil.removeFile(filePath);
|
||||||
|
SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, null);
|
||||||
|
if (updateResult.isNoFidsFound()) {
|
||||||
|
log.info("No fids found for PackageId: {} PackageName: {}. Package status ON_MONITORING. No registration in signal service.", packageId, packageName);
|
||||||
|
signalService.updatePackageStatus(packageId, Status.ON_MONITORING);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (signalRestService.setupMonitoring(packageId)) {
|
||||||
|
LocalDateTime monitoringAt = LocalDateTime.now();
|
||||||
|
log.info("Package was successfully registered in signal service. PackageId: {} PackageName: {}, MonitoringAt: {}", packageId, packageName, monitoringAt);
|
||||||
|
signalService.updatePackageOnMonitoringSuccess(packageId, monitoringAt);
|
||||||
|
monitoringErrorProcesingService.findErrors(packageId);
|
||||||
|
} else {
|
||||||
|
log.info("Package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName);
|
||||||
|
signalService.updatePackageStatus(packageId, Status.ERROR);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CTUtil.removeFile(filePath);
|
||||||
|
signalService.updatePackageStatus(packageId, Status.ERROR);
|
||||||
|
log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isZipFile(MultipartFile file) {
|
||||||
|
return file.getContentType() != null &&
|
||||||
|
(file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) ||
|
||||||
|
file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(MonitoringActivePackagesRequest activePackagesRequest) {
|
||||||
|
try {
|
||||||
|
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(activePackagesRequest.getUserId(), activePackagesRequest.getPassword());
|
||||||
|
if (!authResult.isSuccess()) {
|
||||||
|
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringActivePackagesError);
|
||||||
|
}
|
||||||
|
List<UserPackage> activePackages = signalService.findActivePackages(activePackagesRequest.getUserId());
|
||||||
|
|
||||||
|
if (!activePackages.isEmpty()) {
|
||||||
|
MonitoringActivePackagesResponse response = new MonitoringActivePackagesResponse();
|
||||||
|
response.setStatus("OK");
|
||||||
|
response.setMembercode(activePackagesRequest.getUserId().substring(0, 6));
|
||||||
|
Packages packages = new Packages();
|
||||||
|
activePackages.forEach(data -> {
|
||||||
|
Package pack = new Package();
|
||||||
|
pack.setPackageName(data.getPackageName());
|
||||||
|
pack.setCreatedAt(data.getCreatedAt() != null ? data.getCreatedAt().toString() : null);
|
||||||
|
packages.getPackages().add(pack);
|
||||||
|
});
|
||||||
|
response.setPackages(packages);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} else {
|
||||||
|
throw clientExcp(SignalError.ERROR_015, XmlErrorFormat.MonitoringActivePackagesError);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringActivePackagesError, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity<MonitoringAllPackagesResponse> findAllPackages(MonitoringAllPackagesRequest allPackagesRequest) {
|
||||||
|
try {
|
||||||
|
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(allPackagesRequest.getUserId(), allPackagesRequest.getPassword());
|
||||||
|
if (!authResult.isSuccess()) {
|
||||||
|
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringAllPackagesError);
|
||||||
|
}
|
||||||
|
List<UserPackage> activePackages = signalService.findAllPackages(allPackagesRequest.getUserId());
|
||||||
|
|
||||||
|
if (!activePackages.isEmpty()) {
|
||||||
|
MonitoringAllPackagesResponse response = new MonitoringAllPackagesResponse();
|
||||||
|
response.setStatus("OK");
|
||||||
|
response.setMembercode(allPackagesRequest.getUserId().substring(0, 6));
|
||||||
|
PackagesAll packages = new PackagesAll();
|
||||||
|
activePackages.forEach(data -> {
|
||||||
|
PackageAll pack = new PackageAll();
|
||||||
|
pack.setPackageName(data.getPackageName());
|
||||||
|
pack.setCreatedAt(data.getCreatedAt() != null ? data.getCreatedAt().toString() : null);
|
||||||
|
pack.setStatus(data.getStatus());
|
||||||
|
if (data.getStatus().equals(Status.DELETED.name())) {
|
||||||
|
pack.setDeactivatedAt(data.getDeactivatedAt() != null ? data.getDeactivatedAt().toString() : null);
|
||||||
|
}
|
||||||
|
packages.getPackages().add(pack);
|
||||||
|
});
|
||||||
|
response.setPackages(packages);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} else {
|
||||||
|
throw clientExcp(SignalError.ERROR_019, XmlErrorFormat.MonitoringAllPackagesError);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringAllPackagesError, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity<MonitoringPackageDeleteResponse> deletePackage(String username, String packageName) {
|
||||||
|
try {
|
||||||
|
if (!signalService.isPackageExists(username, packageName)) {
|
||||||
|
throw clientExcp(SignalError.ERROR_016, XmlErrorFormat.MonitoringPackageDeleteError, packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDateTime deactivatedAt = LocalDateTime.now();
|
||||||
|
signalService.deletePackage(username, packageName, deactivatedAt);
|
||||||
|
|
||||||
|
MonitoringPackageDeleteResponse response = new MonitoringPackageDeleteResponse();
|
||||||
|
response.setStatus("Deleted");
|
||||||
|
response.setPackageName(packageName);
|
||||||
|
response.setDeactivatedAt(deactivatedAt.toString());
|
||||||
|
|
||||||
|
signalRestService.deletePackage(username, packageName);
|
||||||
|
log.info("Package {} deleted", packageName);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity<MonitoringReportListResponse> getReportList(String username, String packageName) {
|
||||||
|
try {
|
||||||
|
if (signalService.isPackagesByStatusExist(username, packageName, Status.PROCESSING)) {
|
||||||
|
throw clientExcp(SignalError.ERROR_018, XmlErrorFormat.MonitoringReportListError, packageName);
|
||||||
|
}
|
||||||
|
if (signalService.isPackagesByStatusExist(username, packageName, Status.REJECTED)) {
|
||||||
|
throw clientExcp(SignalError.ERROR_020, XmlErrorFormat.MonitoringReportListError, packageName);
|
||||||
|
}
|
||||||
|
if (signalService.isPackagesByStatusExist(username, packageName, Status.ERROR)) {
|
||||||
|
throw clientExcp(SignalError.ERROR_021, XmlErrorFormat.MonitoringReportListError, packageName);
|
||||||
|
}
|
||||||
|
if (signalService.isPackagesByStatusExist(username, packageName, Status.DELETED)) {
|
||||||
|
throw clientExcp(SignalError.ERROR_022, XmlErrorFormat.MonitoringReportListError, packageName);
|
||||||
|
}
|
||||||
|
if (!signalService.isPackagesByStatusExist(username, packageName, Status.ON_MONITORING)) {
|
||||||
|
throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
String memberCode = username.substring(0, 6);
|
||||||
|
String filePrefix = (memberCode + "_" + packageName).toUpperCase();
|
||||||
|
String dirPath = config.getLoadDir() + File.separator + memberCode;
|
||||||
|
File folder = new File(dirPath);
|
||||||
|
|
||||||
|
MonitoringReportListResponse.Reports reports = new MonitoringReportListResponse.Reports();
|
||||||
|
if (folder.exists() && folder.isDirectory()) {
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isFile() && file.getName().startsWith(filePrefix)) {
|
||||||
|
reports.getReports().add(file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MonitoringReportListResponse response = new MonitoringReportListResponse();
|
||||||
|
response.setPackageName(packageName);
|
||||||
|
response.setReports(reports);
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity<Resource> downloadFile(String fileName) {
|
||||||
|
try {
|
||||||
|
String memberCode = CTUtil.getMemberCodeFromFileName(fileName);
|
||||||
|
if (memberCode == null) {
|
||||||
|
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
|
||||||
|
}
|
||||||
|
String dirPath = config.getLoadDir() + File.separator + memberCode;
|
||||||
|
File folder = new File(dirPath);
|
||||||
|
|
||||||
|
if (folder.exists() && folder.isDirectory()) {
|
||||||
|
File file = new File(dirPath + File.separator + fileName);
|
||||||
|
if (file.exists() && file.isFile()) {
|
||||||
|
return ResponseEntity.ok().body(new FileUrlResource(file.getPath()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
|
||||||
|
}
|
||||||
|
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof SignalClientException) {
|
||||||
|
throw (SignalClientException) e;
|
||||||
|
}
|
||||||
|
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SignalFacade getCurrentProxy() {
|
||||||
|
if (self == null) {
|
||||||
|
self = (SignalFacade) AopContext.currentProxy();
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,280 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.facade;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.springframework.core.io.FileUrlResource;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import ru.nbch.credit_tracker.component.MonitoringRequestValidator;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.active_packages.Package;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.active_packages.Packages;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.all_packages.MonitoringAllPackagesResponse;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.all_packages.PackageAll;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.all_packages.PackagesAll;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringPackageDeleteResponse;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringReportListResponse;
|
|
||||||
import ru.nbch.credit_tracker.enums.SignalError;
|
|
||||||
import ru.nbch.credit_tracker.enums.Status;
|
|
||||||
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
|
|
||||||
import ru.nbch.credit_tracker.exceptions.SignalClientException;
|
|
||||||
import ru.nbch.credit_tracker.model.MonitoringValidationError;
|
|
||||||
import ru.nbch.credit_tracker.model.ValidationResult;
|
|
||||||
import ru.nbch.credit_tracker.service.SignalServiceV2;
|
|
||||||
import ru.nbch.credit_tracker.service.scoring.AuthorizationService;
|
|
||||||
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
|
||||||
import ru.nbch.credit_tracker.service.task.PipelinePackageManager;
|
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
|
||||||
import ru.nbch.credit_tracker.utils.LogUtil;
|
|
||||||
import ru.nbch.credit_tracker.utils.ZipUtils;
|
|
||||||
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
|
|
||||||
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
public class SignalFacadeV3 {
|
|
||||||
|
|
||||||
private final MonitoringRequestValidator monitoringRequestValidator;
|
|
||||||
private final CreditTrackerSettings config;
|
|
||||||
private final SignalServiceV2 signalService;
|
|
||||||
private final AuthorizationService authorizationService;
|
|
||||||
private final PipelinePackageManager pipelinePackageManager;
|
|
||||||
private final SignalRestService signalRestService;
|
|
||||||
public SignalFacadeV3(MonitoringRequestValidator monitoringRequestValidator,
|
|
||||||
CreditTrackerSettings config,
|
|
||||||
SignalServiceV2 signalService,
|
|
||||||
AuthorizationService authorizationService,
|
|
||||||
PipelinePackageManager pipelinePackageManager,
|
|
||||||
SignalRestService signalRestService) {
|
|
||||||
this.monitoringRequestValidator = monitoringRequestValidator;
|
|
||||||
this.config = config;
|
|
||||||
this.signalService = signalService;
|
|
||||||
this.authorizationService = authorizationService;
|
|
||||||
this.pipelinePackageManager = pipelinePackageManager;
|
|
||||||
this.signalRestService = signalRestService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setupMonitoringRequest(MultipartFile file) {
|
|
||||||
log.debug("Start processing monitoring request");
|
|
||||||
monitoringRequestValidator.validateZipContent(file);
|
|
||||||
|
|
||||||
log.trace("Saving monitoring request to tmp file...");
|
|
||||||
String filePath;
|
|
||||||
try {
|
|
||||||
String folderPath = config.getLoadDir() + File.separator + "tmp_folder" + File.separator;
|
|
||||||
filePath = ZipUtils.writeTmpFile(folderPath, file);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("File saved to {}", filePath);
|
|
||||||
ValidationResult validationResult = null;
|
|
||||||
try {
|
|
||||||
validationResult = monitoringRequestValidator.readAndValidateMonitoringRequest(filePath);
|
|
||||||
if (!validationResult.getValidationErrors().isEmpty()) {
|
|
||||||
MonitoringValidationError firstError = validationResult.getValidationErrors().get(0);
|
|
||||||
signalService.rejectPackage(validationResult.getUserId(), validationResult.getPackageName());
|
|
||||||
FileUtils.delete(new File(filePath));
|
|
||||||
throw firstError.getSignalException();
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
if (e.getCause() instanceof XMLStreamException) {
|
|
||||||
throw clientExcp(SignalError.ERROR_011, XmlErrorFormat.MonitoringError);
|
|
||||||
}
|
|
||||||
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.warn("Error deleting tmp file", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
String packageName = validationResult.getPackageName();
|
|
||||||
String userId = validationResult.getUserId();
|
|
||||||
String password = validationResult.getPassword();
|
|
||||||
try {
|
|
||||||
// проверка авторизации
|
|
||||||
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(userId, password);
|
|
||||||
if (!authResult.isSuccess()) {
|
|
||||||
signalService.rejectPackage(userId, packageName);
|
|
||||||
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// проверка на уникальность пакета
|
|
||||||
// if (signalService.isPackageNotUnique(userId, packageName)) {
|
|
||||||
// signalService.rejectPackage(userId, packageName);
|
|
||||||
// throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError);
|
|
||||||
// }
|
|
||||||
|
|
||||||
Long packageId = signalService.registerPackage(userId, packageName);
|
|
||||||
LogUtil.addMdcLogKey("%s %d".formatted(packageName, packageId));
|
|
||||||
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
|
|
||||||
pipelinePackageManager.buildAndRun(packageId, filePath);
|
|
||||||
} catch (Exception e) {
|
|
||||||
CTUtil.removeFile(filePath);
|
|
||||||
if (e instanceof SignalClientException) {
|
|
||||||
throw (SignalClientException) e;
|
|
||||||
}
|
|
||||||
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringError, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(MonitoringActivePackagesRequest activePackagesRequest) throws Exception {
|
|
||||||
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(activePackagesRequest.getUserId(), activePackagesRequest.getPassword());
|
|
||||||
if (!authResult.isSuccess()) {
|
|
||||||
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringActivePackagesError);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserPackage> activePackages = signalService.findActivePackages(activePackagesRequest.getUserId());
|
|
||||||
if (activePackages.isEmpty()) {
|
|
||||||
throw clientExcp(SignalError.ERROR_015, XmlErrorFormat.MonitoringActivePackagesError);
|
|
||||||
}
|
|
||||||
|
|
||||||
MonitoringActivePackagesResponse response = new MonitoringActivePackagesResponse();
|
|
||||||
response.setStatus("OK");
|
|
||||||
response.setMembercode(activePackagesRequest.getUserId().substring(0, 6));
|
|
||||||
Packages packages = new Packages();
|
|
||||||
activePackages.forEach(data -> {
|
|
||||||
Package pack = new Package();
|
|
||||||
pack.setPackageName(data.getPackageName());
|
|
||||||
pack.setCreatedAt(data.getCreatedAt() != null ? data.getCreatedAt().toString() : null);
|
|
||||||
packages.getPackages().add(pack);
|
|
||||||
});
|
|
||||||
response.setPackages(packages);
|
|
||||||
return ResponseEntity.ok(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<MonitoringAllPackagesResponse> findAllPackages(MonitoringAllPackagesRequest allPackagesRequest) throws Exception {
|
|
||||||
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(allPackagesRequest.getUserId(), allPackagesRequest.getPassword());
|
|
||||||
if (!authResult.isSuccess()) {
|
|
||||||
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringAllPackagesError);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserPackage> activePackages = signalService.findAllPackages(allPackagesRequest.getUserId());
|
|
||||||
if (activePackages.isEmpty()) {
|
|
||||||
throw clientExcp(SignalError.ERROR_019, XmlErrorFormat.MonitoringAllPackagesError);
|
|
||||||
}
|
|
||||||
|
|
||||||
MonitoringAllPackagesResponse response = new MonitoringAllPackagesResponse();
|
|
||||||
response.setStatus("OK");
|
|
||||||
response.setMembercode(allPackagesRequest.getUserId().substring(0, 6));
|
|
||||||
PackagesAll packages = new PackagesAll();
|
|
||||||
activePackages.forEach(data -> {
|
|
||||||
PackageAll pack = new PackageAll();
|
|
||||||
pack.setPackageName(data.getPackageName());
|
|
||||||
pack.setCreatedAt(data.getCreatedAt() != null ? data.getCreatedAt().toString() : null);
|
|
||||||
pack.setStatus(data.getStatus());
|
|
||||||
if (data.getStatus().equals(Status.DELETED.name())) {
|
|
||||||
pack.setDeactivatedAt(data.getDeactivatedAt() != null ? data.getDeactivatedAt().toString() : null);
|
|
||||||
}
|
|
||||||
packages.getPackages().add(pack);
|
|
||||||
});
|
|
||||||
response.setPackages(packages);
|
|
||||||
return ResponseEntity.ok(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<MonitoringPackageDeleteResponse> deletePackage(String username, String packageName) {
|
|
||||||
try {
|
|
||||||
if (!signalService.isPackageExists(username, packageName)) {
|
|
||||||
throw clientExcp(SignalError.ERROR_016, XmlErrorFormat.MonitoringPackageDeleteError, packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalDateTime deactivatedAt = LocalDateTime.now();
|
|
||||||
signalService.deletePackage(username, packageName, deactivatedAt);
|
|
||||||
|
|
||||||
MonitoringPackageDeleteResponse response = new MonitoringPackageDeleteResponse();
|
|
||||||
response.setStatus("Deleted");
|
|
||||||
response.setPackageName(packageName);
|
|
||||||
response.setDeactivatedAt(deactivatedAt.toString());
|
|
||||||
|
|
||||||
signalRestService.deletePackage(username, packageName);
|
|
||||||
log.info("Package {} deleted", packageName);
|
|
||||||
return ResponseEntity.ok(response);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e instanceof SignalClientException) {
|
|
||||||
throw (SignalClientException) e;
|
|
||||||
}
|
|
||||||
throw serverExcp(SignalError.ERROR_017, XmlErrorFormat.MonitoringPackageDeleteError, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<MonitoringReportListResponse> getReportList(String username, String packageName) {
|
|
||||||
try {
|
|
||||||
if (signalService.isPackagesByStatusExist(username, packageName, Status.PROCESSING)) {
|
|
||||||
throw clientExcp(SignalError.ERROR_018, XmlErrorFormat.MonitoringReportListError, packageName);
|
|
||||||
}
|
|
||||||
if (signalService.isPackagesByStatusExist(username, packageName, Status.REJECTED)) {
|
|
||||||
throw clientExcp(SignalError.ERROR_020, XmlErrorFormat.MonitoringReportListError, packageName);
|
|
||||||
}
|
|
||||||
if (signalService.isPackagesByStatusExist(username, packageName, Status.ERROR)) {
|
|
||||||
throw clientExcp(SignalError.ERROR_021, XmlErrorFormat.MonitoringReportListError, packageName);
|
|
||||||
}
|
|
||||||
if (signalService.isPackagesByStatusExist(username, packageName, Status.DELETED)) {
|
|
||||||
throw clientExcp(SignalError.ERROR_022, XmlErrorFormat.MonitoringReportListError, packageName);
|
|
||||||
}
|
|
||||||
if (!signalService.isPackagesByStatusExist(username, packageName, Status.ON_MONITORING)) {
|
|
||||||
throw clientExcp(SignalError.ERROR_012, XmlErrorFormat.MonitoringReportListError, packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
String memberCode = username.substring(0, 6);
|
|
||||||
String filePrefix = (memberCode + "_" + packageName).toUpperCase();
|
|
||||||
String dirPath = config.getLoadDir() + File.separator + memberCode;
|
|
||||||
File folder = new File(dirPath);
|
|
||||||
|
|
||||||
MonitoringReportListResponse.Reports reports = new MonitoringReportListResponse.Reports();
|
|
||||||
if (folder.exists() && folder.isDirectory()) {
|
|
||||||
File[] files = folder.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File file : files) {
|
|
||||||
if (file.isFile() && file.getName().startsWith(filePrefix)) {
|
|
||||||
reports.getReports().add(file.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MonitoringReportListResponse response = new MonitoringReportListResponse();
|
|
||||||
response.setPackageName(packageName);
|
|
||||||
response.setReports(reports);
|
|
||||||
return ResponseEntity.ok(response);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e instanceof SignalClientException) {
|
|
||||||
throw (SignalClientException) e;
|
|
||||||
}
|
|
||||||
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringReportListError, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity<Resource> downloadFile(String fileName) {
|
|
||||||
try {
|
|
||||||
String memberCode = CTUtil.getMemberCodeFromFileName(fileName);
|
|
||||||
if (memberCode == null) {
|
|
||||||
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
|
|
||||||
}
|
|
||||||
String dirPath = config.getLoadDir() + File.separator + memberCode;
|
|
||||||
File folder = new File(dirPath);
|
|
||||||
|
|
||||||
if (folder.exists() && folder.isDirectory()) {
|
|
||||||
File file = new File(dirPath + File.separator + fileName);
|
|
||||||
if (file.exists() && file.isFile()) {
|
|
||||||
return ResponseEntity.ok().body(new FileUrlResource(file.getPath()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
|
|
||||||
}
|
|
||||||
throw clientExcp(SignalError.ERROR_014, XmlErrorFormat.MonitoringDownloadError, fileName);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e instanceof SignalClientException) {
|
|
||||||
throw (SignalClientException) e;
|
|
||||||
}
|
|
||||||
throw serverExcp(SignalError.ERROR_013, XmlErrorFormat.MonitoringDownloadError, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
package ru.nbch.credit_tracker.mapper.indic;
|
package ru.nbch.credit_tracker.mapper.indic;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import ru.nbch.credit_tracker.service.indic.FlagsService;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
import ru.nbch.credit_tracker.entities.indic.PaymentsFlag;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.FlagsService;
|
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface FlagsMapper {
|
public interface FlagsMapper {
|
||||||
List<FlagsService.RuPastDuarearData> findRuPastDuarearData(@Param("fids") List<Integer> fids);
|
|
||||||
|
|
||||||
List<FlagsService.RuPaymtData> findRuPaymtData(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate);
|
List<FlagsService.FlagFidData> findFlagsDebt5000(@Param("fids") List<Integer> fids);
|
||||||
|
|
||||||
List<PaymentsFlag> findFlagsDebt5000(@Param("fids") List<Integer> fids);
|
List<FlagsService.FlagFidData> findFlag90ByPastDueArrear(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate);
|
||||||
|
|
||||||
List<PaymentsFlag> findFlag90ByPastDueArrear(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate);
|
List<FlagsService.FlagFidData> findFlag90ByRuPaymt(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate);
|
||||||
|
|
||||||
List<PaymentsFlag> findFlag90ByRuPaymt(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.nbch.credit_tracker.mapper.indic;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import ru.nbch.credit_tracker.service.indic.PhoneService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface PhoneMapper {
|
||||||
|
List<PhoneService.FidsData> findFids(@Param("phones") List<String> phones);
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ package ru.nbch.credit_tracker.mapper.signal;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import ru.nbch.credit_tracker.entities.app.Hit;
|
import ru.nbch.credit_tracker.entities.dto.Hit;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,24 @@ package ru.nbch.credit_tracker.mapper.signal;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject;
|
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface PhoneFidMapMapper {
|
public interface PhoneFidMapMapper {
|
||||||
|
|
||||||
void registerSubjects(@Param("subjects") List<Subject> subjects, @Param("packageId") Long packageId);
|
void registerSubjects(@Param("subjects") List<Subject> subjects, @Param("packageId") Long packageId);
|
||||||
void register(@Param("phoneFidMap") List<PhoneFidMap> phoneFidMap);
|
|
||||||
void registerJson(@Param("json") String json);
|
|
||||||
void registerWithId(@Param("phoneFidMap") List<PhoneFidMap> phoneFidMap);
|
|
||||||
|
|
||||||
List<PhoneFidMap> findFullPhoneFidMap(@Param("packageId") Long packageId, @Param("offset") int offset, @Param("limit") int limit);
|
List<PhoneFidMap> findFullPhoneFidMap(@Param("packageId") Long packageId, @Param("offset") int offset, @Param("limit") int limit);
|
||||||
|
|
||||||
void updatePhoneFidMaps(@Param("subjects") Collection<PhoneFidMap> subjects);
|
void updatePhoneFidMaps(@Param("subjects") List<PhoneFidMap> subjects);
|
||||||
void updateOne(@Param("subject") PhoneFidMap subject);
|
|
||||||
void updateFid(@Param("subjects") Collection<PhoneFidMap> subjects);
|
|
||||||
|
|
||||||
void updatePhoneFidMapsErrors(@Param("subjects") List<PhoneFidMap> subjects);
|
void updatePhoneFidMapsErrors(@Param("subjects") List<PhoneFidMap> subjects);
|
||||||
|
|
||||||
PhoneFidMap findPhoneFidMapById(@Param("id") Long packageId);
|
PhoneFidMap findPhoneFidMapById(@Param("id") Long packageId);
|
||||||
|
|
||||||
boolean hasNonNullFids(@Param("packageId") Long packageId);
|
boolean hasNonNullFids(@Param("packageId") Long packageId);
|
||||||
|
boolean hasOldRow(@Param("packageId") Long packageId, @Param("daysCount") Integer daysCount);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package ru.nbch.credit_tracker.mapper.signal;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
public class DummyPayload implements StagePayload {
|
|
||||||
|
|
||||||
private final boolean poison;
|
|
||||||
public static DummyPayload POISON = new DummyPayload(true);
|
|
||||||
|
|
||||||
public DummyPayload(boolean poison) {
|
|
||||||
this.poison = poison;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPoison() {
|
|
||||||
return poison;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class FlagsPayload implements StagePayload {
|
|
||||||
private final Long packageId;
|
|
||||||
private final List<PhoneFidMap> phoneFidMaps;
|
|
||||||
private final boolean poison;
|
|
||||||
|
|
||||||
public FlagsPayload(Long packageId, List<PhoneFidMap> fidsMapByBatch) {
|
|
||||||
this.packageId = packageId;
|
|
||||||
this.phoneFidMaps = fidsMapByBatch;
|
|
||||||
this.poison = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlagsPayload(boolean poison) {
|
|
||||||
this.packageId = null;
|
|
||||||
this.phoneFidMaps = null;
|
|
||||||
this.poison = poison;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getPackageId() {
|
|
||||||
return packageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<PhoneFidMap> getPhoneFidMaps() {
|
|
||||||
return phoneFidMaps;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPoison() {
|
|
||||||
return poison;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@Builder
|
|
||||||
//todo подумать над неймингом класс
|
|
||||||
public class IdData {
|
|
||||||
private Integer fid;
|
|
||||||
private String serNum;
|
|
||||||
private String idNum;
|
|
||||||
private LocalDate issDate;
|
|
||||||
private String idType;
|
|
||||||
private String idType2;
|
|
||||||
private LocalDate fileSinceDate;
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
import ru.nbch.credit_tracker.exceptions.SignalException;
|
|
||||||
|
|
||||||
public class MonitoringValidationError {
|
|
||||||
private final int line;
|
|
||||||
private final String message;
|
|
||||||
private final SignalException signalException;
|
|
||||||
|
|
||||||
|
|
||||||
public MonitoringValidationError(int line,
|
|
||||||
String message,
|
|
||||||
SignalException signalException) {
|
|
||||||
this.line = line;
|
|
||||||
this.message = message;
|
|
||||||
this.signalException = signalException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLine() {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalException getSignalException() {
|
|
||||||
return signalException;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@Builder
|
|
||||||
//todo подумать над неймингом класс
|
|
||||||
public class NameData {
|
|
||||||
private Integer fid;
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
private String middleName;
|
|
||||||
private LocalDate birthDate;
|
|
||||||
private LocalDate fileSinceDate;
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
public class SendSignalsPayload implements StagePayload {
|
|
||||||
private String signalXmlPath;
|
|
||||||
public static final SendSignalsPayload POISON = new SendSignalsPayload(true);
|
|
||||||
private boolean poison;
|
|
||||||
|
|
||||||
public SendSignalsPayload(boolean poison) {
|
|
||||||
this.poison = poison;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPoison() {
|
|
||||||
return poison;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
public interface StagePayload {
|
|
||||||
boolean isPoison();
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@Builder
|
|
||||||
public class SubjectProfile {
|
|
||||||
private String identifier;
|
|
||||||
private String phone;
|
|
||||||
private Integer fid;
|
|
||||||
private NameData nameData;
|
|
||||||
private IdData idData;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
public interface TerminatePayload {
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ValidationResult {
|
|
||||||
private String packageName;
|
|
||||||
private String userId;
|
|
||||||
private String password;
|
|
||||||
private List<MonitoringValidationError> validationErrors = new ArrayList<>();
|
|
||||||
|
|
||||||
public void setPackageName(String packageName) {
|
|
||||||
this.packageName = packageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(String userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValidationErrors(List<MonitoringValidationError> validationErrors) {
|
|
||||||
this.validationErrors = validationErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValidationResult() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPackageName() {
|
|
||||||
return packageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MonitoringValidationError> getValidationErrors() {
|
|
||||||
return validationErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addError(MonitoringValidationError error) {
|
|
||||||
this.validationErrors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model.impl;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import lombok.Getter;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class PartFilePayload implements StagePayload {
|
|
||||||
private final Path partPath;
|
|
||||||
private final Long packageId;
|
|
||||||
private final boolean poison;
|
|
||||||
public static final PartFilePayload POISON = new PartFilePayload(true);
|
|
||||||
|
|
||||||
public PartFilePayload(boolean poison) {
|
|
||||||
this.poison = poison;
|
|
||||||
this.partPath = null;
|
|
||||||
this.packageId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PartFilePayload(Path partPath, Long packageId) {
|
|
||||||
this.partPath = partPath;
|
|
||||||
this.packageId = packageId;
|
|
||||||
this.poison = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPoison() {
|
|
||||||
return poison;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model.impl;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import ru.nbch.credit_tracker.model.TerminatePayload;
|
|
||||||
|
|
||||||
public class SignalXmlFilePayload implements TerminatePayload {
|
|
||||||
private final Path signalXmlFilePath;
|
|
||||||
|
|
||||||
public SignalXmlFilePayload(Path signalXmlFilePath) {
|
|
||||||
this.signalXmlFilePath = signalXmlFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getSignalXmlFilePath() {
|
|
||||||
return signalXmlFilePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.model.impl;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
|
|
||||||
|
|
||||||
public class SubjectPayload implements StagePayload {
|
|
||||||
private final Long packageId;
|
|
||||||
private final List<SubjectProfile> subjects;
|
|
||||||
public static final SubjectPayload POISON = new SubjectPayload(true);
|
|
||||||
private final boolean poison;
|
|
||||||
|
|
||||||
public SubjectPayload(boolean poison) {
|
|
||||||
this.packageId = null;
|
|
||||||
this.subjects = null;
|
|
||||||
this.poison = poison;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SubjectPayload(Long packageId, List<SubjectProfile> subjects) {
|
|
||||||
this.packageId = packageId;
|
|
||||||
this.subjects = subjects;
|
|
||||||
this.poison = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getPackageId() {
|
|
||||||
return packageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<SubjectProfile> getSubjects() {
|
|
||||||
return subjects;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPoison() {
|
|
||||||
return poison;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,150 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.repository;
|
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.List;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
import ru.nbch.credit_tracker.entities.indic.Name;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
public class PhoneRepository {
|
|
||||||
|
|
||||||
private static final String SELCT_FIDS = """
|
|
||||||
SELECT
|
|
||||||
pn.number,
|
|
||||||
pn.fid,
|
|
||||||
pn.file_since_dt
|
|
||||||
FROM PHONE_NORM pn
|
|
||||||
JOIN (SELECT DISTINCT fid FROM NAME) nf
|
|
||||||
ON nf.fid = pn.fid
|
|
||||||
WHERE number in (:phones)
|
|
||||||
ORDER BY
|
|
||||||
pn.number ASC,
|
|
||||||
pn.file_since_dt DESC,
|
|
||||||
pn.fid DESC
|
|
||||||
WITH UR
|
|
||||||
""";
|
|
||||||
|
|
||||||
private static final String SELCT_FIDS_WITH_NAME = """
|
|
||||||
SELECT
|
|
||||||
pn.number,
|
|
||||||
pn.fid,
|
|
||||||
pn.file_since_dt,
|
|
||||||
nf.first,
|
|
||||||
nf.middle,
|
|
||||||
nf.name_1,
|
|
||||||
nf.birth_dt,
|
|
||||||
nf.file_since_dt as file_since_dt_name
|
|
||||||
FROM PHONE_NORM pn
|
|
||||||
JOIN NAME nf
|
|
||||||
ON nf.fid = pn.fid
|
|
||||||
WHERE number in (:phones) WITH UR
|
|
||||||
""";
|
|
||||||
|
|
||||||
private final NamedParameterJdbcTemplate jdbcTemplate;
|
|
||||||
|
|
||||||
public PhoneRepository(@Qualifier("jdbcTemplateIndic") NamedParameterJdbcTemplate jdbcTemplate) {
|
|
||||||
this.jdbcTemplate = jdbcTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public List<FidsData> findFids(List<String> phones) {
|
|
||||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
|
||||||
params.addValue("phones", phones);
|
|
||||||
|
|
||||||
return jdbcTemplate.query(SELCT_FIDS, params, (rs, rowNum) ->
|
|
||||||
new PhoneRepository.FidsData(rs.getInt("fid"), rs.getString("number"), rs.getObject("file_since_dt", LocalDate.class))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public List<FidsDataWithName> findFidsWithName(List<String> phones) {
|
|
||||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
|
||||||
params.addValue("phones", phones);
|
|
||||||
|
|
||||||
return jdbcTemplate.query(SELCT_FIDS_WITH_NAME, params, (rs, rowNum) ->
|
|
||||||
new PhoneRepository.FidsDataWithName(
|
|
||||||
rs.getInt("FID"),
|
|
||||||
rs.getString("NUMBER"),
|
|
||||||
getLocalDate(rs, "FILE_SINCE_DT"),
|
|
||||||
rs.getString("FIRST"),
|
|
||||||
rs.getString("NAME_1"),
|
|
||||||
rs.getString("MIDDLE"),
|
|
||||||
getLocalDate(rs, "BIRTH_DT"),
|
|
||||||
getLocalDate(rs, "FILE_SINCE_DT_NAME")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Name> findNameByPhones(List<String> phones) {
|
|
||||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
|
||||||
params.addValue("phones", phones);
|
|
||||||
|
|
||||||
return jdbcTemplate.query(SELCT_FIDS_WITH_NAME, params, (rs, rowNum) ->
|
|
||||||
Name.builder()
|
|
||||||
.fid(rs.getInt("FID"))
|
|
||||||
.number(rs.getString("NUMBER"))
|
|
||||||
.fileSinceDate(getLocalDate(rs, "FILE_SINCE_DT_NAME"))
|
|
||||||
.first(rs.getString("FIRST"))
|
|
||||||
.middle(rs.getString("MIDDLE"))
|
|
||||||
.last(rs.getString("NAME_1"))
|
|
||||||
.birthDate(getLocalDate(rs, "BIRTH_DT"))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LocalDate getLocalDate(ResultSet rs, String col) throws SQLException {
|
|
||||||
java.sql.Date d = rs.getDate(col);
|
|
||||||
return d != null ? d.toLocalDate() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<FidsDataLong> findFidsLong(List<String> phones) {
|
|
||||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
|
||||||
params.addValue("phones", phones);
|
|
||||||
|
|
||||||
return jdbcTemplate.query(SELCT_FIDS, params, (rs, rowNum) ->
|
|
||||||
new PhoneRepository.FidsDataLong(rs.getInt("fid"), Long.parseLong(rs.getString("number")), rs.getObject("file_since_dt", LocalDate.class))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public static class FidsData {
|
|
||||||
private Integer fid;
|
|
||||||
private String phone;
|
|
||||||
private LocalDate fileSinceDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public static class FidsDataWithName {
|
|
||||||
private Integer fid;
|
|
||||||
private String phone;
|
|
||||||
private LocalDate fileSinceDate;
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
private String middleName;
|
|
||||||
private LocalDate birthDate;
|
|
||||||
private LocalDate fileSinceDateName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public static class FidsDataLong {
|
|
||||||
private Integer fid;
|
|
||||||
private Long phone;
|
|
||||||
private LocalDate fileSinceDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,7 +6,7 @@ import org.springframework.aop.framework.AopContext;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
|
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
import ru.nbch.credit_tracker.utils.CTUtil;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import org.slf4j.MDC;
|
||||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
import ru.nbch.credit_tracker.entities.app.Hit;
|
import ru.nbch.credit_tracker.entities.dto.Hit;
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Inquiry;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Inquiry;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Person;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Person;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Persons;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Persons;
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,18 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.builder.PersonFactoryBuilder;
|
import ru.nbch.credit_tracker.builder.PersonFactoryBuilder;
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
import ru.nbch.credit_tracker.entities.app.Hit;
|
import ru.nbch.credit_tracker.entities.dto.Hit;
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Auth;
|
import ru.nbch.credit_tracker.entities.external_request.signals.Auth;
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Person;
|
import ru.nbch.credit_tracker.entities.external_request.signals.Person;
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Signals;
|
import ru.nbch.credit_tracker.entities.external_request.signals.Signals;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_error.MonitoringReportErrors;
|
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_error.MonitoringReportErrors;
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
||||||
import ru.nbch.credit_tracker.enums.Status;
|
import ru.nbch.credit_tracker.enums.Status;
|
||||||
import ru.nbch.credit_tracker.service.indic.*;
|
import ru.nbch.credit_tracker.service.indic.FlagsService;
|
||||||
|
import ru.nbch.credit_tracker.service.indic.PersonService;
|
||||||
|
import ru.nbch.credit_tracker.service.indic.PhoneService;
|
||||||
import ru.nbch.credit_tracker.service.signal.HitsService;
|
import ru.nbch.credit_tracker.service.signal.HitsService;
|
||||||
import ru.nbch.credit_tracker.service.signal.PhoneFidMapService;
|
import ru.nbch.credit_tracker.service.signal.PhoneFidMapService;
|
||||||
import ru.nbch.credit_tracker.service.signal.UserPackageService;
|
import ru.nbch.credit_tracker.service.signal.UserPackageService;
|
||||||
|
|
@ -35,15 +37,12 @@ import java.util.function.Predicate;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@Deprecated
|
|
||||||
//todo оставил для временного подсмотреть на старую логику
|
|
||||||
public class SignalService {
|
public class SignalService {
|
||||||
|
|
||||||
private final CreditTrackerSettings config;
|
private final CreditTrackerSettings config;
|
||||||
private final HitsService hitsService;
|
private final HitsService hitsService;
|
||||||
private final UserPackageService userPackageService;
|
private final UserPackageService userPackageService;
|
||||||
private final PhoneFidMapService phoneFidMapService;
|
private final PhoneFidMapService phoneFidMapService;
|
||||||
private final PhoneService2 phoneService2;
|
|
||||||
private final PhoneService phoneService;
|
private final PhoneService phoneService;
|
||||||
private final FlagsService flagsService;
|
private final FlagsService flagsService;
|
||||||
private final PersonService personService;
|
private final PersonService personService;
|
||||||
|
|
@ -55,7 +54,6 @@ public class SignalService {
|
||||||
HitsService hitsService,
|
HitsService hitsService,
|
||||||
UserPackageService userPackageService,
|
UserPackageService userPackageService,
|
||||||
PhoneFidMapService phoneFidMapService,
|
PhoneFidMapService phoneFidMapService,
|
||||||
PhoneService2 phoneService2,
|
|
||||||
PhoneService phoneService,
|
PhoneService phoneService,
|
||||||
FlagsService flagsService,
|
FlagsService flagsService,
|
||||||
PersonService personService,
|
PersonService personService,
|
||||||
|
|
@ -64,7 +62,6 @@ public class SignalService {
|
||||||
this.hitsService = hitsService;
|
this.hitsService = hitsService;
|
||||||
this.userPackageService = userPackageService;
|
this.userPackageService = userPackageService;
|
||||||
this.phoneFidMapService = phoneFidMapService;
|
this.phoneFidMapService = phoneFidMapService;
|
||||||
this.phoneService2 = phoneService2;
|
|
||||||
this.phoneService = phoneService;
|
this.phoneService = phoneService;
|
||||||
this.flagsService = flagsService;
|
this.flagsService = flagsService;
|
||||||
this.personService = personService;
|
this.personService = personService;
|
||||||
|
|
@ -75,10 +72,6 @@ public class SignalService {
|
||||||
return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName());
|
return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPackageNotUnique(String userId, String packageName) {
|
|
||||||
return userPackageService.isPackageNotUnique(userId, packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long registerPackage(MonitoringRequest request) {
|
public Long registerPackage(MonitoringRequest request) {
|
||||||
UserPackage userPackage = UserPackage.builder()
|
UserPackage userPackage = UserPackage.builder()
|
||||||
.userId(request.getUserId())
|
.userId(request.getUserId())
|
||||||
|
|
@ -89,16 +82,6 @@ public class SignalService {
|
||||||
return userPackageService.insertPackage(userPackage);
|
return userPackageService.insertPackage(userPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long registerPackage(String userId, String packageName) {
|
|
||||||
UserPackage userPackage = UserPackage.builder()
|
|
||||||
.userId(userId)
|
|
||||||
.packageName(packageName)
|
|
||||||
.createdAt(LocalDateTime.now())
|
|
||||||
.status(Status.PROCESSING.name())
|
|
||||||
.build();
|
|
||||||
return userPackageService.insertPackage(userPackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerSubjects(String filePath, Long packageId) {
|
public void registerSubjects(String filePath, Long packageId) {
|
||||||
log.info("Start registering subjects. PackageId: {}", packageId);
|
log.info("Start registering subjects. PackageId: {}", packageId);
|
||||||
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
|
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
|
||||||
|
|
@ -119,25 +102,6 @@ public class SignalService {
|
||||||
log.info("Subjects were registered. PackageId: {}", packageId);
|
log.info("Subjects were registered. PackageId: {}", packageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Выгружает {@link PhoneFidMap} батчами. Передает обогащенные фидами и данными из Name {@link PhoneFidMap}
|
|
||||||
* на поиск флагов и формирование отчета в оф. сервис сигналов
|
|
||||||
* @param packageId id пакета, по которому идет выборка {@link PhoneFidMap}
|
|
||||||
*/
|
|
||||||
public void processSubjects(Long packageId) {
|
|
||||||
int offset = 0;
|
|
||||||
List<PhoneFidMap> batch;
|
|
||||||
do {
|
|
||||||
batch = phoneFidMapService.findFullPhoneFidMap(packageId, offset, batchSize);
|
|
||||||
if (!batch.isEmpty()) {
|
|
||||||
Map<Integer, PhoneFidMap> fidsMapByBatch = phoneService.defineFidsAndNameByPhone(batch);
|
|
||||||
// TODO process fidsMapByBatch here
|
|
||||||
}
|
|
||||||
offset += batchSize;
|
|
||||||
} while (!batch.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Обрабатывает все PhoneFidMap по packageId, выгружая их пачками и фильтруя по переданному фильтру
|
* Обрабатывает все PhoneFidMap по packageId, выгружая их пачками и фильтруя по переданному фильтру
|
||||||
*/
|
*/
|
||||||
|
|
@ -146,7 +110,6 @@ public class SignalService {
|
||||||
boolean noFidsFound = true;
|
boolean noFidsFound = true;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
List<PhoneFidMap> batch;
|
List<PhoneFidMap> batch;
|
||||||
Map<Integer, PhoneFidMap> phonesByFidToProcessing = new HashMap<>();
|
|
||||||
do {
|
do {
|
||||||
batch = phoneFidMapService.findFullPhoneFidMap(packageId, offset, batchSize);
|
batch = phoneFidMapService.findFullPhoneFidMap(packageId, offset, batchSize);
|
||||||
|
|
||||||
|
|
@ -162,32 +125,15 @@ public class SignalService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filteredItems.isEmpty()) {
|
if (!filteredItems.isEmpty()) {
|
||||||
Map<Integer, PhoneFidMap> fidsMapByBatch = phoneService.defineFidByPhone(filteredItems);
|
boolean fidsFound = updateFlags(filteredItems, packageId);
|
||||||
phoneService.defineFidByPhone(filteredItems);
|
if (noFidsFound) {
|
||||||
log.debug("Actual fids size by phone's batch: {}", fidsMapByBatch.size());
|
noFidsFound = !fidsFound;
|
||||||
|
|
||||||
if (fidsMapByBatch.size() + phonesByFidToProcessing.size() <= batchSize) {
|
|
||||||
phonesByFidToProcessing.putAll(fidsMapByBatch);
|
|
||||||
} else {
|
|
||||||
//todo execute find name and id -> forming xml
|
|
||||||
boolean fidsFound = updateFlags(phonesByFidToProcessing, packageId);
|
|
||||||
if (noFidsFound) {
|
|
||||||
noFidsFound = !fidsFound;
|
|
||||||
}
|
|
||||||
phonesByFidToProcessing = new HashMap<>(fidsMapByBatch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += batchSize;
|
offset += batchSize;
|
||||||
} while (!batch.isEmpty());
|
} while (!batch.isEmpty());
|
||||||
|
|
||||||
if (!phonesByFidToProcessing.isEmpty()) {
|
|
||||||
boolean fidsFound = updateFlags(phonesByFidToProcessing, packageId);
|
|
||||||
if (noFidsFound) {
|
|
||||||
noFidsFound = !fidsFound;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UpdateResult(updated, noFidsFound);
|
return new UpdateResult(updated, noFidsFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,37 +141,50 @@ public class SignalService {
|
||||||
* Обрабатывает пачку PhoneFidMap: обновляет фиды и флаги просрочек
|
* Обрабатывает пачку PhoneFidMap: обновляет фиды и флаги просрочек
|
||||||
* @return fidsFound true - если хотя бы по одному номеру был найден фид, false - в противном случае
|
* @return fidsFound true - если хотя бы по одному номеру был найден фид, false - в противном случае
|
||||||
*/
|
*/
|
||||||
// TODO Добавить отдельный метод. Если не нашелся фид, надо обновить в базе fid = null и флаги = null calculated_at=now()
|
public boolean updateFlags(List<PhoneFidMap> subjects, Long packageId) {
|
||||||
public boolean updateFlags(Map<Integer, PhoneFidMap> fidsMap, Long packageId) {
|
log.info("Start calculating fids and flags for subjects batch. PackageId: {}", packageId);
|
||||||
log.info("Start calculating flags for subjects batch. PackageId: {}", packageId);
|
Map<String, Integer> fidsMap = phoneService.findFidsPhoneData(subjects);
|
||||||
Map<Integer, FlagsService.FlagsData> flagsDataMap = flagsService.findFlags(fidsMap.keySet().stream().toList());
|
LocalDateTime calculatedAt = LocalDateTime.now();
|
||||||
|
boolean fidsFound = fidsMap.values().stream().anyMatch(Objects::nonNull);
|
||||||
|
Map<Integer, FlagsService.FlagsData> flagsDataMap = flagsService.findFlags(fidsMap.values().stream().filter(Objects::nonNull).toList());
|
||||||
List<PhoneFidMap> subjectToUpdate = new ArrayList<>();
|
List<PhoneFidMap> subjectToUpdate = new ArrayList<>();
|
||||||
for (Map.Entry<Integer, FlagsService.FlagsData> entry : flagsDataMap.entrySet()) {
|
|
||||||
Integer fid = entry.getKey();
|
|
||||||
FlagsService.FlagsData flagsData = entry.getValue();
|
|
||||||
PhoneFidMap phoneFidMap = fidsMap.get(fid);
|
|
||||||
|
|
||||||
phoneFidMap.setFid(fid);
|
subjects.forEach(subject -> {
|
||||||
phoneFidMap.setFlagDebt5000(flagsData.getFlagDebt5000());
|
Integer fid = fidsMap.get("9" + subject.getPhone());
|
||||||
phoneFidMap.setFlag90days(flagsData.getFlag90days());
|
if (fid != null) {
|
||||||
phoneFidMap.setCalculatedAt(LocalDateTime.now());
|
FlagsService.FlagsData flagsData = flagsDataMap.get(fid);
|
||||||
|
subject = PhoneFidMap.builder()
|
||||||
subjectToUpdate.add(phoneFidMap);
|
.id(subject.getId())
|
||||||
}
|
.packageId(packageId)
|
||||||
|
.subjectId(subject.getSubjectId())
|
||||||
log.debug("Start updating subject's batch");
|
.phone(subject.getPhone())
|
||||||
if (!subjectToUpdate.isEmpty()) {
|
.fid(fid)
|
||||||
int updateBatchSize = 7000; // 9 параметров на одну запись для обновления. Максимальное количество параметров ~65000
|
.flagDebt5000(flagsData.getFlagDebt5000())
|
||||||
for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) {
|
.flag90days(flagsData.getFlag90days())
|
||||||
int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size());
|
.calculatedAt(calculatedAt)
|
||||||
phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex));
|
.build();
|
||||||
log.trace("Updated fids and flags for subject's batch from: {} to: {}. Total count: {}. PackageId: {}", j, endIndex, subjectToUpdate.size(), packageId);
|
} else {
|
||||||
|
subject = PhoneFidMap.builder()
|
||||||
|
.id(subject.getId())
|
||||||
|
.packageId(packageId)
|
||||||
|
.subjectId(subject.getSubjectId())
|
||||||
|
.phone(subject.getPhone())
|
||||||
|
.calculatedAt(calculatedAt)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
subjectToUpdate.add(subject);
|
||||||
log.debug("Complete updating subject's batch");
|
});
|
||||||
|
|
||||||
log.info("Finish calculating flags for subjects. PackageId: {}. Batch size: {}", packageId, fidsMap.size());
|
int updateBatchSize = batchSize / 9; // 9 параметров на одну запись для обновления. Максимальное количество параметров ~65000
|
||||||
return !fidsMap.isEmpty();
|
for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) {
|
||||||
|
int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size());
|
||||||
|
phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex));
|
||||||
|
log.trace("Updated fids and flags for subject's batch from: {} to: {}. Total count: {}. PackageId: {}", j, endIndex, subjectToUpdate.size(), packageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Finish calculating fids and flags for subjects. PackageId: {}. Batch size: {}", packageId, subjects.size());
|
||||||
|
|
||||||
|
return fidsFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rejectPackage(MonitoringRequest request) {
|
public void rejectPackage(MonitoringRequest request) {
|
||||||
|
|
@ -238,16 +197,6 @@ public class SignalService {
|
||||||
userPackageService.insertPackage(userPackage);
|
userPackageService.insertPackage(userPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rejectPackage(String userId, String packageName) {
|
|
||||||
UserPackage userPackage = UserPackage.builder()
|
|
||||||
.userId(userId)
|
|
||||||
.packageName(packageName)
|
|
||||||
.createdAt(LocalDateTime.now())
|
|
||||||
.status(Status.REJECTED.name())
|
|
||||||
.build();
|
|
||||||
userPackageService.insertPackage(userPackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updatePackageStatus(Long packageId, Status status) {
|
public void updatePackageStatus(Long packageId, Status status) {
|
||||||
userPackageService.updatePackageStatus(packageId, status);
|
userPackageService.updatePackageStatus(packageId, status);
|
||||||
}
|
}
|
||||||
|
|
@ -277,7 +226,7 @@ public class SignalService {
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Signals buildSignals(Long packageId) {
|
private Signals buildSignals(Long packageId) {
|
||||||
UserPackage userPackage = userPackageService.findPackage(packageId);
|
UserPackage userPackage = userPackageService.findPackage(packageId);
|
||||||
Signals signals = new Signals();
|
Signals signals = new Signals();
|
||||||
signals.setOnline("2"); // Всегда=2 (только онлайн-сигналы)
|
signals.setOnline("2"); // Всегда=2 (только онлайн-сигналы)
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
|
||||||
import ru.nbch.credit_tracker.enums.Status;
|
|
||||||
import ru.nbch.credit_tracker.service.signal.UserPackageService;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class SignalServiceV2 {
|
|
||||||
private final UserPackageService userPackageService;
|
|
||||||
|
|
||||||
public SignalServiceV2(UserPackageService userPackageService) {
|
|
||||||
this.userPackageService = userPackageService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPackageNotUnique(MonitoringRequest request) {
|
|
||||||
return userPackageService.isPackageNotUnique(request.getUserId(), request.getPackageName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPackageNotUnique(String userId, String packageName) {
|
|
||||||
return userPackageService.isPackageNotUnique(userId, packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Long registerPackage(String userId, String packageName) {
|
|
||||||
UserPackage userPackage = UserPackage.builder()
|
|
||||||
.userId(userId)
|
|
||||||
.packageName(packageName)
|
|
||||||
.createdAt(LocalDateTime.now())
|
|
||||||
.status(Status.PROCESSING.name())
|
|
||||||
.build();
|
|
||||||
return userPackageService.insertPackage(userPackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rejectPackage(String userId, String packageName) {
|
|
||||||
UserPackage userPackage = UserPackage.builder()
|
|
||||||
.userId(userId)
|
|
||||||
.packageName(packageName)
|
|
||||||
.createdAt(LocalDateTime.now())
|
|
||||||
.status(Status.REJECTED.name())
|
|
||||||
.build();
|
|
||||||
userPackageService.insertPackage(userPackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public List<UserPackage> findActivePackages(String userId) {
|
|
||||||
return userPackageService.findUserPackages(userId, Status.ON_MONITORING);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<UserPackage> findAllPackages(String userId) {
|
|
||||||
return userPackageService.findAllPackagesByUserId(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPackageExists(String username, String packageName) {
|
|
||||||
return userPackageService.isPackageExists(username, packageName, Status.ON_MONITORING);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPackagesByStatusExist(String username, String packageName, Status status) {
|
|
||||||
return userPackageService.hasActivePackages(username, packageName, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deletePackage(String username, String packageName, LocalDateTime deactivatedAt) {
|
|
||||||
userPackageService.deletePackage(username, packageName, Status.DELETED, Status.ON_MONITORING, deactivatedAt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,7 @@ import org.springframework.aop.framework.AopContext;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
|
import ru.nbch.credit_tracker.config.mdc.SetAndClearMdc;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
import ru.nbch.credit_tracker.enums.Status;
|
import ru.nbch.credit_tracker.enums.Status;
|
||||||
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,18 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
package ru.nbch.credit_tracker.service;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
|
||||||
import ru.nbch.credit_tracker.enums.Status;
|
|
||||||
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import org.slf4j.MDC;
|
||||||
import java.util.concurrent.TimeUnit;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
import java.util.function.Predicate;
|
import org.springframework.scheduling.support.CronTrigger;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
|
import ru.nbch.credit_tracker.enums.Status;
|
||||||
|
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
||||||
|
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сервис периодического обновления фидов и флагов просрочек по пакетам находящимся в статусе ON_MONITORING
|
* Сервис периодического обновления фидов и флагов просрочек по пакетам находящимся в статусе ON_MONITORING
|
||||||
|
|
@ -30,31 +26,40 @@ public class UpdatingFlagsService {
|
||||||
private final SignalRestService signalRestService;
|
private final SignalRestService signalRestService;
|
||||||
private final MonitoringErrorProcesingService monitoringErrorProcesingService;
|
private final MonitoringErrorProcesingService monitoringErrorProcesingService;
|
||||||
private final Long daysToUpdateFlags;
|
private final Long daysToUpdateFlags;
|
||||||
private final Long updateFlagsInterval;
|
private final String updateFlagsCronExpression;
|
||||||
|
private final PhoneFidMapMapper phoneFidMapMapper;
|
||||||
|
|
||||||
public UpdatingFlagsService(SignalService signalService,
|
public UpdatingFlagsService(SignalService signalService,
|
||||||
SignalRestService signalRestService,
|
SignalRestService signalRestService,
|
||||||
MonitoringErrorProcesingService monitoringErrorProcesingService,
|
MonitoringErrorProcesingService monitoringErrorProcesingService,
|
||||||
CreditTrackerSettings config) {
|
CreditTrackerSettings config,
|
||||||
|
PhoneFidMapMapper phoneFidMapMapper) {
|
||||||
this.signalService = signalService;
|
this.signalService = signalService;
|
||||||
this.signalRestService = signalRestService;
|
this.signalRestService = signalRestService;
|
||||||
this.monitoringErrorProcesingService = monitoringErrorProcesingService;
|
this.monitoringErrorProcesingService = monitoringErrorProcesingService;
|
||||||
this.daysToUpdateFlags = config.getDaysToUpdateFlags() != null ? config.getDaysToUpdateFlags() : 1;
|
this.daysToUpdateFlags = config.getDaysToUpdateFlags() != null ? config.getDaysToUpdateFlags() : 1;
|
||||||
this.updateFlagsInterval = config.getUpdateFlagsInterval() != null ? config.getUpdateFlagsInterval() : 1;
|
this.updateFlagsCronExpression = config.getUpdateFlagsCronExpression() != null ? config.getUpdateFlagsCronExpression() : "*/10 * * * * *";
|
||||||
|
this.phoneFidMapMapper = phoneFidMapMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("updating-flags-"));
|
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||||
scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS);
|
scheduler.setPoolSize(1);
|
||||||
|
scheduler.initialize();
|
||||||
|
scheduler.schedule(this::update, new CronTrigger(updateFlagsCronExpression));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update() {
|
public void update() {
|
||||||
log.info("Start updating flags");
|
log.info("Start updating flags");
|
||||||
List<UserPackage> packages = signalService.findPackagesOnMonitoring();
|
List<UserPackage> packages = signalService.findPackagesOnMonitoring();
|
||||||
for (UserPackage userPackage : packages) {
|
for (UserPackage userPackage : packages) {
|
||||||
log.info("Updating flags for Package {}", userPackage.getPackageName());
|
|
||||||
MDC.put("ru.nbch.credit_tracker.log.mdc.key", "[" + userPackage.getPackageName() +"]");
|
MDC.put("ru.nbch.credit_tracker.log.mdc.key", "[" + userPackage.getPackageName() +"]");
|
||||||
updateFlags(userPackage);
|
log.info("Check on updating flags for Package {}", userPackage.getPackageName());
|
||||||
|
boolean hasOldRow = phoneFidMapMapper.hasOldRow(userPackage.getId(), daysToUpdateFlags.intValue());
|
||||||
|
log.info("There are {} old rows", hasOldRow ? "exist" : "doesn't exist");
|
||||||
|
if (hasOldRow) {
|
||||||
|
updateFlags(userPackage);
|
||||||
|
}
|
||||||
MDC.remove("ru.nbch.credit_tracker.log.mdc.key");
|
MDC.remove("ru.nbch.credit_tracker.log.mdc.key");
|
||||||
}
|
}
|
||||||
log.info("Finish updating flags");
|
log.info("Finish updating flags");
|
||||||
|
|
@ -65,8 +70,7 @@ public class UpdatingFlagsService {
|
||||||
String packageName = userPackage.getPackageName();
|
String packageName = userPackage.getPackageName();
|
||||||
try {
|
try {
|
||||||
signalService.updatePackageStatus(packageId, Status.PROCESSING);
|
signalService.updatePackageStatus(packageId, Status.PROCESSING);
|
||||||
Predicate<PhoneFidMap> filter = subject -> subject.getCalculatedAt() != null && hasDaysPassed(subject.getCalculatedAt());
|
SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, null);
|
||||||
SignalService.UpdateResult updateResult = signalService.updateSubjects(packageId, filter);
|
|
||||||
if (updateResult.isUpdated()) {
|
if (updateResult.isUpdated()) {
|
||||||
if (signalRestService.setupMonitoring(packageId)) {
|
if (signalRestService.setupMonitoring(packageId)) {
|
||||||
LocalDateTime monitoringAt = userPackage.getMonitoringAt() != null ? userPackage.getMonitoringAt() : LocalDateTime.now();
|
LocalDateTime monitoringAt = userPackage.getMonitoringAt() != null ? userPackage.getMonitoringAt() : LocalDateTime.now();
|
||||||
|
|
|
||||||
|
|
@ -1,70 +1,35 @@
|
||||||
package ru.nbch.credit_tracker.service.indic;
|
package ru.nbch.credit_tracker.service.indic;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
|
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class FlagsService {
|
public class FlagsService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(FlagsService.class);
|
|
||||||
private final FlagsMapper mapper;
|
private final FlagsMapper mapper;
|
||||||
|
|
||||||
private static final String SELECT_RU_PASDUEARREAR_DATA =
|
public FlagsService(FlagsMapper mapper) {
|
||||||
"SELECT FID, ACC_SERIAL_NUM, REPORTED_DT, AMT_PAST_DUE, DAYS_PAST_DUE " +
|
|
||||||
"FROM RU_PASTDUEARREAR " +
|
|
||||||
"WHERE FID IN (:fids) " +
|
|
||||||
"ORDER BY FID, REPORTED_DT DESC " +
|
|
||||||
"WITH UR";
|
|
||||||
|
|
||||||
private static final String SELECT_RU_PAYMT_DATA =
|
|
||||||
"SELECT FID, DAYS_PAST_DUE, REPORTED_DT " +
|
|
||||||
"FROM RU_PAYMT " +
|
|
||||||
"WHERE FID IN (:fids) " +
|
|
||||||
"AND REPORTED_DT >= :reportedDate " +
|
|
||||||
"WITH UR";
|
|
||||||
|
|
||||||
private final NamedParameterJdbcTemplate jdbcTemplate;
|
|
||||||
|
|
||||||
public FlagsService(FlagsMapper mapper,
|
|
||||||
@Qualifier("jdbcTemplateIndic") NamedParameterJdbcTemplate jdbcTemplate) {
|
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
this.jdbcTemplate = jdbcTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, FlagsData> findFlags(List<Integer> fids) {
|
public Map<Integer, FlagsData> findFlags(List<Integer> fids) {
|
||||||
if (fids.isEmpty()) {
|
if (fids.isEmpty()) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
List<Integer> distinctFids = fids.stream()
|
|
||||||
.distinct()
|
|
||||||
.sorted(Comparator.naturalOrder())
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
log.debug("Fids count: {}", distinctFids.size());
|
|
||||||
Map<Integer, Integer> flags5000 = new HashMap<>();
|
|
||||||
Map<Integer, Integer> flags90DaysByPastDueArrear = new HashMap<>();
|
|
||||||
Map<Integer, Integer> flags90DaysByRuPaymt = new HashMap<>();
|
|
||||||
findFlagsRuPastDueArrear(distinctFids, flags5000, flags90DaysByPastDueArrear);
|
|
||||||
findFlagsRuPaymt(distinctFids, flags90DaysByRuPaymt);
|
|
||||||
|
|
||||||
Map<Integer, FlagsData> result = new HashMap<>();
|
Map<Integer, FlagsData> result = new HashMap<>();
|
||||||
|
Map<Integer, Integer> flags5000 = calcFlag5000(fids);
|
||||||
|
Map<Integer, Integer> flags90DaysByPastDueArrear = calcFlag90DaysByPastDueArrear(fids);
|
||||||
|
Map<Integer, Integer> flags90DaysByRuPaymt = calcFlag90DaysByRuPaymt(fids);
|
||||||
|
|
||||||
fids.forEach(fid -> {
|
fids.forEach(fid -> {
|
||||||
Integer flagDebt5000 = flags5000.get(fid);
|
Integer flagDebt5000 = flags5000.get(fid);
|
||||||
if (flagDebt5000 == null) {
|
if (flagDebt5000 == null) {
|
||||||
|
|
@ -72,7 +37,7 @@ public class FlagsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer flag90days = flags90DaysByPastDueArrear.get(fid);
|
Integer flag90days = flags90DaysByPastDueArrear.get(fid);
|
||||||
if (flag90days == null || flag90days == 0) {
|
if (flag90days == null) {
|
||||||
flag90days = flags90DaysByRuPaymt.get(fid);
|
flag90days = flags90DaysByRuPaymt.get(fid);
|
||||||
if (flag90days == null) {
|
if (flag90days == null) {
|
||||||
flag90days = 0;
|
flag90days = 0;
|
||||||
|
|
@ -84,352 +49,52 @@ public class FlagsService {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO optimize
|
|
||||||
public void fillFlagsData(List<SubjectProfile> subjects) {
|
|
||||||
List<Integer> fids = subjects.stream().map(SubjectProfile::getFid).filter(Objects::nonNull).toList();
|
|
||||||
Map<Integer, FlagsService.FlagsData> fidsflagsDataMap = findFlags2(fids);
|
|
||||||
|
|
||||||
fidsflagsDataMap.forEach((fid, data) -> {
|
|
||||||
subjects.stream().filter(s-> s.getFid() != null && s.getFid().equals(fid)).forEach(phoneFidMap -> {
|
|
||||||
|
|
||||||
// phoneFidMap.setFlagDebt5000(data.getFlagDebt5000());
|
|
||||||
// phoneFidMap.setFlag90days(data.getFlag90days());
|
|
||||||
// phoneFidMap.setCalculatedAt(LocalDateTime.now());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
subjects.stream().filter(s-> s.getFid() == null).forEach(phoneFidMap -> {
|
|
||||||
// phoneFidMap.setCalculatedAt(LocalDateTime.now());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Выбирает данные из RU_PASTDUEARREAR и ищет по ним флаги просрочек
|
|
||||||
* По FID из RU_PASTDUEARREAR выбираются все уникальные ACC_SERIAL_NUM с максимальной датой REPORTED_DT.
|
* По FID из RU_PASTDUEARREAR выбираются все уникальные ACC_SERIAL_NUM с максимальной датой REPORTED_DT.
|
||||||
* Если по хотя бы одной такой записи AMT_PAST_DUE > 5000, то flag500 устанавливается в 1.
|
* Если по хотя бы одной такой записи AMT_PAST_DUE > 5000, то флаг устанавливается в 1.
|
||||||
* Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 0.
|
* Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 0.
|
||||||
*
|
|
||||||
* flag90Days = 1, если выполняется хотя бы одно из условий:
|
|
||||||
* В INDIC.RU_PASTDUEARREAR у данного FID есть запись с DAYS_PAST_DUE ≥ 90 и REPORTED_DT >= текущая дата – 12 месяцев.
|
|
||||||
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
|
||||||
* @param fids - отсортирован по возрастанию фидов
|
|
||||||
* @param flag5000Map - рещультирующая мапа флагов просрочек debt5000
|
|
||||||
* @param flag90Days - рещультирующая мапа флагов просрочек 90_days
|
|
||||||
*/
|
*/
|
||||||
private void findFlagsRuPastDueArrear(List<Integer> fids, Map<Integer, Integer> flag5000Map, Map<Integer, Integer> flag90Days) {
|
private Map<Integer, Integer> calcFlag5000(List<Integer> fids) {
|
||||||
log.debug("Start calculating flag 5000 and 90 days by RU_PASTDUEARREAR");
|
return mapper.findFlagsDebt5000(fids).stream()
|
||||||
List<RuPastDuarearData> ruPastDuarearDataList = mapper.findRuPastDuarearData(fids);
|
.collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag,
|
||||||
|
(existing, replacement) -> {
|
||||||
ruPastDuarearDataList.sort(Comparator.comparing(FlagsService.RuPastDuarearData::getFid) // сортируем сначала по фиду
|
if (existing == 1) {
|
||||||
.thenComparing(FlagsService.RuPastDuarearData::getReportedDate, Comparator.reverseOrder())); // Затем сортируем по REPORTED_DT по убыванию
|
return existing;
|
||||||
|
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
|
||||||
|
|
||||||
for (Integer fid : fids) {
|
|
||||||
Iterator<RuPastDuarearData> iterator = ruPastDuarearDataList.iterator();
|
|
||||||
BigInteger prevAccSerialNum = null;
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
FlagsService.RuPastDuarearData data = iterator.next();
|
|
||||||
if (fid.equals(data.getFid())) {
|
|
||||||
if (flag5000Map.get(fid) == null) { // Первая запись в списке с макс REPORTED_DT. Нас интересует только она для флага 5000
|
|
||||||
if (prevAccSerialNum == null || !prevAccSerialNum.equals(data.getAccSerialNum())) {
|
|
||||||
if (data.getAmtPastDue() != null && data.getAmtPastDue().compareTo(BigDecimal.valueOf(5000)) >= 0) {
|
|
||||||
flag5000Map.put(fid, 1);
|
|
||||||
}
|
|
||||||
prevAccSerialNum = data.getAccSerialNum();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer flag90 = flag90Days.get(fid);
|
|
||||||
if (flag90 != null && flag90 == 1) {
|
|
||||||
iterator.remove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag90 == null || flag90 == 0) {
|
|
||||||
if (data.getDaysPastDue() != null) {
|
|
||||||
boolean has90daysFlag = data.getDaysPastDue().compareTo(BigInteger.valueOf(90)) >= 0 && !data.getReportedDate().isBefore(yearAgo);
|
|
||||||
if (has90daysFlag) {
|
|
||||||
flag90Days.put(fid, 1);
|
|
||||||
iterator.remove();
|
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
flag90Days.put(fid, 0);
|
return replacement;
|
||||||
iterator.remove();
|
|
||||||
}
|
}
|
||||||
} else {
|
}));
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// если мы так и не нашли флаги для этих фидов - выставляем их в 0
|
|
||||||
flag5000Map.putIfAbsent(fid, 0);
|
|
||||||
flag90Days.putIfAbsent(fid, 0);
|
|
||||||
}
|
|
||||||
log.debug("Complete calculating flag 5000 and 90 days by RU_PASTDUEARREAR");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Выбирает данные из RU_PAYMT и ищет по ним флаги просрочек 90Days
|
* Флаг = 1, если выполняется хотя бы одно из условий:
|
||||||
*
|
* В INDIC.RU_PASTDUEARREAR или RU_PAYMT у данного FID есть запись с DAYS_PAST_DUE ≥ 90 и REPORTED_DT >= текущая дата – 12 месяцев.
|
||||||
* flag90Days = 1, если выполняется хотя бы одно из условий:
|
|
||||||
* В INDIC.RU_PAYMT у данного FID есть запись с DAYS_PAST_DUE ≥ 90 и REPORTED_DT >= текущая дата – 12 месяцев.
|
|
||||||
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
||||||
* @param fids - отсортирован по возрастанию фидов
|
|
||||||
* @param flag90Days - рещультирующая мапа флагов просрочек 90_days
|
|
||||||
*/
|
*/
|
||||||
private void findFlagsRuPaymt(List<Integer> fids, Map<Integer, Integer> flag90Days) {
|
private Map<Integer, Integer> calcFlag90DaysByPastDueArrear(List<Integer> fids) {
|
||||||
log.debug("Start calculating flag 90 days by RU_PAPAYMT");
|
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
||||||
List<RuPaymtData> ruPaymtDataList = mapper.findRuPaymtData(fids, yearAgo);
|
return mapper.findFlag90ByPastDueArrear(fids, yearAgo).stream()
|
||||||
ruPaymtDataList.sort(Comparator.comparing(RuPaymtData::getFid, Comparator.naturalOrder()));
|
.collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag,
|
||||||
|
(existing, replacement) -> {
|
||||||
for (Integer fid : fids) {
|
if (existing == 1) {
|
||||||
Iterator<RuPaymtData> iterator = ruPaymtDataList.iterator();
|
return existing;
|
||||||
while (iterator.hasNext()) {
|
|
||||||
RuPaymtData data = iterator.next();
|
|
||||||
if (fid.equals(data.getFid())) {
|
|
||||||
Integer flag90 = flag90Days.get(fid);
|
|
||||||
if (flag90 != null && flag90 == 1) {
|
|
||||||
iterator.remove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag90 == null || flag90 == 0) {
|
|
||||||
if (data.getDaysPastDue() != null) {
|
|
||||||
boolean has90daysFlag = data.getDaysPastDue().compareTo(BigInteger.valueOf(90)) >= 0 && !data.getReportedDate().isBefore(yearAgo);
|
|
||||||
if (has90daysFlag) {
|
|
||||||
flag90Days.put(fid, 1);
|
|
||||||
iterator.remove();
|
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
flag90Days.put(fid, 0);
|
return replacement;
|
||||||
iterator.remove();
|
|
||||||
}
|
}
|
||||||
} else {
|
}));
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flag90Days.putIfAbsent(fid, 0);
|
|
||||||
}
|
|
||||||
log.debug("Complete calculating flag 90 days by RU_PAPAYMT");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, FlagsService.FlagsData> findFlags2(List<Integer> fids) {
|
private Map<Integer, Integer> calcFlag90DaysByRuPaymt(List<Integer> fids) {
|
||||||
if (fids.isEmpty()) {
|
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
List<Integer> distinctFids = fids.stream()
|
|
||||||
.distinct()
|
|
||||||
.sorted(Comparator.naturalOrder())
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
log.debug("Fids count: {}", distinctFids.size());
|
|
||||||
Map<Integer, Integer> flags5000 = new HashMap<>();
|
|
||||||
Map<Integer, Integer> flags90DaysByPastDueArrear = new HashMap<>();
|
|
||||||
Map<Integer, Integer> flags90DaysByRuPaymt = new HashMap<>();
|
|
||||||
findFlagsRuPastDueArrear2(distinctFids, flags5000, flags90DaysByPastDueArrear);
|
|
||||||
findFlagsRuPaymt2(distinctFids, flags90DaysByRuPaymt);
|
|
||||||
|
|
||||||
Map<Integer, FlagsService.FlagsData> result = new HashMap<>();
|
|
||||||
fids.forEach(fid -> {
|
|
||||||
Integer flagDebt5000 = flags5000.get(fid);
|
|
||||||
if (flagDebt5000 == null) {
|
|
||||||
flagDebt5000 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer flag90days = flags90DaysByPastDueArrear.get(fid);
|
|
||||||
if (flag90days == null || flag90days == 0) {
|
|
||||||
flag90days = flags90DaysByRuPaymt.get(fid);
|
|
||||||
if (flag90days == null) {
|
|
||||||
flag90days = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.put(fid, new FlagsService.FlagsData(flagDebt5000, flag90days));
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Выбирает данные из RU_PASTDUEARREAR и ищет по ним флаги просрочек
|
|
||||||
* По FID из RU_PASTDUEARREAR выбираются все уникальные ACC_SERIAL_NUM с максимальной датой REPORTED_DT.
|
|
||||||
* Если по хотя бы одной такой записи AMT_PAST_DUE > 5000, то flag500 устанавливается в 1.
|
|
||||||
* Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 0.
|
|
||||||
* <p>
|
|
||||||
* flag90Days = 1, если выполняется хотя бы одно из условий:
|
|
||||||
* В INDIC.RU_PASTDUEARREAR у данного FID есть запись с DAYS_PAST_DUE ≥ 90 и REPORTED_DT >= текущая дата – 12 месяцев.
|
|
||||||
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
|
||||||
*
|
|
||||||
* @param fids - отсортирован по возрастанию фидов
|
|
||||||
* @param flag5000Map - рещультирующая мапа флагов просрочек debt5000
|
|
||||||
* @param flag90Days - рещультирующая мапа флагов просрочек 90_days
|
|
||||||
*/
|
|
||||||
private void findFlagsRuPastDueArrear2(List<Integer> fids, Map<Integer, Integer> flag5000Map, Map<Integer, Integer> flag90Days) {
|
|
||||||
log.debug("Start calculating flag 5000 and 90 days by RU_PASTDUEARREAR");
|
|
||||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
|
||||||
params.addValue("fids", fids);
|
|
||||||
|
|
||||||
jdbcTemplate.query(SELECT_RU_PASDUEARREAR_DATA, params, (ResultSet rs) -> {
|
|
||||||
Integer currentFid = null;
|
|
||||||
BigInteger prevAccSerialNum = null;
|
|
||||||
boolean processed5000ForCurrentId = false;
|
|
||||||
boolean processed90DaysForCurrentId = false;
|
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
|
||||||
|
|
||||||
while (rs.next()) {
|
|
||||||
Integer fid = rs.getInt("FID");
|
|
||||||
|
|
||||||
// Переход к новому fid. Сброс состояния
|
|
||||||
if (!fid.equals(currentFid)) {
|
|
||||||
currentFid = fid;
|
|
||||||
prevAccSerialNum = null;
|
|
||||||
processed5000ForCurrentId = false;
|
|
||||||
processed90DaysForCurrentId = false;
|
|
||||||
|
|
||||||
// Инициализируем значения по умолчанию
|
|
||||||
flag5000Map.putIfAbsent(fid, 0);
|
|
||||||
flag90Days.putIfAbsent(fid, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если для текущего FID уже обработали оба флага, пропускаем остальные записи
|
|
||||||
if (processed5000ForCurrentId && processed90DaysForCurrentId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработка флага 5000
|
|
||||||
if (!processed5000ForCurrentId && flag5000Map.get(fid) == 0) {
|
|
||||||
BigInteger currentAccSerialNum = getBigInteger(rs, "ACC_SERIAL_NUM");
|
|
||||||
BigDecimal amtPastDue = getBigDecimal(rs, "AMT_PAST_DUE");
|
|
||||||
|
|
||||||
if (prevAccSerialNum == null || !prevAccSerialNum.equals(currentAccSerialNum)) {
|
|
||||||
if (amtPastDue != null && amtPastDue.compareTo(BigDecimal.valueOf(5000)) >= 0) {
|
|
||||||
flag5000Map.put(fid, 1);
|
|
||||||
processed5000ForCurrentId = true;
|
|
||||||
}
|
|
||||||
prevAccSerialNum = currentAccSerialNum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработка флага 90 дней
|
|
||||||
if (!processed90DaysForCurrentId) {
|
|
||||||
Integer currentFlag90 = flag90Days.get(fid);
|
|
||||||
|
|
||||||
if (currentFlag90 != null && currentFlag90 == 1) {
|
|
||||||
processed90DaysForCurrentId = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentFlag90 == null || currentFlag90 == 0) {
|
|
||||||
BigInteger days = getBigInteger(rs, "DAYS_PAST_DUE");
|
|
||||||
LocalDate reportedDate = rs.getObject("REPORTED_DT", LocalDate.class);
|
|
||||||
|
|
||||||
if (days != null) {
|
|
||||||
boolean has90daysFlag = days.compareTo(BigInteger.valueOf(90)) >= 0
|
|
||||||
&& reportedDate != null && !reportedDate.isBefore(yearAgo);
|
|
||||||
|
|
||||||
if (has90daysFlag) {
|
|
||||||
flag90Days.put(fid, 1);
|
|
||||||
processed90DaysForCurrentId = true;
|
|
||||||
} else {
|
|
||||||
flag90Days.put(fid, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flag90Days.put(fid, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
log.debug("Complete calculating flag 5000 and 90 days by RU_PASTDUEARREAR");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Выбирает данные из RU_PAYMT и ищет по ним флаги просрочек 90Days
|
|
||||||
* <p>
|
|
||||||
* flag90Days = 1, если выполняется хотя бы одно из условий:
|
|
||||||
* В INDIC.RU_PAYMT у данного FID есть запись с DAYS_PAST_DUE ≥ 90 и REPORTED_DT >= текущая дата – 12 месяцев.
|
|
||||||
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
|
||||||
*
|
|
||||||
* @param fids - отсортирован по возрастанию фидов
|
|
||||||
* @param flag90Days - рещультирующая мапа флагов просрочек 90_days
|
|
||||||
*/
|
|
||||||
private void findFlagsRuPaymt2(List<Integer> fids, Map<Integer, Integer> flag90Days) {
|
|
||||||
log.debug("Start calculating flag 90 days by RU_PAPAYMT");
|
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
||||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
return mapper.findFlag90ByRuPaymt(fids, yearAgo).stream()
|
||||||
params.addValue("fids", fids);
|
.collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag,
|
||||||
params.addValue("reportedDate", yearAgo);
|
(existing, replacement) -> {
|
||||||
jdbcTemplate.query(SELECT_RU_PAYMT_DATA, params, rs -> {
|
if (existing == 1) {
|
||||||
Integer currentFid = null;
|
return existing;
|
||||||
boolean processed90DaysForCurrentId = false;
|
|
||||||
|
|
||||||
while (rs.next()) {
|
|
||||||
Integer fid = rs.getInt("FID");
|
|
||||||
|
|
||||||
// Переход к новому fid. Сброс состояния
|
|
||||||
if (!fid.equals(currentFid)) {
|
|
||||||
currentFid = fid;
|
|
||||||
processed90DaysForCurrentId = false;
|
|
||||||
|
|
||||||
// Инициализируем значения по умолчанию
|
|
||||||
flag90Days.putIfAbsent(fid, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработка флага 90 дней
|
|
||||||
if (!processed90DaysForCurrentId) {
|
|
||||||
Integer currentFlag90 = flag90Days.get(fid);
|
|
||||||
|
|
||||||
if (currentFlag90 != null && currentFlag90 == 1) {
|
|
||||||
processed90DaysForCurrentId = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentFlag90 == null || currentFlag90 == 0) {
|
|
||||||
BigInteger days = getBigInteger(rs, "DAYS_PAST_DUE");
|
|
||||||
LocalDate date = rs.getObject("REPORTED_DT", LocalDate.class);
|
|
||||||
|
|
||||||
if (days != null) {
|
|
||||||
boolean has90daysFlag = days.compareTo(BigInteger.valueOf(90)) >= 0
|
|
||||||
&& date != null && !date.isBefore(yearAgo);
|
|
||||||
|
|
||||||
if (has90daysFlag) {
|
|
||||||
flag90Days.put(fid, 1);
|
|
||||||
processed90DaysForCurrentId = true;
|
|
||||||
} else {
|
} else {
|
||||||
flag90Days.put(fid, 0);
|
return replacement;
|
||||||
}
|
}
|
||||||
} else {
|
}));
|
||||||
flag90Days.put(fid, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
log.debug("Complete calculating flag 90 days by RU_PAPAYMT");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private BigInteger getBigInteger(ResultSet rs, String columnName) {
|
|
||||||
try {
|
|
||||||
String value = rs.getString(columnName);
|
|
||||||
return value != null ? new BigInteger(value) : null;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BigDecimal getBigDecimal(ResultSet rs, String columnName) {
|
|
||||||
try {
|
|
||||||
return rs.getBigDecimal(columnName);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|
@ -442,23 +107,8 @@ public class FlagsService {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@AllArgsConstructor
|
public static class FlagFidData {
|
||||||
@NoArgsConstructor
|
|
||||||
public static class RuPastDuarearData {
|
|
||||||
private Integer fid;
|
private Integer fid;
|
||||||
private BigInteger accSerialNum;
|
private Integer flag;
|
||||||
private LocalDate reportedDate;
|
|
||||||
private BigDecimal amtPastDue;
|
|
||||||
private BigInteger daysPastDue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public static class RuPaymtData {
|
|
||||||
private Integer fid;
|
|
||||||
private BigInteger daysPastDue;
|
|
||||||
private LocalDate reportedDate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.indic;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.entities.indic.PaymentsFlag;
|
|
||||||
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class FlagsService2 {
|
|
||||||
private final FlagsMapper flagsMapper;
|
|
||||||
|
|
||||||
public FlagsService2(FlagsMapper flagsMapper) {
|
|
||||||
this.flagsMapper = flagsMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, Integer> findFlagsDebt5000(List<Integer> fids) {
|
|
||||||
return flagsMapper.findFlagsDebt5000(fids).stream()
|
|
||||||
.collect(Collectors.toMap(PaymentsFlag::getFid, PaymentsFlag::getFlag));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, Integer> findFlag90ByPastDueArrear(List<Integer> fids, LocalDate date) {
|
|
||||||
return flagsMapper.findFlag90ByPastDueArrear(fids, date).stream()
|
|
||||||
.collect(Collectors.toMap(PaymentsFlag::getFid, PaymentsFlag::getFlag));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, Integer> findFlag90ByRuPaymt(List<Integer> fids, LocalDate date) {
|
|
||||||
return flagsMapper.findFlag90ByRuPaymt(fids, date).stream()
|
|
||||||
.collect(Collectors.toMap(PaymentsFlag::getFid, PaymentsFlag::getFlag));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
package ru.nbch.credit_tracker.service.indic;
|
package ru.nbch.credit_tracker.service.indic;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
@ -13,8 +7,13 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.mapper.indic.PersonMapper;
|
import ru.nbch.credit_tracker.mapper.indic.PersonMapper;
|
||||||
import ru.nbch.credit_tracker.model.IdData;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
import java.time.LocalDate;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
|
|
@ -52,22 +51,22 @@ public class PersonService {
|
||||||
private Map<Integer, NameData> findNameData(List<Integer> fids) {
|
private Map<Integer, NameData> findNameData(List<Integer> fids) {
|
||||||
List<NameData> persons = mapper.findNameData(fids);
|
List<NameData> persons = mapper.findNameData(fids);
|
||||||
return persons.stream()
|
return persons.stream()
|
||||||
.collect(Collectors.toMap(NameData::getFid, nameData -> nameData,
|
.collect(Collectors.toMap(NameData::getFid, nameData -> nameData,
|
||||||
(existing, replacement) -> {
|
(existing, replacement) -> {
|
||||||
LocalDate existingDate = existing.getFileSinceDate();
|
LocalDate existingDate = existing.getFileSinceDate();
|
||||||
LocalDate replacementDate = replacement.getFileSinceDate();
|
LocalDate replacementDate = replacement.getFileSinceDate();
|
||||||
if (existingDate != null && replacementDate != null) {
|
if (existingDate != null && replacementDate != null) {
|
||||||
if (existingDate.isAfter(replacementDate)) {
|
if (existingDate.isAfter(replacementDate)) {
|
||||||
return existing;
|
return existing;
|
||||||
} else {
|
} else {
|
||||||
return replacement;
|
return replacement;
|
||||||
}
|
}
|
||||||
} else if (existingDate != null) {
|
} else if (existingDate != null) {
|
||||||
return existing;
|
return existing;
|
||||||
} else {
|
} else {
|
||||||
return replacement;
|
return replacement;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Integer, PassportData> findPassportData(List<Integer> fids) {
|
private Map<Integer, PassportData> findPassportData(List<Integer> fids) {
|
||||||
|
|
@ -76,7 +75,7 @@ public class PersonService {
|
||||||
List<PassportData> passports = mapper.findPassportData(fids);
|
List<PassportData> passports = mapper.findPassportData(fids);
|
||||||
|
|
||||||
Map<Integer, List<PassportData>> passportsMap = passports.stream()
|
Map<Integer, List<PassportData>> passportsMap = passports.stream()
|
||||||
.collect(Collectors.groupingBy(PassportData::getFid));
|
.collect(Collectors.groupingBy(PassportData::getFid));
|
||||||
|
|
||||||
fids.forEach(fid -> {
|
fids.forEach(fid -> {
|
||||||
PassportData passport = findPassport(passportsMap.get(fid));
|
PassportData passport = findPassport(passportsMap.get(fid));
|
||||||
|
|
@ -88,44 +87,13 @@ public class PersonService {
|
||||||
return resultMap;
|
return resultMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void filledPassportsData(List<SubjectProfile> subjectProfiles) {
|
|
||||||
List<Integer> fids = subjectProfiles.stream().map(SubjectProfile::getFid).collect(Collectors.toList());
|
|
||||||
if (fids.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<PassportData> passports = mapper.findPassportData(fids);
|
|
||||||
|
|
||||||
Map<Integer, List<PassportData>> passportsMap = passports.stream()
|
|
||||||
.collect(Collectors.groupingBy(PassportData::getFid));
|
|
||||||
|
|
||||||
subjectProfiles.forEach(subjectProfile -> {
|
|
||||||
PassportData passport = findPassport(passportsMap.get(subjectProfile.getFid()));
|
|
||||||
if (passport != null) {
|
|
||||||
IdData idProfile = IdData.builder()
|
|
||||||
.serNum(passport.getSerNum())
|
|
||||||
.idNum(passport.getIdNum())
|
|
||||||
.issDate(passport.getIssDate())
|
|
||||||
.idType(passport.getIdType())
|
|
||||||
.idType2(passport.getIdType2())
|
|
||||||
.fileSinceDate(passport.getFileSinceDate())
|
|
||||||
.build();
|
|
||||||
subjectProfile.setIdData(idProfile);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isRequiredPassportDataPresent(PassportData passportData) {
|
|
||||||
boolean isDocTypeNotNull = StringUtils.isNotBlank(passportData.idType) || StringUtils.isNotBlank(passportData.idType2);
|
|
||||||
return StringUtils.isNotBlank(passportData.idNum) && isDocTypeNotNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PassportData findPassport(List<PassportData> passports) {
|
private PassportData findPassport(List<PassportData> passports) {
|
||||||
if (passports == null || passports.isEmpty()) {
|
if (passports == null || passports.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<PassportData> documents = passports.stream()
|
List<PassportData> documents = passports.stream()
|
||||||
.filter(this::isDUL)
|
.filter(this::isDUL)
|
||||||
.toList(); // берем только ДУЛ
|
.toList(); // берем только ДУЛ
|
||||||
|
|
||||||
if (documents.isEmpty()) {
|
if (documents.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -133,16 +101,16 @@ public class PersonService {
|
||||||
|
|
||||||
// Отдаем приоритет паспортам РФ
|
// Отдаем приоритет паспортам РФ
|
||||||
PassportData passport = documents.stream()
|
PassportData passport = documents.stream()
|
||||||
.filter(p -> "21".equals(p.getIdType2()) || "21".equals(p.getIdType()))
|
.filter(p -> "21".equals(p.getIdType2()) || "21".equals(p.getIdType()))
|
||||||
.sorted(
|
.sorted(
|
||||||
Comparator.comparing(
|
Comparator.comparing(
|
||||||
PassportData::getIssDate,
|
PassportData::getIssDate,
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
Comparator.nullsLast(Comparator.reverseOrder())
|
||||||
).thenComparing(
|
).thenComparing(
|
||||||
PassportData::getFileSinceDate,
|
PassportData::getFileSinceDate,
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
Comparator.nullsLast(Comparator.reverseOrder())
|
||||||
)
|
)
|
||||||
).findFirst().orElse(null);
|
).findFirst().orElse(null);
|
||||||
|
|
||||||
if (passport != null) {
|
if (passport != null) {
|
||||||
return passport;
|
return passport;
|
||||||
|
|
@ -150,15 +118,15 @@ public class PersonService {
|
||||||
|
|
||||||
// Если паспорт РФ не найден, смотри остальные ДУЛ'ы и берем первый
|
// Если паспорт РФ не найден, смотри остальные ДУЛ'ы и берем первый
|
||||||
passport = documents.stream()
|
passport = documents.stream()
|
||||||
.sorted(
|
.sorted(
|
||||||
Comparator.comparing(
|
Comparator.comparing(
|
||||||
PassportData::getIssDate,
|
PassportData::getIssDate,
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
Comparator.nullsLast(Comparator.reverseOrder())
|
||||||
).thenComparing(
|
).thenComparing(
|
||||||
PassportData::getFileSinceDate,
|
PassportData::getFileSinceDate,
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
Comparator.nullsLast(Comparator.reverseOrder())
|
||||||
)
|
)
|
||||||
).findFirst().orElse(null);
|
).findFirst().orElse(null);
|
||||||
return passport;
|
return passport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.indic;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.mapper.indic.PersonMapper;
|
|
||||||
import ru.nbch.credit_tracker.model.IdData;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class PersonServiceV2 {
|
|
||||||
|
|
||||||
private final PersonMapper mapper;
|
|
||||||
|
|
||||||
public PersonServiceV2(PersonMapper mapper) {
|
|
||||||
this.mapper = mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void filledPassportsData(List<SubjectProfile> subjectProfiles) {
|
|
||||||
List<Integer> fids = subjectProfiles.stream().map(SubjectProfile::getFid).collect(Collectors.toList());
|
|
||||||
if (fids.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<PersonService.PassportData> passports = mapper.findPassportData(fids);
|
|
||||||
|
|
||||||
Map<Integer, List<PersonService.PassportData>> passportsMap = passports.stream()
|
|
||||||
.collect(Collectors.groupingBy(PersonService.PassportData::getFid));
|
|
||||||
|
|
||||||
subjectProfiles.forEach(subjectProfile -> {
|
|
||||||
PersonService.PassportData passport = findPassport(passportsMap.get(subjectProfile.getFid()));
|
|
||||||
if (passport != null) {
|
|
||||||
IdData idProfile = IdData.builder()
|
|
||||||
.serNum(passport.getSerNum())
|
|
||||||
.idNum(passport.getIdNum())
|
|
||||||
.issDate(passport.getIssDate())
|
|
||||||
.idType(passport.getIdType())
|
|
||||||
.idType2(passport.getIdType2())
|
|
||||||
.fileSinceDate(passport.getFileSinceDate())
|
|
||||||
.build();
|
|
||||||
subjectProfile.setIdData(idProfile);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo подлежит рефакторингу
|
|
||||||
private PersonService.PassportData findPassport(List<PersonService.PassportData> passports) {
|
|
||||||
if (passports == null || passports.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<PersonService.PassportData> documents = passports.stream()
|
|
||||||
.filter(this::isDUL)
|
|
||||||
.toList(); // берем только ДУЛ
|
|
||||||
|
|
||||||
if (documents.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Отдаем приоритет паспортам РФ
|
|
||||||
PersonService.PassportData passport = documents.stream()
|
|
||||||
.filter(p -> "21".equals(p.getIdType2()) || "21".equals(p.getIdType()))
|
|
||||||
.sorted(
|
|
||||||
Comparator.comparing(
|
|
||||||
PersonService.PassportData::getIssDate,
|
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
|
||||||
).thenComparing(
|
|
||||||
PersonService.PassportData::getFileSinceDate,
|
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
|
||||||
)
|
|
||||||
).findFirst().orElse(null);
|
|
||||||
|
|
||||||
if (passport != null) {
|
|
||||||
return passport;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если паспорт РФ не найден, смотри остальные ДУЛ'ы и берем первый
|
|
||||||
passport = documents.stream()
|
|
||||||
.sorted(
|
|
||||||
Comparator.comparing(
|
|
||||||
PersonService.PassportData::getIssDate,
|
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
|
||||||
).thenComparing(
|
|
||||||
PersonService.PassportData::getFileSinceDate,
|
|
||||||
Comparator.nullsLast(Comparator.reverseOrder())
|
|
||||||
)
|
|
||||||
).findFirst().orElse(null);
|
|
||||||
return passport;
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo подлежит рефакторингу;
|
|
||||||
private boolean isDUL(PersonService.PassportData p) {
|
|
||||||
Integer idType;
|
|
||||||
Double idType2;
|
|
||||||
try {
|
|
||||||
idType = p.getIdType() != null ? Integer.parseInt(p.getIdType()) : null;
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
idType = null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
idType2 = p.getIdType2() != null ? Double.valueOf(p.getIdType2()) : null;
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
idType2 = null;
|
|
||||||
}
|
|
||||||
return (idType != null && idType <= 30 && idType != 12) || (idType2 != null && (idType2 >= 1 || idType2 <= 999));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,269 +1,58 @@
|
||||||
package ru.nbch.credit_tracker.service.indic;
|
package ru.nbch.credit_tracker.service.indic;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
|
import ru.nbch.credit_tracker.mapper.indic.PhoneMapper;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
|
||||||
import ru.nbch.credit_tracker.entities.indic.Name;
|
|
||||||
import ru.nbch.credit_tracker.repository.PhoneRepository;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
@Service
|
||||||
@Deprecated
|
|
||||||
//todo оставил для временного подсмотреть на старую логику
|
|
||||||
public class PhoneService {
|
public class PhoneService {
|
||||||
|
|
||||||
private final PhoneRepository phoneRepository;
|
private final PhoneMapper mapper;
|
||||||
|
|
||||||
public PhoneService(PhoneRepository phoneRepository) {
|
public PhoneService(PhoneMapper mapper) {
|
||||||
this.phoneRepository = phoneRepository;
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ищет фиды по номерам телефона
|
* Ищет фиды по номерам телефона
|
||||||
*
|
* @return Map: key - номер телефона; value - fid
|
||||||
* @return Map: key - fid; value - {@link PhoneFidMap}
|
|
||||||
*/
|
*/
|
||||||
public Map<Integer, PhoneFidMap> defineFidByPhone(List<PhoneFidMap> subjects) {
|
public Map<String, Integer> findFidsPhoneData(List<PhoneFidMap> subjects) {
|
||||||
List<String> phones = subjects.stream().
|
List<String> phones = subjects.stream().map(subject -> "9" + subject.getPhone()).toList();
|
||||||
map(subject -> "9" + subject.getPhone())
|
return convertFidsDataToMap(mapper.findFids(phones));
|
||||||
.toList();
|
|
||||||
|
|
||||||
subjects.sort(
|
|
||||||
Comparator.comparing(
|
|
||||||
PhoneFidMap::getPhone,
|
|
||||||
Comparator.naturalOrder()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<PhoneRepository.FidsDataLong> phonesByFid = phoneRepository.findFidsLong(phones);
|
|
||||||
|
|
||||||
log.debug("Start merging fids");
|
|
||||||
Map<Integer, PhoneFidMap> phoneFidMap = merger(subjects, phonesByFid);
|
|
||||||
log.debug("End merging fids");
|
|
||||||
|
|
||||||
return phoneFidMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Integer, PhoneFidMap> merger(List<PhoneFidMap> subjects, List<PhoneRepository.FidsDataLong> phonesByFid) {
|
private Map<String, Integer> convertFidsDataToMap(List<FidsData> fidsData) {
|
||||||
Map<Integer, PhoneFidMap> phoneFidMap = new HashMap<>();
|
if (fidsData == null || fidsData.isEmpty()) {
|
||||||
|
return new HashMap<>();
|
||||||
if (phonesByFid.isEmpty()) {
|
|
||||||
return phoneFidMap;
|
|
||||||
}
|
}
|
||||||
|
return fidsData.stream()
|
||||||
int index = 0;
|
.collect(Collectors.groupingBy(
|
||||||
for (PhoneFidMap subject : subjects) {
|
FidsData::getPhone,
|
||||||
Long normalizedPhone = Long.parseLong("9" + subject.getPhone());
|
Collectors.collectingAndThen(
|
||||||
|
Collectors.maxBy(
|
||||||
while (index < phonesByFid.size()) {
|
Comparator.comparing(FidsData::getFileSinceDate)
|
||||||
PhoneRepository.FidsDataLong currentFidData = phonesByFid.get(index);
|
.thenComparing(FidsData::getFid)
|
||||||
|
),
|
||||||
if (currentFidData.getPhone() < normalizedPhone) {
|
data -> data.map(FidsData::getFid).orElse(null)
|
||||||
index++;
|
)
|
||||||
continue;
|
));
|
||||||
}
|
|
||||||
|
|
||||||
if (currentFidData.getPhone().equals(normalizedPhone)) {
|
|
||||||
phoneFidMap.put(currentFidData.getFid(), subject);
|
|
||||||
index++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index >= phonesByFid.size()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return phoneFidMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defineFidsAndNameByPhone2(List<PhoneFidMap> subjects) {
|
@Getter
|
||||||
List<String> phones = subjects.stream().
|
@Setter
|
||||||
map(subject -> "9" + subject.getPhone())
|
public static class FidsData {
|
||||||
.toList();
|
private Integer fid;
|
||||||
|
private String phone;
|
||||||
subjects.sort(
|
private LocalDate fileSinceDate;
|
||||||
Comparator.comparing(
|
|
||||||
PhoneFidMap::getPhone,
|
|
||||||
Comparator.naturalOrder()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<PhoneRepository.FidsDataWithName> phonesByFid = phoneRepository.findFidsWithName(phones);
|
|
||||||
|
|
||||||
log.debug("Start merging fids and names");
|
|
||||||
Map<Integer, List<PhoneRepository.FidsDataWithName>> fidFidsDataMap = phonesByFid.stream()
|
|
||||||
.collect(Collectors.groupingBy(PhoneRepository.FidsDataWithName::getFid));
|
|
||||||
|
|
||||||
Map<String, Integer> phoneToFidsMap = new HashMap<>();
|
|
||||||
for (PhoneRepository.FidsDataWithName fidsData : phonesByFid) {
|
|
||||||
if (!phoneToFidsMap.containsKey(fidsData.getPhone())) {
|
|
||||||
phoneToFidsMap.put(fidsData.getPhone(), fidsData.getFid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (PhoneFidMap phoneFid : subjects) {
|
|
||||||
String phone = "9" + phoneFid.getPhone();
|
|
||||||
Integer fid = phoneToFidsMap.get(phone);
|
|
||||||
if (fid != null) {
|
|
||||||
phoneFid.setFid(fid);
|
|
||||||
|
|
||||||
List<PhoneRepository.FidsDataWithName> fidsDataWithNames = fidFidsDataMap.get(fid);
|
|
||||||
if (fidsDataWithNames != null) {
|
|
||||||
PhoneRepository.FidsDataWithName nameData = defineNameData(fidsDataWithNames);
|
|
||||||
|
|
||||||
if (nameData != null) {
|
|
||||||
phoneFid.setFirstName(nameData.getFirstName());
|
|
||||||
phoneFid.setMiddleName(nameData.getMiddleName());
|
|
||||||
phoneFid.setLastName(nameData.getLastName());
|
|
||||||
phoneFid.setBirthDate(nameData.getBirthDate());
|
|
||||||
phoneFid.setFileSinceDate(nameData.getFileSinceDateName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
phoneToFidsMap.remove(phone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.debug("End merging fids and names");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
private PhoneRepository.FidsDataWithName defineNameData(List<PhoneRepository.FidsDataWithName> dataList) {
|
|
||||||
PhoneRepository.FidsDataWithName currentData = null;
|
|
||||||
for (PhoneRepository.FidsDataWithName fidsData : dataList) {
|
|
||||||
if (currentData == null) {
|
|
||||||
currentData = fidsData;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
LocalDate currentDate = currentData.getFileSinceDateName();
|
|
||||||
LocalDate newDate = fidsData.getFileSinceDateName();
|
|
||||||
if (currentDate != null && newDate != null) {
|
|
||||||
if (currentDate.isBefore(newDate)) {
|
|
||||||
currentData = fidsData;
|
|
||||||
}
|
|
||||||
} else if (currentDate == null) {
|
|
||||||
currentData = fidsData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentData;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Name defineNameDataV2(List<Name> dataList) {
|
|
||||||
Name currentData = null;
|
|
||||||
for (Name fidsData : dataList) {
|
|
||||||
if (currentData == null) {
|
|
||||||
currentData = fidsData;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
LocalDate currentDate = currentData.getFileSinceDate();
|
|
||||||
LocalDate newDate = fidsData.getFileSinceDate();
|
|
||||||
if (currentDate != null && newDate != null) {
|
|
||||||
if (currentDate.isBefore(newDate)) {
|
|
||||||
currentData = fidsData;
|
|
||||||
}
|
|
||||||
} else if (currentDate == null) {
|
|
||||||
currentData = fidsData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Integer, PhoneFidMap> merger2(List<PhoneFidMap> subjects, List<PhoneRepository.FidsData> phonesByFid) {
|
|
||||||
Map<Integer, PhoneFidMap> phoneFidMap = new HashMap<>();
|
|
||||||
Iterator<PhoneRepository.FidsData> iterator = phonesByFid.iterator();
|
|
||||||
String lastUniquePhone = null;
|
|
||||||
PhoneRepository.FidsData fidsData = null;
|
|
||||||
for (PhoneFidMap phoneFid : subjects) {
|
|
||||||
String normalizedPhone = 9 + phoneFid.getPhone();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
fidsData = iterator.next();
|
|
||||||
if (StringUtils.isNotEmpty(lastUniquePhone) && lastUniquePhone.equals(fidsData.getPhone())) {
|
|
||||||
iterator.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (fidsData.getPhone().equals(normalizedPhone) || normalizedPhone.equals(lastUniquePhone)) {
|
|
||||||
lastUniquePhone = fidsData.getPhone();
|
|
||||||
iterator.remove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastUniquePhone = fidsData.getPhone();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fidsData != null && normalizedPhone.equals(lastUniquePhone)) {
|
|
||||||
phoneFidMap.put(fidsData.getFid(), phoneFid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return phoneFidMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ищет фиды по номерам телефона. Обогащает {@link PhoneFidMap} для найденных фидов данными из Name и фидом.
|
|
||||||
* @return Map: key - FID, value - {@link PhoneFidMap}
|
|
||||||
*/
|
|
||||||
public Map<Integer, PhoneFidMap> defineFidsAndNameByPhone(List<PhoneFidMap> subjects) {
|
|
||||||
Map<Integer, PhoneFidMap> phoneFidMap = new HashMap<>();
|
|
||||||
|
|
||||||
List<String> phones = subjects.stream().
|
|
||||||
map(subject -> "9" + subject.getPhone())
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
subjects.sort(
|
|
||||||
Comparator.comparing(
|
|
||||||
PhoneFidMap::getPhone,
|
|
||||||
Comparator.naturalOrder()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<PhoneRepository.FidsDataWithName> phonesByFid = phoneRepository.findFidsWithName(phones);
|
|
||||||
|
|
||||||
log.debug("Start merging fids and names");
|
|
||||||
Map<Integer, List<PhoneRepository.FidsDataWithName>> fidFidsDataMap = phonesByFid.stream()
|
|
||||||
.collect(Collectors.groupingBy(PhoneRepository.FidsDataWithName::getFid));
|
|
||||||
|
|
||||||
Map<String, Integer> phoneToFidsMap = new HashMap<>();
|
|
||||||
for (PhoneRepository.FidsDataWithName fidsData : phonesByFid) {
|
|
||||||
if (!phoneToFidsMap.containsKey(fidsData.getPhone())) {
|
|
||||||
phoneToFidsMap.put(fidsData.getPhone(), fidsData.getFid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (PhoneFidMap phoneFid : subjects) {
|
|
||||||
String phone = "9" + phoneFid.getPhone();
|
|
||||||
Integer fid = phoneToFidsMap.get(phone);
|
|
||||||
if (fid != null) {
|
|
||||||
phoneFid.setFid(fid);
|
|
||||||
|
|
||||||
List<PhoneRepository.FidsDataWithName> fidsDataWithNames = fidFidsDataMap.get(fid);
|
|
||||||
if (fidsDataWithNames != null) {
|
|
||||||
PhoneRepository.FidsDataWithName nameData = defineNameData(fidsDataWithNames);
|
|
||||||
|
|
||||||
if (nameData != null) {
|
|
||||||
phoneFid.setFirstName(nameData.getFirstName());
|
|
||||||
phoneFid.setMiddleName(nameData.getMiddleName());
|
|
||||||
phoneFid.setLastName(nameData.getLastName());
|
|
||||||
phoneFid.setBirthDate(nameData.getBirthDate());
|
|
||||||
phoneFid.setFileSinceDate(nameData.getFileSinceDateName());
|
|
||||||
}
|
|
||||||
|
|
||||||
fidFidsDataMap.remove(fid);
|
|
||||||
}
|
|
||||||
phoneFidMap.put(fid, phoneFid); // TODO можно перезатереть запись если у разных phone нашлись одинаковые фиды
|
|
||||||
phoneToFidsMap.remove(phone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.debug("End merging fids and names");
|
|
||||||
|
|
||||||
return phoneFidMap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.indic;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.BinaryOperator;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.entities.indic.Name;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.repository.PhoneRepository;
|
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class PhoneService2 {
|
|
||||||
|
|
||||||
private final PhoneRepository phoneRepository;
|
|
||||||
private final Comparator<Name> byDateThenIdNullSafe =
|
|
||||||
Comparator.comparing(Name::getFileSinceDate, Comparator.nullsFirst(Comparator.naturalOrder()))
|
|
||||||
.thenComparing(Name::getFid);
|
|
||||||
|
|
||||||
public PhoneService2(PhoneRepository phoneRepository) {
|
|
||||||
this.phoneRepository = phoneRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск данных по таблицам PHONE_NORM и NAME по списку номеров телефонов
|
|
||||||
* @param subjects
|
|
||||||
* @return - отображение NAME к номеру телефону, отфильтрованному по логике
|
|
||||||
* FID с максимальным значением FILE_SINCE_DT. Если FILE_SINCE_DT оказался одинаковый, берется максимальный FID
|
|
||||||
*/
|
|
||||||
public Map<String, Name> findNameByNumber(List<SubjectProfile> subjects) {
|
|
||||||
List<String> phones = subjects.stream()
|
|
||||||
.map(subject -> CTUtil.normalizePhoneNumber(subject.getPhone()))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
List<Name> names = phoneRepository.findNameByPhones(phones);
|
|
||||||
|
|
||||||
return names.stream()
|
|
||||||
.collect(Collectors.toMap(
|
|
||||||
Name::getNumber,
|
|
||||||
Function.identity(),
|
|
||||||
BinaryOperator.maxBy(byDateThenIdNullSafe)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package ru.nbch.credit_tracker.service.signal;
|
package ru.nbch.credit_tracker.service.signal;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.entities.app.Hit;
|
import ru.nbch.credit_tracker.entities.dto.Hit;
|
||||||
import ru.nbch.credit_tracker.mapper.signal.HitsMapper;
|
import ru.nbch.credit_tracker.mapper.signal.HitsMapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
||||||
|
|
@ -1,84 +1,33 @@
|
||||||
package ru.nbch.credit_tracker.service.signal;
|
package ru.nbch.credit_tracker.service.signal;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import org.apache.ibatis.session.ExecutorType;
|
|
||||||
import org.apache.ibatis.session.SqlSession;
|
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
import ru.nbch.credit_tracker.entities.indic.Name;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject;
|
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.Subject;
|
||||||
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PhoneFidMapService {
|
public class PhoneFidMapService {
|
||||||
|
|
||||||
private final PhoneFidMapMapper mapper;
|
private final PhoneFidMapMapper mapper;
|
||||||
private final SqlSessionFactory sqlSessionFactory;
|
|
||||||
|
|
||||||
public PhoneFidMapService(PhoneFidMapMapper mapper,
|
public PhoneFidMapService(PhoneFidMapMapper mapper) {
|
||||||
@Qualifier("sqlSessionSignal") SqlSessionFactory sqlSessionFactory) {
|
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
this.sqlSessionFactory = sqlSessionFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void registerSubjects(List<Subject> subjects, Long packageId) {
|
public void registerSubjects(List<Subject> subjects, Long packageId) {
|
||||||
mapper.registerSubjects(subjects, packageId);
|
mapper.registerSubjects(subjects, packageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public List<PhoneFidMap> findFullPhoneFidMap(Long packageId, int offset, int limit) {
|
||||||
* Регистрирует в базе список субъектов переданных в запросе
|
|
||||||
*
|
|
||||||
* @param subjects - список субъектов
|
|
||||||
* @param packageId - уникальный идентификатор пакета
|
|
||||||
*/
|
|
||||||
public void register(List<SubjectProfile> subjects, Map<String, Name> nameByPhone, Long packageId) {
|
|
||||||
List<PhoneFidMap> phoneFidMaps = subjects.stream().map(subjectProfile -> {
|
|
||||||
Integer fid = Optional
|
|
||||||
.ofNullable(nameByPhone.get(CTUtil.normalizePhoneNumber(subjectProfile.getPhone())))
|
|
||||||
.map(Name::getFid)
|
|
||||||
.orElse(null);
|
|
||||||
|
|
||||||
return PhoneFidMap.builder()
|
|
||||||
.phone(subjectProfile.getPhone())
|
|
||||||
.subjectId(subjectProfile.getIdentifier())
|
|
||||||
.packageId(packageId)
|
|
||||||
.fid(fid)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
).toList();
|
|
||||||
mapper.register(phoneFidMaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<PhoneFidMap> findFullPhoneFidMap(Long packageId, int offset, int limit) {
|
|
||||||
return mapper.findFullPhoneFidMap(packageId, offset, limit);
|
return mapper.findFullPhoneFidMap(packageId, offset, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePhoneFidMaps(Collection<PhoneFidMap> subjects) {
|
public void updatePhoneFidMaps(List<PhoneFidMap> subjects) {
|
||||||
mapper.updatePhoneFidMaps(subjects);
|
mapper.updatePhoneFidMaps(subjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePhoneFidMaps2(Collection<PhoneFidMap> subjects) {
|
|
||||||
final int batchSize = 1000;
|
|
||||||
try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
|
|
||||||
PhoneFidMapMapper mapper = session.getMapper(PhoneFidMapMapper.class);
|
|
||||||
int i = 0;
|
|
||||||
for (PhoneFidMap s : subjects) {
|
|
||||||
mapper.updateOne(s);
|
|
||||||
if (++i % batchSize == 0) session.flushStatements();
|
|
||||||
}
|
|
||||||
session.flushStatements();
|
|
||||||
session.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updatePhoneFidMapsErrors(List<PhoneFidMap> subjects) {
|
public void updatePhoneFidMapsErrors(List<PhoneFidMap> subjects) {
|
||||||
mapper.updatePhoneFidMapsErrors(subjects);
|
mapper.updatePhoneFidMapsErrors(subjects);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,6 @@ public class SignalRestService {
|
||||||
*/
|
*/
|
||||||
public boolean setupMonitoring(Long packageId) throws Exception {
|
public boolean setupMonitoring(Long packageId) throws Exception {
|
||||||
String path = signalService.writeSignals(packageId);
|
String path = signalService.writeSignals(packageId);
|
||||||
return setupMonitoring(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean setupMonitoring(String path) throws Exception {
|
|
||||||
Resource request = compressFile(path);
|
Resource request = compressFile(path);
|
||||||
|
|
||||||
MultiValueMap<String, Resource> body = new LinkedMultiValueMap<>();
|
MultiValueMap<String, Resource> body = new LinkedMultiValueMap<>();
|
||||||
|
|
@ -99,6 +95,8 @@ public class SignalRestService {
|
||||||
} else {
|
} else {
|
||||||
log.error("неизвестная ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", response.getBody());
|
log.error("неизвестная ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", response.getBody());
|
||||||
}
|
}
|
||||||
|
CTUtil.removeFile(path);
|
||||||
|
CTUtil.removeFile(path + ".gz");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package ru.nbch.credit_tracker.service.signal;
|
package ru.nbch.credit_tracker.service.signal;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.dto.UserPackage;
|
||||||
import ru.nbch.credit_tracker.enums.Status;
|
import ru.nbch.credit_tracker.enums.Status;
|
||||||
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
|
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task;
|
|
||||||
|
|
||||||
public interface Handler<X, Z> {
|
|
||||||
Z handle(X taskPayload);
|
|
||||||
default int preferredConcurrency() {return 10;}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
|
|
||||||
|
|
||||||
public class Pipeline {
|
|
||||||
private Runnable starter;
|
|
||||||
private IPipeLineTerminator<?,?> terminator;
|
|
||||||
private List<Stage<?, ?>> stages;
|
|
||||||
|
|
||||||
public Pipeline() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stage<?, ?> getLast() {
|
|
||||||
return stages.getLast();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Runnable getStarter() {
|
|
||||||
return starter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStarter(Runnable starter) {
|
|
||||||
this.starter = starter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IPipeLineTerminator<?, ?> getTerminator() {
|
|
||||||
return terminator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTerminator(IPipeLineTerminator<?, ?> terminator) {
|
|
||||||
this.terminator = terminator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Stage<?, ?>> getStages() {
|
|
||||||
return stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStages(List<Stage<?, ?>> stages) {
|
|
||||||
this.stages = stages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.config.task.StageQueueFactory;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.PartFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
|
||||||
import ru.nbch.credit_tracker.service.task.impl.FidIdEnricher;
|
|
||||||
import ru.nbch.credit_tracker.service.task.impl.FlagsEnricherV2;
|
|
||||||
import ru.nbch.credit_tracker.service.task.impl.SaveSubjectHandler;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineStarter;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.PipeLineBuilderV2;
|
|
||||||
import ru.nbch.credit_tracker.utils.LogUtil;
|
|
||||||
import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
public class PipelinePackageManager {
|
|
||||||
private final SignalRestService signalRestService;
|
|
||||||
private final FlagsEnricherV2 flagsEnricherV2;
|
|
||||||
private final StageQueueFactory<SubjectPayload> saveSubjectQueueFactory;
|
|
||||||
private final StageQueueFactory<SubjectPayload> idEnricherQueueFactory;
|
|
||||||
private final StageQueueFactory<PartFilePayload> sendSignalQueueFactory;
|
|
||||||
private final SaveSubjectHandler saveSubjectHandler;
|
|
||||||
private final FidIdEnricher fidIdEnricherHandler;
|
|
||||||
private final Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory;
|
|
||||||
private final BiFunction<Long, String, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory;
|
|
||||||
private final CreditTrackerSettings creditTrackerSettings;
|
|
||||||
private final ExecutorService executorService = Executors.newFixedThreadPool(10, r -> {
|
|
||||||
Thread t = new Thread(r);
|
|
||||||
t.setName("pipe-starter-%d".formatted(t.threadId()));
|
|
||||||
return t;
|
|
||||||
});
|
|
||||||
private final Semaphore semaphore;
|
|
||||||
private final static int MAX_PARALLEL_REQUESTS = 3;
|
|
||||||
|
|
||||||
public PipelinePackageManager(SignalRestService signalRestService,
|
|
||||||
@Qualifier("saveSubjectQueueFactory") StageQueueFactory<SubjectPayload> saveSubjectQueueFactory,
|
|
||||||
@Qualifier("idEnricherQueueFactory") StageQueueFactory<SubjectPayload> idEnricherQueueFactory,
|
|
||||||
@Qualifier("partFileQueueFactory") StageQueueFactory<PartFilePayload> sendSignalQueueFactory,
|
|
||||||
SaveSubjectHandler saveSubjectHandler, FidIdEnricher fidIdEnricherHandler,
|
|
||||||
Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory,
|
|
||||||
BiFunction<Long, String, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory,
|
|
||||||
FlagsEnricherV2 flagsEnricherV2,
|
|
||||||
CreditTrackerSettings creditTrackerSettings) {
|
|
||||||
this.signalRestService = signalRestService;
|
|
||||||
this.saveSubjectQueueFactory = saveSubjectQueueFactory;
|
|
||||||
this.idEnricherQueueFactory = idEnricherQueueFactory;
|
|
||||||
this.sendSignalQueueFactory = sendSignalQueueFactory;
|
|
||||||
this.saveSubjectHandler = saveSubjectHandler;
|
|
||||||
this.fidIdEnricherHandler = fidIdEnricherHandler;
|
|
||||||
this.pipelineTerminatorFactory = pipelineTerminatorFactory;
|
|
||||||
this.pipelineStarterFactory = pipelineStarterFactory;
|
|
||||||
this.flagsEnricherV2 = flagsEnricherV2;
|
|
||||||
this.creditTrackerSettings = creditTrackerSettings;
|
|
||||||
this.semaphore = new Semaphore(MAX_PARALLEL_REQUESTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildAndRun(Long packageId, String pkgPath) throws Exception {
|
|
||||||
if (!semaphore.tryAcquire()) {
|
|
||||||
throw new RuntimeException("Too many concurrent requests");
|
|
||||||
}
|
|
||||||
log.info("throttler permits after acquire: {}", semaphore.availablePermits());
|
|
||||||
try {
|
|
||||||
Pipeline pipeline = PipeLineBuilderV2.first(saveSubjectQueueFactory.getObject(), idEnricherQueueFactory.getObject())
|
|
||||||
.handler(saveSubjectHandler)
|
|
||||||
.poison(SubjectPayload.POISON)
|
|
||||||
.handlerResult(flagsEnricherV2)
|
|
||||||
.andThen()
|
|
||||||
.stage(sendSignalQueueFactory.getObject())
|
|
||||||
.handler(fidIdEnricherHandler)
|
|
||||||
.poison(PartFilePayload.POISON)
|
|
||||||
.andThen()
|
|
||||||
.fillInitialQueue(pipelineStarterFactory.apply(packageId, pkgPath))
|
|
||||||
.pollFinishingQueue(pipelineTerminatorFactory.get())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
executorService.submit(LogUtil.wrap(LogUtil.extractMdcMap(), pipeline.getStarter()));
|
|
||||||
executorService.submit(LogUtil.wrap(LogUtil.extractMdcMap(), pipeline.getTerminator()));
|
|
||||||
|
|
||||||
pipeline.getTerminator()
|
|
||||||
.doneFuture()
|
|
||||||
.orTimeout(creditTrackerSettings.getTimeout(), TimeUnit.MINUTES)
|
|
||||||
.whenComplete((v, e) -> {
|
|
||||||
try {
|
|
||||||
if (e != null) {
|
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SignalXmlFilePayload res = (SignalXmlFilePayload) v;
|
|
||||||
log.trace("Signal file by path: {} is completed", res.getSignalXmlFilePath());
|
|
||||||
// signalRestService.setupMonitoring(res.getSignalXmlFilePath().toString());
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.error("pipeline finished with error{}", ExceptionUtils.getStackTrace(ex));
|
|
||||||
} finally {
|
|
||||||
log.info("packageId={}: pipeline finished", packageId);
|
|
||||||
pipeline.getStages().forEach(Stage::close);
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
semaphore.release();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,174 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
import ru.nbch.credit_tracker.utils.LogUtil;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class Stage<X extends StagePayload, Z extends StagePayload> implements Runnable {
|
|
||||||
private final Handler<X, Z> dispatcher;
|
|
||||||
private final BlockingQueue<X> in;
|
|
||||||
private final BlockingQueue<Z> out;
|
|
||||||
private final Z POISON;
|
|
||||||
private final ExecutorService ioPool;
|
|
||||||
private Consumer<Z> consumer = null;
|
|
||||||
private final String dispatcherName;
|
|
||||||
|
|
||||||
private static final ThreadPoolExecutor.CallerRunsPolicy callerRunsPolicy
|
|
||||||
= new ThreadPoolExecutor.CallerRunsPolicy();
|
|
||||||
|
|
||||||
public Stage(Handler<X, Z> dispatcher,
|
|
||||||
BlockingQueue<X> in,
|
|
||||||
BlockingQueue<Z> out,
|
|
||||||
Z POISON) {
|
|
||||||
this.dispatcher = dispatcher;
|
|
||||||
this.in = in;
|
|
||||||
this.out = out;
|
|
||||||
this.dispatcherName = dispatcher.getClass().getSimpleName();
|
|
||||||
var mdcMap = LogUtil.extractMdcMap();
|
|
||||||
this.ioPool = new ThreadPoolExecutor(dispatcher.preferredConcurrency(),
|
|
||||||
dispatcher.preferredConcurrency(),
|
|
||||||
0L, TimeUnit.MINUTES,
|
|
||||||
new LinkedBlockingQueue<>(1),
|
|
||||||
r -> {
|
|
||||||
Thread t = new Thread(LogUtil.wrap(mdcMap, r));
|
|
||||||
t.setName("pipe-handler-%s-%d".formatted(dispatcherName, t.threadId()));
|
|
||||||
return t;
|
|
||||||
},
|
|
||||||
(r, executor) -> {
|
|
||||||
log.info("stage {}: all threads are working; switch to CallerRunsPolicy", dispatcherName);
|
|
||||||
callerRunsPolicy.rejectedExecution(r, executor);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this.POISON = POISON;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startRunning() {
|
|
||||||
ioPool.submit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
List<Future<Z>> inflight = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
int counter = 0;
|
|
||||||
while (true) {
|
|
||||||
X b = takeQuiet(in, Duration.ofSeconds(5));
|
|
||||||
if (wasInterrupted()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (b == null) continue;
|
|
||||||
if (b.isPoison()) {
|
|
||||||
log.info("Got poison");
|
|
||||||
// дождаться всех in-flight задач
|
|
||||||
for (Future<Z> f : inflight) {
|
|
||||||
if (wasInterrupted()) {
|
|
||||||
log.info("stage {} was interrupted while waiting for tasks to finish",
|
|
||||||
dispatcher.getClass().getSimpleName());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
f.get();
|
|
||||||
}
|
|
||||||
putQuiet(out, POISON);
|
|
||||||
log.info("stage {} finished.", dispatcher.getClass().getSimpleName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
counter++;
|
|
||||||
int finalCounter = counter;
|
|
||||||
Future<Z> f = ioPool.submit(() -> {
|
|
||||||
try {
|
|
||||||
if (wasInterrupted()) {
|
|
||||||
log.info("stage {} task {} interrupted...", dispatcher.getClass().getSimpleName(), finalCounter);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
log.info("stage {} task {} started.", dispatcher.getClass().getSimpleName(), finalCounter);
|
|
||||||
Z p = dispatcher.handle(b);
|
|
||||||
putQuiet(out, p);
|
|
||||||
log.info("stage {} task {} ended.", dispatcher.getClass().getSimpleName(), finalCounter);
|
|
||||||
return p;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("{} ERROR: {}", dispatcherName, ExceptionUtils.getStackTrace(e));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
inflight.add(f);
|
|
||||||
if ((counter % 20) == 0) {
|
|
||||||
inflight.removeIf(Future::isDone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error for {}: {}; {}", dispatcherName, info(), ExceptionUtils.getStackTrace(e));
|
|
||||||
putQuiet(out, POISON);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String info() {
|
|
||||||
ThreadPoolExecutor casted = (ThreadPoolExecutor) ioPool;
|
|
||||||
return "executor active tasks: %d; queue size: %d, completed tasks: %d".formatted(
|
|
||||||
casted.getActiveCount(),
|
|
||||||
casted.getQueue().size(),
|
|
||||||
casted.getCompletedTaskCount()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean wasInterrupted() {
|
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
|
||||||
log.warn("pipeline was interrupted...");
|
|
||||||
putQuiet(out, POISON);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
log.info("Stage {} is getting shutdown", dispatcher.getClass().getSimpleName());
|
|
||||||
ioPool.shutdownNow(); // прерываем обработчики
|
|
||||||
}
|
|
||||||
|
|
||||||
void putQuiet(BlockingQueue<Z> q, Z b) {
|
|
||||||
try {
|
|
||||||
if (consumer != null) {
|
|
||||||
consumer.accept(b);
|
|
||||||
}
|
|
||||||
q.put(b);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.error("Error for {}: {}; {}", dispatcherName, info(), ExceptionUtils.getStackTrace(e));
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
X takeQuiet(BlockingQueue<X> q, Duration timeout) {
|
|
||||||
try {
|
|
||||||
return q.poll(timeout.toMillis(), TimeUnit.MILLISECONDS);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.error("Error for {}: {}; {}", dispatcherName, info(), ExceptionUtils.getStackTrace(e));
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockingQueue<X> getIn() {
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Consumer<Z> getConsumer() {
|
|
||||||
return consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConsumer(Consumer<Z> consumer) {
|
|
||||||
this.consumer = consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.impl;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.builder.PersonFactoryBuilderV2;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Person;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.PartFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.PersonServiceV2;
|
|
||||||
import ru.nbch.credit_tracker.service.task.Handler;
|
|
||||||
import ru.nbch.credit_tracker.service.xml.stax.SignalsStaxXmlWriterV2;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
public class FidIdEnricher implements Handler<SubjectPayload, PartFilePayload> {
|
|
||||||
private final PersonServiceV2 personService;
|
|
||||||
private final CreditTrackerSettings config;
|
|
||||||
|
|
||||||
public FidIdEnricher(PersonServiceV2 personService,
|
|
||||||
CreditTrackerSettings config) {
|
|
||||||
this.personService = personService;
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PartFilePayload handle(SubjectPayload taskPayload) {
|
|
||||||
List<SubjectProfile> subjectsProfile = taskPayload.getSubjects();
|
|
||||||
log.debug("FidIdEnricher handle by packageId: {}; size: {}", taskPayload.getPackageId(), subjectsProfile.size());
|
|
||||||
personService.filledPassportsData(subjectsProfile);
|
|
||||||
List<Person> personOnProcessing = subjectsProfile.stream()
|
|
||||||
.filter(subjectProfile -> subjectProfile.getIdData() != null && subjectProfile.getNameData() != null)
|
|
||||||
.map(subjectProfile -> PersonFactoryBuilderV2.builder().personData(subjectProfile).build())
|
|
||||||
.toList();
|
|
||||||
log.debug("personOnProcessing size: {}", personOnProcessing.size());
|
|
||||||
Long packageId = taskPayload.getPackageId();
|
|
||||||
Path partPath = writeSignals(personOnProcessing, packageId);
|
|
||||||
return new PartFilePayload(partPath, packageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path writeSignals(List<Person> persons, Long packageId) {
|
|
||||||
Path dir = Paths.get(config.getLoadDir(), "tmp_folder");
|
|
||||||
try {
|
|
||||||
Files.createDirectories(dir);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
String base = UUID.randomUUID() + "_output.xml";
|
|
||||||
log.debug("Write tmp xml by packageId: {}", packageId);
|
|
||||||
Path tmp = dir.resolve(base + ".part");
|
|
||||||
Path done = dir.resolve(base);
|
|
||||||
|
|
||||||
try (OutputStream os = Files.newOutputStream(tmp, StandardOpenOption.CREATE_NEW)) {
|
|
||||||
SignalsStaxXmlWriterV2 writer = new SignalsStaxXmlWriterV2(persons, null, config.getEncoding());
|
|
||||||
writer.writeWithStax(os); // перегрузи на OutputStream, если нужно
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Files.move(tmp, done, StandardCopyOption.ATOMIC_MOVE);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return done;
|
|
||||||
// try {
|
|
||||||
// mergerQueue.put(new PartFilePayload(done, packageId, null));
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.impl;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.FlagsService2;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class FlagsEnricher implements Runnable {
|
|
||||||
|
|
||||||
private final FlagsService2 flagsService;
|
|
||||||
private final PhoneFidMapMapper phoneFidMapMapper;
|
|
||||||
private BlockingQueue<SubjectPayload> in;
|
|
||||||
private final CompletableFuture<Void> done = new CompletableFuture<>();
|
|
||||||
private final ExecutorService ioPool;
|
|
||||||
private final ObjectMapper mapper = new ObjectMapper()
|
|
||||||
.registerModule(new JavaTimeModule())
|
|
||||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
|
||||||
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
|
||||||
|
|
||||||
public FlagsEnricher(FlagsService2 flagsService,
|
|
||||||
PhoneFidMapMapper phoneFidMapMapper) {
|
|
||||||
this.flagsService = flagsService;
|
|
||||||
this.phoneFidMapMapper = phoneFidMapMapper;
|
|
||||||
this.ioPool = new ThreadPoolExecutor(10,
|
|
||||||
10,
|
|
||||||
0L, TimeUnit.MINUTES,
|
|
||||||
new LinkedBlockingQueue<>(),
|
|
||||||
r -> {
|
|
||||||
Thread t = new Thread(r);
|
|
||||||
t.setName("queue-handler-%s-%d".formatted(this.getClass().getSimpleName(), t.threadId()));
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
List<Future<?>> inFlight = new ArrayList<>();
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
|
||||||
try {
|
|
||||||
SubjectPayload subjectPayload = in.poll(5, TimeUnit.SECONDS);
|
|
||||||
if (subjectPayload == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (subjectPayload.isPoison()) {
|
|
||||||
log.debug("Got poison");
|
|
||||||
for (Future<?> f : inFlight) {
|
|
||||||
f.get();
|
|
||||||
}
|
|
||||||
done.complete(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
inFlight.add(ioPool.submit(() -> process(subjectPayload)));
|
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error: {}", ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void process(SubjectPayload subjectPayload) {
|
|
||||||
List<SubjectProfile> subjects = subjectPayload.getSubjects();
|
|
||||||
log.debug("FlagsEnricher handle by packageId: {}, size: {}", subjectPayload.getPackageId(), subjects.size());
|
|
||||||
|
|
||||||
List<Integer> fids = subjects.stream()
|
|
||||||
.map(SubjectProfile::getFid)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList();
|
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
|
||||||
|
|
||||||
Map<Integer, Integer> flagsDebt5000 = flagsService.findFlagsDebt5000(fids);
|
|
||||||
Map<Integer, Integer> flag90ByPastDueArrear = flagsService.findFlag90ByPastDueArrear(fids, yearAgo);
|
|
||||||
Map<Integer, Integer> flag90ByRuPaymt = flagsService.findFlag90ByRuPaymt(fids, yearAgo);
|
|
||||||
|
|
||||||
String json;
|
|
||||||
try {
|
|
||||||
json = mapper.writeValueAsString(subjects.stream().map(subject -> {
|
|
||||||
Integer debt5000 = null;
|
|
||||||
Integer flagDays90 = null;
|
|
||||||
LocalDateTime calculatedAt = null;
|
|
||||||
|
|
||||||
if (subject.getFid() != null) {
|
|
||||||
debt5000 = flagsDebt5000.getOrDefault(subject.getFid(), 0);
|
|
||||||
int pastDue90 = flag90ByPastDueArrear.getOrDefault(subject.getFid(), 0);
|
|
||||||
int paymt90 = flag90ByRuPaymt.getOrDefault(subject.getFid(), 0);
|
|
||||||
flagDays90 = Math.max(pastDue90, paymt90);
|
|
||||||
calculatedAt = LocalDateTime.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer finalDebt500 = debt5000;
|
|
||||||
Integer finalFlagDays9 = flagDays90;
|
|
||||||
LocalDateTime finalCalculatedAt = calculatedAt;
|
|
||||||
return new HashMap<String, Object>() {{
|
|
||||||
put("subject_id", subject.getIdentifier());
|
|
||||||
put("fid", subject.getFid());
|
|
||||||
put("phone", subject.getPhone());
|
|
||||||
put("package_id", subjectPayload.getPackageId());
|
|
||||||
put("flag_debt5000", finalDebt500);
|
|
||||||
put("flag_90_12", finalFlagDays9);
|
|
||||||
put("calculated_at", finalCalculatedAt);
|
|
||||||
}};
|
|
||||||
}).toList());
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
phoneFidMapMapper.registerJson(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPollingQueue(BlockingQueue<SubjectPayload> queue) {
|
|
||||||
this.in = queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Void> doneFuture() {
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.impl;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.FlagsService2;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class FlagsEnricherV2 implements Consumer<SubjectPayload> {
|
|
||||||
|
|
||||||
private final FlagsService2 flagsService;
|
|
||||||
private final PhoneFidMapMapper phoneFidMapMapper;
|
|
||||||
private final ExecutorService ioPool;
|
|
||||||
private final ObjectMapper mapper = new ObjectMapper()
|
|
||||||
.registerModule(new JavaTimeModule())
|
|
||||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
|
||||||
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
|
||||||
|
|
||||||
public FlagsEnricherV2(FlagsService2 flagsService,
|
|
||||||
PhoneFidMapMapper phoneFidMapMapper) {
|
|
||||||
this.flagsService = flagsService;
|
|
||||||
this.phoneFidMapMapper = phoneFidMapMapper;
|
|
||||||
this.ioPool = new ThreadPoolExecutor(10,
|
|
||||||
10,
|
|
||||||
0L, TimeUnit.MINUTES,
|
|
||||||
new LinkedBlockingQueue<>(100),
|
|
||||||
r -> {
|
|
||||||
Thread t = new Thread(r);
|
|
||||||
t.setName("flags-enricher-%d".formatted(t.threadId()));
|
|
||||||
return t;
|
|
||||||
},
|
|
||||||
new ThreadPoolExecutor.CallerRunsPolicy()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void process(SubjectPayload subjectPayload) {
|
|
||||||
List<SubjectProfile> subjects = subjectPayload.getSubjects();
|
|
||||||
log.debug("FlagsEnricher handle by packageId: {}, size: {}", subjectPayload.getPackageId(), subjects.size());
|
|
||||||
|
|
||||||
List<Integer> fids = subjects.stream()
|
|
||||||
.map(SubjectProfile::getFid)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList();
|
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
|
||||||
|
|
||||||
Map<Integer, Integer> flagsDebt5000 = flagsService.findFlagsDebt5000(fids);
|
|
||||||
Map<Integer, Integer> flag90ByPastDueArrear = flagsService.findFlag90ByPastDueArrear(fids, yearAgo);
|
|
||||||
Map<Integer, Integer> flag90ByRuPaymt = flagsService.findFlag90ByRuPaymt(fids, yearAgo);
|
|
||||||
|
|
||||||
String json;
|
|
||||||
try {
|
|
||||||
json = mapper.writeValueAsString(subjects.stream().map(subject -> {
|
|
||||||
Integer debt5000 = null;
|
|
||||||
Integer flagDays90 = null;
|
|
||||||
LocalDateTime calculatedAt = null;
|
|
||||||
|
|
||||||
if (subject.getFid() != null) {
|
|
||||||
debt5000 = flagsDebt5000.getOrDefault(subject.getFid(), 0);
|
|
||||||
int pastDue90 = flag90ByPastDueArrear.getOrDefault(subject.getFid(), 0);
|
|
||||||
int paymt90 = flag90ByRuPaymt.getOrDefault(subject.getFid(), 0);
|
|
||||||
flagDays90 = Math.max(pastDue90, paymt90);
|
|
||||||
calculatedAt = LocalDateTime.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer finalDebt500 = debt5000;
|
|
||||||
Integer finalFlagDays9 = flagDays90;
|
|
||||||
LocalDateTime finalCalculatedAt = calculatedAt;
|
|
||||||
return new HashMap<String, Object>() {{
|
|
||||||
put("subject_id", subject.getIdentifier());
|
|
||||||
put("fid", subject.getFid());
|
|
||||||
put("phone", subject.getPhone());
|
|
||||||
put("package_id", subjectPayload.getPackageId());
|
|
||||||
put("flag_debt5000", finalDebt500);
|
|
||||||
put("flag_90_12", finalFlagDays9);
|
|
||||||
put("calculated_at", finalCalculatedAt);
|
|
||||||
}};
|
|
||||||
}).toList());
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
phoneFidMapMapper.registerJson(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(SubjectPayload subjectPayload) {
|
|
||||||
ThreadPoolExecutor casted = (ThreadPoolExecutor) ioPool;
|
|
||||||
log.info("submitting payload. active tasks number: {}; queue size: {}", casted.getActiveCount(), casted.getQueue().size());
|
|
||||||
this.ioPool.submit(() -> {
|
|
||||||
process(subjectPayload);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.impl;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineStarter;
|
|
||||||
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
|
|
||||||
import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
|
|
||||||
|
|
||||||
public class KickPipeLineImpl implements IPipeLineStarter<SubjectPayload> {
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
|
||||||
private final Long packageId;
|
|
||||||
private final String pkgPath;
|
|
||||||
|
|
||||||
private final StaxXmlProcessor xmlProcessor;
|
|
||||||
private final int BATCH_SIZE;
|
|
||||||
|
|
||||||
|
|
||||||
public KickPipeLineImpl(StaxXmlProcessor xmlProcessor, Long packageId, String pkgPath,
|
|
||||||
CreditTrackerSettings creditTrackerSettings) {
|
|
||||||
this.packageId = packageId;
|
|
||||||
this.pkgPath = pkgPath;
|
|
||||||
this.xmlProcessor = xmlProcessor;
|
|
||||||
this.BATCH_SIZE = creditTrackerSettings.getBatchSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startFillingQueue(BlockingQueue<SubjectPayload> firstQueue) {
|
|
||||||
log.info("Start registering subjects. PackageId: {}", packageId);
|
|
||||||
AtomicInteger counter = new AtomicInteger(0);
|
|
||||||
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(pkgPath)), 8 * 1024 * 1024)) {
|
|
||||||
xmlProcessor.read(in, MonitoringRequest.class,
|
|
||||||
request -> {
|
|
||||||
if (!request.getSubjects().getSubject().isEmpty()) {
|
|
||||||
List<SubjectProfile> subjectProfileBatch = request.getSubjects().getSubject().stream().map(subject ->
|
|
||||||
SubjectProfile.builder()
|
|
||||||
.identifier(subject.getId())
|
|
||||||
.phone(subject.getClientId())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
).collect(Collectors.toList());
|
|
||||||
int count = counter.incrementAndGet();
|
|
||||||
log.trace("Reading subject's {} batch. Total count: {}. PackageId: {}", count, request.getSubjects().getSubject().size(), packageId);
|
|
||||||
try {
|
|
||||||
firstQueue.put(new SubjectPayload(packageId, subjectProfileBatch));
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.error("{}", ExceptionUtils.getStackTrace(e));
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
request.getSubjects().getSubject().clear();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
request -> request.getSubjects().getSubject().isEmpty()
|
|
||||||
,
|
|
||||||
BATCH_SIZE, "/MonitoringRequest/Subjects/Subject");
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("{}", ExceptionUtils.getStackTrace(e));
|
|
||||||
} finally {
|
|
||||||
log.debug("Send poison pill");
|
|
||||||
try {
|
|
||||||
firstQueue.put(new SubjectPayload(true));
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.error("couldn't send poison: {}", ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.impl;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.entities.indic.Name;
|
|
||||||
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
|
||||||
import ru.nbch.credit_tracker.model.NameData;
|
|
||||||
import ru.nbch.credit_tracker.model.SubjectProfile;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.PhoneService2;
|
|
||||||
import ru.nbch.credit_tracker.service.task.Handler;
|
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Стадия для сопоставления FID к номеру телефона и регистрации пакета в базе данных.
|
|
||||||
* Так же выполняется поиск и обогащение перс.данными из NAME для дальнейшей обработки.
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
//todo опять нейминг класса, варианты: ResolveSubject; DefineIcrsSubject; IcrsMapping/Resolving; PackageSaver; Filler...
|
|
||||||
public class SaveSubjectHandler implements Handler<SubjectPayload, SubjectPayload> {
|
|
||||||
private final PhoneService2 phoneService2;
|
|
||||||
private final PhoneFidMapMapper phoneFidMapMapper;
|
|
||||||
|
|
||||||
public SaveSubjectHandler(PhoneService2 phoneService2,
|
|
||||||
PhoneFidMapMapper phoneFidMapMapper) {
|
|
||||||
this.phoneService2 = phoneService2;
|
|
||||||
this.phoneFidMapMapper = phoneFidMapMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SubjectPayload handle(SubjectPayload taskPayload) {
|
|
||||||
List<SubjectProfile> subjects = taskPayload.getSubjects();
|
|
||||||
Long packageId = taskPayload.getPackageId();
|
|
||||||
log.debug("SaveSubjectStage handle by packageId: {}, size of bucket for save: {}", taskPayload.getPackageId(), subjects.size());
|
|
||||||
|
|
||||||
Map<String, Name> nameByPhone = phoneService2.findNameByNumber(subjects);
|
|
||||||
//todo сделать один проход для установки FID для вставки в PHONE_FID_MAP и одновременного заполнения инфо из Name для дальнейшей обработки
|
|
||||||
subjects.forEach(subject -> {
|
|
||||||
Name name = nameByPhone.get(CTUtil.normalizePhoneNumber(subject.getPhone()));
|
|
||||||
if (name != null) {
|
|
||||||
NameData nameData = NameData.builder()
|
|
||||||
.middleName(name.getMiddle())
|
|
||||||
.firstName(name.getFirst())
|
|
||||||
.lastName(name.getLast())
|
|
||||||
.fileSinceDate(name.getFileSinceDate())
|
|
||||||
.birthDate(name.getBirthDate())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
subject.setFid(name.getFid());
|
|
||||||
subject.setNameData(nameData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//todo стоит ли делать имутабл для subject?
|
|
||||||
return new SubjectPayload(taskPayload.getPackageId(), subjects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.impl;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import javax.xml.stream.XMLInputFactory;
|
|
||||||
import javax.xml.stream.XMLOutputFactory;
|
|
||||||
import javax.xml.stream.XMLStreamConstants;
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
import javax.xml.stream.XMLStreamReader;
|
|
||||||
import javax.xml.stream.XMLStreamWriter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.PartFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public final class XmlMergeCoordinator implements IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload> {
|
|
||||||
private final Path mergedDir;
|
|
||||||
private final Charset encoding = Charset.forName("windows-1251");
|
|
||||||
private final int batchSize = 10;
|
|
||||||
private final CompletableFuture<SignalXmlFilePayload> done = new CompletableFuture<>();
|
|
||||||
private Path out;
|
|
||||||
private BlockingQueue<PartFilePayload> inQueue;
|
|
||||||
|
|
||||||
public XmlMergeCoordinator(CreditTrackerSettings config) {
|
|
||||||
this.mergedDir = Path.of(config.getLoadDir() + File.separator + "tmp_folder" + File.separator + "merged" + File.separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Files.createDirectories(mergedDir);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
|
||||||
try {
|
|
||||||
PartFilePayload part = inQueue.poll(5, TimeUnit.SECONDS);
|
|
||||||
if (part == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (part.isPoison()) {
|
|
||||||
log.debug("Got poison");
|
|
||||||
done.complete(new SignalXmlFilePayload(out));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mergeBatch(Collections.singletonList(part));
|
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error: {}", ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergeBatch(List<PartFilePayload> inputs) throws Exception {
|
|
||||||
log.debug("Starting merge batch; size: {}", inputs.size());
|
|
||||||
Long packageId = inputs.stream().findFirst().get().getPackageId();
|
|
||||||
String outName = "merged_" + packageId + ".xml";
|
|
||||||
if (out == null) {
|
|
||||||
out = mergedDir.resolve(outName);
|
|
||||||
}
|
|
||||||
|
|
||||||
XMLOutputFactory xof = XMLOutputFactory.newFactory();
|
|
||||||
try (OutputStream os = Files.newOutputStream(out, StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
|
|
||||||
XMLStreamWriter w = xof.createXMLStreamWriter(os, encoding.name());
|
|
||||||
|
|
||||||
for (PartFilePayload in : inputs) {
|
|
||||||
log.debug("Copy person from file {}", in.getPartPath());
|
|
||||||
copyPersonsChildren(in.getPartPath(), w);
|
|
||||||
}
|
|
||||||
|
|
||||||
w.flush();
|
|
||||||
w.close();
|
|
||||||
}
|
|
||||||
for (PartFilePayload p : inputs) Files.deleteIfExists(p.getPartPath());
|
|
||||||
// inputs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Копирует всё содержимое внутри <Persons>...</Persons> входного файла
|
|
||||||
* в текущий writer, но без повторного открытия/закрытия корневого тега.
|
|
||||||
*/
|
|
||||||
private void copyPersonsChildren(Path input, XMLStreamWriter w) throws Exception {
|
|
||||||
XMLInputFactory xif = XMLInputFactory.newFactory();
|
|
||||||
try (InputStream is = Files.newInputStream(input)) {
|
|
||||||
XMLStreamReader r = xif.createXMLStreamReader(is, encoding.name());
|
|
||||||
|
|
||||||
while (r.hasNext()) {
|
|
||||||
int t = r.next();
|
|
||||||
if (t == XMLStreamConstants.START_ELEMENT && "Persons".equals(r.getLocalName())) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int depth = 0; // 0 — внутри корневого контейнера
|
|
||||||
while (r.hasNext()) {
|
|
||||||
int t = r.next();
|
|
||||||
if (t == XMLStreamConstants.START_ELEMENT) {
|
|
||||||
depth++;
|
|
||||||
writeStart(w, r);
|
|
||||||
} else if (t == XMLStreamConstants.CHARACTERS) {
|
|
||||||
if (!r.isWhiteSpace()) w.writeCharacters(r.getText());
|
|
||||||
} else if (t == XMLStreamConstants.CDATA) {
|
|
||||||
w.writeCData(r.getText());
|
|
||||||
} else if (t == XMLStreamConstants.END_ELEMENT) {
|
|
||||||
if (depth > 0) {
|
|
||||||
w.writeEndElement();
|
|
||||||
depth--;
|
|
||||||
} else if ("Persons".equals(r.getLocalName())) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeStart(XMLStreamWriter w, XMLStreamReader r) throws XMLStreamException {
|
|
||||||
w.writeStartElement(r.getLocalName());
|
|
||||||
for (int i = 0; i < r.getAttributeCount(); i++) {
|
|
||||||
w.writeAttribute(r.getAttributeLocalName(i), r.getAttributeValue(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPollingQueue(BlockingQueue<PartFilePayload> mergerQueue) {
|
|
||||||
this.inQueue = mergerQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<SignalXmlFilePayload> doneFuture() {
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.setup;
|
|
||||||
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
|
|
||||||
public interface IPipeLineStarter<Q extends StagePayload> {
|
|
||||||
void startFillingQueue(BlockingQueue<Q> queue);
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.setup;
|
|
||||||
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
import ru.nbch.credit_tracker.model.TerminatePayload;
|
|
||||||
|
|
||||||
public interface IPipeLineTerminator<Q extends StagePayload, X extends TerminatePayload> extends Runnable {
|
|
||||||
void setPollingQueue(BlockingQueue<Q> queue);
|
|
||||||
CompletableFuture<X> doneFuture();
|
|
||||||
}
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.setup;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
import ru.nbch.credit_tracker.service.task.Pipeline;
|
|
||||||
import ru.nbch.credit_tracker.service.task.Stage;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.step.HandlerStep;
|
|
||||||
|
|
||||||
public class PipeLineBuilderV2<FIRST extends StagePayload, LAST extends StagePayload> {
|
|
||||||
private final List<Stage<?, ?>> stages;
|
|
||||||
private Stage<FIRST, ?> firstStage;
|
|
||||||
private BlockingQueue<LAST> lastQueue;
|
|
||||||
private IPipeLineStarter<FIRST> pipeLineStarter;
|
|
||||||
private IPipeLineTerminator<LAST, ?> pipeLineTerminator;
|
|
||||||
|
|
||||||
private PipeLineBuilderV2() {
|
|
||||||
this.stages = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <I extends StagePayload, O extends StagePayload>
|
|
||||||
HandlerStep<I, I, O> first(BlockingQueue<I> inputQueue, BlockingQueue<O> outputQueue) {
|
|
||||||
PipeLineBuilderV2<I, O> builder = new PipeLineBuilderV2<>();
|
|
||||||
builder.lastQueue = outputQueue;
|
|
||||||
HandlerStep<I, I, O> step = StageBuilderV2.create(inputQueue, outputQueue);
|
|
||||||
((StageBuilderV2<I, I, O>) step).setParent(builder);
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <NEXT extends StagePayload>
|
|
||||||
HandlerStep<FIRST, LAST, NEXT> stage(BlockingQueue<NEXT> outputQueue) {
|
|
||||||
HandlerStep<FIRST, LAST, NEXT> step = StageBuilderV2.create(lastQueue, outputQueue);
|
|
||||||
lastQueue = (BlockingQueue<LAST>) outputQueue;
|
|
||||||
((StageBuilderV2<FIRST, LAST, NEXT>) step).setParent((PipeLineBuilderV2<FIRST, NEXT>) this);
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PipeLineBuilderV2<FIRST, LAST> fillInitialQueue(IPipeLineStarter<FIRST> pipeLineStarter) {
|
|
||||||
Objects.requireNonNull(pipeLineStarter, "pipeLineStarter is required");
|
|
||||||
if (firstStage == null) {
|
|
||||||
throw new IllegalStateException("Pipeline has no stages");
|
|
||||||
}
|
|
||||||
this.pipeLineStarter = pipeLineStarter;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PipeLineBuilderV2<FIRST, LAST> pollFinishingQueue(IPipeLineTerminator<LAST, ?> pipeLineTerminator) {
|
|
||||||
Objects.requireNonNull(pipeLineTerminator, "pipeLineTerminator is required");
|
|
||||||
this.pipeLineTerminator = pipeLineTerminator;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pipeline build() {
|
|
||||||
Pipeline p = new Pipeline();
|
|
||||||
p.setStarter(() -> {
|
|
||||||
stages.forEach(Stage::startRunning);
|
|
||||||
pipeLineStarter.startFillingQueue(firstStage.getIn());
|
|
||||||
});
|
|
||||||
pipeLineTerminator.setPollingQueue(lastQueue);
|
|
||||||
p.setTerminator(pipeLineTerminator);
|
|
||||||
p.setStages(stages);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
<I extends StagePayload, O extends StagePayload>
|
|
||||||
void addStage(Stage<I, O> stage) {
|
|
||||||
Objects.requireNonNull(stage, "stage is required");
|
|
||||||
if (stages.isEmpty()) {
|
|
||||||
this.firstStage = (Stage<FIRST, ?>) stage;
|
|
||||||
}
|
|
||||||
stages.add(stage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.setup;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
import ru.nbch.credit_tracker.service.task.Handler;
|
|
||||||
import ru.nbch.credit_tracker.service.task.Stage;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.step.BuildStep;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.step.HandlerStep;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.step.PoisonStep;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Step Builder для Stage:
|
|
||||||
* Обязательная последовательность: handler(...) -> poison(...) -> buildStage()
|
|
||||||
*/
|
|
||||||
public class StageBuilderV2<FIRST extends StagePayload, I extends StagePayload, O extends StagePayload>
|
|
||||||
implements HandlerStep<FIRST, I, O>, PoisonStep<FIRST, I, O>, BuildStep<FIRST, O> {
|
|
||||||
|
|
||||||
private PipeLineBuilderV2<FIRST, O> parent;
|
|
||||||
private final BlockingQueue<I> inputQueue;
|
|
||||||
private final BlockingQueue<O> outputQueue;
|
|
||||||
private Handler<I, O> handler;
|
|
||||||
private O poison;
|
|
||||||
Consumer<O> consumer = null;
|
|
||||||
|
|
||||||
private StageBuilderV2(BlockingQueue<I> inputQueue, BlockingQueue<O> outputQueue) {
|
|
||||||
this.inputQueue = Objects.requireNonNull(inputQueue, "inputQueue is required");
|
|
||||||
this.outputQueue = Objects.requireNonNull(outputQueue, "outputQueue is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Стартовая фабрика возвращает первый шаг — HandlerStep */
|
|
||||||
public static <FIRST extends StagePayload, I extends StagePayload, O extends StagePayload>
|
|
||||||
HandlerStep<FIRST, I, O> create(BlockingQueue<I> inputQueue, BlockingQueue<O> outputQueue) {
|
|
||||||
return new StageBuilderV2<>(inputQueue, outputQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setParent(PipeLineBuilderV2<FIRST, O> parent) {
|
|
||||||
this.parent = Objects.requireNonNull(parent, "parent is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================== ШАГИ =====================
|
|
||||||
|
|
||||||
/** Шаг 1: задать обработчик */
|
|
||||||
@Override
|
|
||||||
public PoisonStep<FIRST, I, O> handler(Handler<I, O> handler) {
|
|
||||||
this.handler = Objects.requireNonNull(handler, "handler is required");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Шаг 2: задать poison pill */
|
|
||||||
@Override
|
|
||||||
public BuildStep<FIRST, O> poison(O poison) {
|
|
||||||
this.poison = Objects.requireNonNull(poison, "poison is required");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BuildStep<FIRST, O> handlerResult(Consumer<O> consumer) {
|
|
||||||
this.consumer = Objects.requireNonNull(consumer, "consumer is required");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Шаг 3: собрать Stage и вернуться к PipeLineBuilder */
|
|
||||||
@Override
|
|
||||||
public PipeLineBuilderV2<FIRST, O> andThen() {
|
|
||||||
if (parent == null) {
|
|
||||||
throw new IllegalStateException("parent PipeLineBuilder is not set");
|
|
||||||
}
|
|
||||||
if (handler == null) {
|
|
||||||
throw new IllegalStateException("handler must be set before buildStage()");
|
|
||||||
}
|
|
||||||
if (poison == null) {
|
|
||||||
throw new IllegalStateException("poison must be set before buildStage()");
|
|
||||||
}
|
|
||||||
|
|
||||||
Stage<I, O> stage = new Stage<>(handler, inputQueue, outputQueue, poison);
|
|
||||||
stage.setConsumer(consumer);
|
|
||||||
parent.addStage(stage);
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================== Step-interfaces =====================
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.setup.step;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
import ru.nbch.credit_tracker.service.task.setup.PipeLineBuilderV2;
|
|
||||||
|
|
||||||
public interface BuildStep<FIRST extends StagePayload, O extends StagePayload> {
|
|
||||||
PipeLineBuilderV2<FIRST, O> andThen();
|
|
||||||
BuildStep<FIRST, O> handlerResult(Consumer<O> consumer);
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.setup.step;
|
|
||||||
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
import ru.nbch.credit_tracker.service.task.Handler;
|
|
||||||
|
|
||||||
public interface HandlerStep<FIRST extends StagePayload, I extends StagePayload, O extends StagePayload> {
|
|
||||||
PoisonStep<FIRST, I, O> handler(Handler<I, O> handler);
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.task.setup.step;
|
|
||||||
|
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
|
||||||
|
|
||||||
public interface PoisonStep<FIRST extends StagePayload, I extends StagePayload, O extends StagePayload> {
|
|
||||||
BuildStep<FIRST, O> poison(O poison);
|
|
||||||
}
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.xml.stax;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.xml.stream.XMLEventFactory;
|
|
||||||
import javax.xml.stream.XMLEventWriter;
|
|
||||||
import javax.xml.stream.XMLOutputFactory;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Auth;
|
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Person;
|
|
||||||
import ru.nbch.credit_tracker.entities.external_request.signals.Signals;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
//todo сделать с этим что-то!!!
|
|
||||||
public class SignalsStaxXmlWriterV2 {
|
|
||||||
private final List<Person> personList;
|
|
||||||
private final Signals signals;
|
|
||||||
private final String charsetName;
|
|
||||||
|
|
||||||
public SignalsStaxXmlWriterV2(List<Person> personList,
|
|
||||||
Signals signals,
|
|
||||||
String charsetName) {
|
|
||||||
this.personList = personList;
|
|
||||||
this.signals = signals;
|
|
||||||
this.charsetName = charsetName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeWithStax(OutputStream ou) {
|
|
||||||
try {
|
|
||||||
XMLOutputFactory output = XMLOutputFactory.newInstance();
|
|
||||||
XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance();
|
|
||||||
XMLEventWriter writer = output.createXMLEventWriter(ou, charsetName);
|
|
||||||
writer = new IndentingXMLEventWriter(writer);
|
|
||||||
|
|
||||||
WriterWrapper writerWrapper = new WriterWrapper(xmlEventFactory, writer);
|
|
||||||
// writerWrapper.addStartDocument(charsetName);
|
|
||||||
//
|
|
||||||
// writerWrapper.addStartElement("Signals");
|
|
||||||
// writerWrapper.addAttribute("online", signals.getOnline());
|
|
||||||
// writerWrapper.addAttribute("processWithErrors", signals.getProcessWithErrors());
|
|
||||||
// writerWrapper.addSimplelement("Id", signals.getId());
|
|
||||||
// writeAuth(writerWrapper, signals.getAuth());
|
|
||||||
//
|
|
||||||
// writerWrapper.addStartElement("Conditions");
|
|
||||||
writerWrapper.addStartElement("Persons");
|
|
||||||
|
|
||||||
writePersons(writerWrapper, personList);
|
|
||||||
|
|
||||||
writerWrapper.addEndElement("Persons");
|
|
||||||
// writerWrapper.addEndElement("Conditions");
|
|
||||||
|
|
||||||
// writerWrapper.addEndElement("Signals");
|
|
||||||
|
|
||||||
writerWrapper.addEndDocument();
|
|
||||||
writerWrapper.flush();
|
|
||||||
System.gc();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error("Error serializing object to XML string: {}", e.getMessage(), e);
|
|
||||||
throw new IllegalStateException("cannot serialize object to XML");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writePersons(WriterWrapper writerWrapper, List<Person> persons) throws Exception {
|
|
||||||
writerWrapper.writeCollection("p", persons, (obj, name) -> writePerson(writerWrapper, obj, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void writeAuth(WriterWrapper writerWrapper, Auth auth) throws Exception {
|
|
||||||
writerWrapper.addStartElement("Auth");
|
|
||||||
writerWrapper.addSimplelement("User", auth.getUser());
|
|
||||||
writerWrapper.addEndElement("Auth");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writePerson(WriterWrapper writerWrapper, Person person, String name) throws Exception {
|
|
||||||
if (person == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
writerWrapper.addStartElement(name);
|
|
||||||
writerWrapper.addAttribute("uid", String.valueOf(person.getUid()));
|
|
||||||
writerWrapper.addAttribute("oksm", person.getOksm());
|
|
||||||
writerWrapper.addAttribute("s", person.getS());
|
|
||||||
writerWrapper.addAttribute("n", person.getN());
|
|
||||||
writerWrapper.addAttribute("m", person.getM());
|
|
||||||
writerWrapper.addAttribute("d", person.getD());
|
|
||||||
writerWrapper.addAttribute("pn", person.getPn());
|
|
||||||
writerWrapper.addAttribute("pd", person.getPd());
|
|
||||||
writerWrapper.addAttribute("dt", person.getDt());
|
|
||||||
writerWrapper.addAttribute("odt", person.getOdt());
|
|
||||||
writerWrapper.addAttribute("ip", person.getIp());
|
|
||||||
writerWrapper.addAttribute("consentDate", person.getConsentDate());
|
|
||||||
writerWrapper.addAttribute("consentPurpose", person.getConsentPurpose());
|
|
||||||
writerWrapper.addAttribute("reportUser", person.getReportUser());
|
|
||||||
writerWrapper.addAttribute("liability", person.getLiability());
|
|
||||||
writerWrapper.addAttribute("consentPeriod", person.getConsentPeriod());
|
|
||||||
writerWrapper.addAttribute("agrDate", person.getAgrDate());
|
|
||||||
writerWrapper.addAttribute("reportUserRegNum", person.getReportUserRegNum());
|
|
||||||
writerWrapper.addAttribute("reportUserTaxID", person.getReportUserTaxID());
|
|
||||||
writerWrapper.addAttribute("consentHash", person.getConsentHash());
|
|
||||||
writerWrapper.addAttribute("cS", person.getCs());
|
|
||||||
writerWrapper.addAttribute("consentN", person.getConsentN());
|
|
||||||
writerWrapper.addAttribute("consentM", person.getConsentM());
|
|
||||||
writerWrapper.addAttribute("consentBd", person.getConsentBd());
|
|
||||||
writerWrapper.addAttribute("consentPn", person.getConsentPn());
|
|
||||||
writerWrapper.addAttribute("consentPd", person.getConsentPd());
|
|
||||||
writerWrapper.addAttribute("consentDivCode", person.getConsentDivCode());
|
|
||||||
writerWrapper.addAttribute("consentDt", person.getConsentDt());
|
|
||||||
writerWrapper.addAttribute("consentOdt", person.getConsentOdt());
|
|
||||||
writerWrapper.addAttribute("consentIssueAuthority", person.getConsentIssueAuthority());
|
|
||||||
writerWrapper.addAttribute("inqPurpose", person.getInqPurpose());
|
|
||||||
writerWrapper.addEndElement(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -104,11 +104,7 @@ public class XmlProcessorStaxImpl implements StaxXmlProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <Z> Z read(InputStream inputStream,
|
public <Z> Z read(InputStream inputStream, Class<Z> clazz, Consumer<Z> objProcessor, Function<Z, Boolean> emptyBatchCheckFunction, Integer batchSize, String endBatchElementPath) {
|
||||||
Class<Z> clazz, Consumer<Z> objProcessor,
|
|
||||||
Function<Z, Boolean> emptyBatchCheckFunction,
|
|
||||||
Integer batchSize,
|
|
||||||
String endBatchElementPath) {
|
|
||||||
try {
|
try {
|
||||||
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);
|
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);
|
||||||
Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz);
|
Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz);
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,4 @@ public class CTUtil {
|
||||||
log.warn("File {} hasn't been deleted", filePath);
|
log.warn("File {} hasn't been deleted", filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String normalizePhoneNumber(String phoneNumber) {
|
|
||||||
return "9" + phoneNumber;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.utils;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
|
|
||||||
|
|
||||||
|
|
||||||
public class LogUtil {
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(LogUtil.class);
|
|
||||||
public static final String mdcKey = "ru.nbch.credit_tracker.log.mdc.key";
|
|
||||||
|
|
||||||
public static void addMdcLogKey(String uuid) {
|
|
||||||
addMdcLogKey(mdcKey, uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void removeMdcLogKey() {
|
|
||||||
removeMdcLogKey(mdcKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeMdcLogKey(String key) {
|
|
||||||
try {
|
|
||||||
MDC.remove(key);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addMdcLogKey(String mdcKey, String uuid) {
|
|
||||||
if (uuid != null) {
|
|
||||||
try {
|
|
||||||
MDC.put(mdcKey, "[" + uuid + "] ");
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error("{}", ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, String> extractMdcMap() {
|
|
||||||
try {
|
|
||||||
return MDC.getCopyOfContextMap();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Runnable wrap(Map<String, String> contextMap, Runnable task) {
|
|
||||||
return () -> {
|
|
||||||
Map<String, String> previous = null;
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
previous = MDC.getCopyOfContextMap();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
// ставим захваченный контекст (может быть null)
|
|
||||||
try {
|
|
||||||
if (contextMap == null) {
|
|
||||||
MDC.clear();
|
|
||||||
} else {
|
|
||||||
MDC.setContextMap(contextMap);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
task.run();
|
|
||||||
} finally {
|
|
||||||
// восстанавливаем предыдущий (может быть null)
|
|
||||||
try {
|
|
||||||
if (previous == null) {
|
|
||||||
MDC.clear();
|
|
||||||
} else {
|
|
||||||
MDC.setContextMap(previous);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,10 @@
|
||||||
package ru.nbch.credit_tracker.utils;
|
package ru.nbch.credit_tracker.utils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ZipUtils {
|
public class ZipUtils {
|
||||||
|
|
@ -30,27 +25,4 @@ public class ZipUtils {
|
||||||
}
|
}
|
||||||
return zipEntry;
|
return zipEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isZipFile(MultipartFile file) {
|
|
||||||
return file.getContentType() != null &&
|
|
||||||
(file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) ||
|
|
||||||
file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String writeTmpFile(String path, MultipartFile file) throws IOException {
|
|
||||||
CTUtil.createFolder(path);
|
|
||||||
String filePath = path + UUID.randomUUID() + "monitoring_request.xml";
|
|
||||||
|
|
||||||
try (OutputStream out = Files.newOutputStream(Path.of(filePath))) {
|
|
||||||
ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream());
|
|
||||||
zipInputStream.getNextEntry();
|
|
||||||
byte[] buffer = new byte[8 * 1024 * 1024];
|
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = zipInputStream.read(buffer)) > 0) {
|
|
||||||
out.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package ru.nbch.credit_tracker.utils.error;
|
package ru.nbch.credit_tracker.utils.error;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import ru.nbch.credit_tracker.enums.EnumKeyMessage;
|
import ru.nbch.credit_tracker.enums.EnumKeyMessage;
|
||||||
import ru.nbch.credit_tracker.enums.IEnumKeyCode;
|
import ru.nbch.credit_tracker.enums.IEnumKeyCode;
|
||||||
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
|
import ru.nbch.credit_tracker.enums.XmlErrorFormat;
|
||||||
|
|
@ -10,13 +8,6 @@ import ru.nbch.credit_tracker.exceptions.SignalServerException;
|
||||||
|
|
||||||
public class ExceptionUtils {
|
public class ExceptionUtils {
|
||||||
|
|
||||||
public static String getStackTrace(Throwable throwable) {
|
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
PrintWriter pw = new PrintWriter(sw, true);
|
|
||||||
throwable.printStackTrace(pw);
|
|
||||||
return sw.getBuffer().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SignalClientException clientExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) {
|
public static SignalClientException clientExcp(IEnumKeyCode enumKeyCode, XmlErrorFormat xmlErrorFormat, Object... args) {
|
||||||
return clientExcp(enumKeyCode, null, xmlErrorFormat, args);
|
return clientExcp(enumKeyCode, null, xmlErrorFormat, args);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{ru.nbch.credit_tracker.log.mdc.key}- %msg%n</pattern>
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{ru.nbch.credit_tracker.log.mdc.key} - %msg%n</pattern>
|
||||||
<charset>utf-8</charset>
|
<charset>utf-8</charset>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<maxFileSize>100MB</maxFileSize>
|
<maxFileSize>100MB</maxFileSize>
|
||||||
</triggeringPolicy>
|
</triggeringPolicy>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{ru.nbch.credit_tracker.log.mdc.key}- %msg%n</pattern>
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{ru.nbch.credit_tracker.log.mdc.key} - %msg%n</pattern>
|
||||||
<charset>utf-8</charset>
|
<charset>utf-8</charset>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
@ -63,18 +63,12 @@
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<!--SQL запросы и результаты их выполнения-->
|
<!--SQL запросы и результаты их выполнения-->
|
||||||
<logger name="ru.nbch.credit_tracker.mapper" level="DEBUG" additivity="false">
|
<logger name="ru.nbch.credit_tracker.mapper" level="INFO" additivity="false">
|
||||||
<appender-ref ref="FILE"/>
|
<appender-ref ref="FILE"/>
|
||||||
<appender-ref ref="FILE-JSON"/>
|
<appender-ref ref="FILE-JSON"/>
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="ru.nbch.credit_tracker.component" level="DEBUG" additivity="false">
|
<logger name="ru.nbch.credit_tracker.service" level="INFO" additivity="false">
|
||||||
<appender-ref ref="FILE"/>
|
|
||||||
<appender-ref ref="FILE-JSON"/>
|
|
||||||
<appender-ref ref="CONSOLE"/>
|
|
||||||
</logger>
|
|
||||||
|
|
||||||
<logger name="ru.nbch.credit_tracker.service" level="TRACE" additivity="false">
|
|
||||||
<appender-ref ref="FILE"/>
|
<appender-ref ref="FILE"/>
|
||||||
<appender-ref ref="FILE-JSON"/>
|
<appender-ref ref="FILE-JSON"/>
|
||||||
<appender-ref ref="CONSOLE"/>
|
<appender-ref ref="CONSOLE"/>
|
||||||
|
|
|
||||||
|
|
@ -5,85 +5,50 @@
|
||||||
|
|
||||||
<mapper namespace="ru.nbch.credit_tracker.mapper.indic.FlagsMapper">
|
<mapper namespace="ru.nbch.credit_tracker.mapper.indic.FlagsMapper">
|
||||||
|
|
||||||
<resultMap id="RuPastDuarearResultMap" type="ru.nbch.credit_tracker.service.indic.FlagsService$RuPastDuarearData">
|
<resultMap id="FlagsFidDataResultMap" type="ru.nbch.credit_tracker.service.indic.FlagsService$FlagFidData">
|
||||||
<result property="fid" column="fid" />
|
|
||||||
<result property="accSerialNum" column="ACC_SERIAL_NUM" />
|
|
||||||
<result property="reportedDate" column="REPORTED_DT" />
|
|
||||||
<result property="amtPastDue" column="AMT_PAST_DUE" />
|
|
||||||
<result property="daysPastDue" column="DAYS_PAST_DUE" />
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<resultMap id="RuPaymtResultMap" type="ru.nbch.credit_tracker.service.indic.FlagsService$RuPaymtData">
|
|
||||||
<result property="fid" column="fid" />
|
|
||||||
<result property="daysPastDue" column="DAYS_PAST_DUE" />
|
|
||||||
<result property="reportedDate" column="REPORTED_DT" />
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<resultMap id="PaymentsFlagResult" type="ru.nbch.credit_tracker.entities.indic.PaymentsFlag">
|
|
||||||
<result property="fid" column="fid" />
|
<result property="fid" column="fid" />
|
||||||
<result property="flag" column="flag" />
|
<result property="flag" column="flag" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<select id="findRuPastDuarearData" resultMap="RuPastDuarearResultMap">
|
<select id="findFlagsDebt5000" resultMap="FlagsFidDataResultMap">
|
||||||
SELECT FID, ACC_SERIAL_NUM, REPORTED_DT, AMT_PAST_DUE, DAYS_PAST_DUE
|
|
||||||
FROM RU_PASTDUEARREAR
|
|
||||||
WHERE FID IN
|
|
||||||
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
|
||||||
#{fid}
|
|
||||||
</foreach>
|
|
||||||
with UR
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select id="findRuPaymtData" resultMap="RuPaymtResultMap">
|
|
||||||
SELECT FID, DAYS_PAST_DUE, REPORTED_DT
|
|
||||||
FROM RU_PAYMT
|
|
||||||
WHERE FID IN
|
|
||||||
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
|
||||||
#{fid}
|
|
||||||
</foreach>
|
|
||||||
AND REPORTED_DT >= #{reportedDate}
|
|
||||||
with UR
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select id="findFlagsDebt5000" resultMap="PaymentsFlagResult">
|
|
||||||
SELECT
|
SELECT
|
||||||
FID as fid,
|
FID as fid,
|
||||||
(case when (sum(case when AMT_PAST_DUE > 5000 then 1 else 0 end) = 0) then 0 else 1 end) as flag
|
(case when (sum(case when AMT_PAST_DUE > 5000 then 1 else 0 end) = 0) then 0 else 1 end) as flag
|
||||||
FROM
|
FROM
|
||||||
(select FID, AMT_PAST_DUE, rank() over (partition by FID, ACC_SERIAL_NUM order by REPORTED_DT desc) rn
|
(select FID, AMT_PAST_DUE, rank() over (partition by FID, ACC_SERIAL_NUM order by REPORTED_DT desc) rn
|
||||||
FROM RU_PASTDUEARREAR
|
FROM RU_PASTDUEARREAR
|
||||||
WHERE FID IN
|
WHERE FID IN
|
||||||
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
||||||
#{fid}
|
#{fid}
|
||||||
</foreach>
|
</foreach>
|
||||||
)
|
)
|
||||||
where rn=1
|
where rn=1
|
||||||
group by FID
|
group by FID
|
||||||
WITH UR
|
WITH UR
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findFlag90ByPastDueArrear" resultMap="PaymentsFlagResult">
|
<select id="findFlag90ByPastDueArrear" resultMap="FlagsFidDataResultMap">
|
||||||
SELECT
|
SELECT
|
||||||
FID as fid,
|
FID as fid,
|
||||||
(case when (sum(case when (REPORTED_DT >= #{reportedDate} and DAYS_PAST_DUE > 90) then 1 else 0 end) = 0) then 0 else 1 end) as flag
|
(case when (sum(case when (REPORTED_DT >= #{reportedDate} and DAYS_PAST_DUE > 90) then 1 else 0 end) = 0) then 0 else 1 end) as flag
|
||||||
FROM RU_PASTDUEARREAR
|
FROM RU_PASTDUEARREAR
|
||||||
WHERE FID IN
|
WHERE FID IN
|
||||||
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
||||||
#{fid}
|
#{fid}
|
||||||
</foreach>
|
</foreach>
|
||||||
GROUP BY FID
|
GROUP BY FID
|
||||||
WITH UR
|
WITH UR
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findFlag90ByRuPaymt" resultMap="PaymentsFlagResult">
|
<select id="findFlag90ByRuPaymt" resultMap="FlagsFidDataResultMap">
|
||||||
SELECT
|
SELECT
|
||||||
FID as fid,
|
FID as fid,
|
||||||
(case when (sum(case when (REPORTED_DT >= #{reportedDate} and DAYS_PAST_DUE > 90) then 1 else 0 end) = 0) then 0 else 1 end) as flag
|
(case when (sum(case when (REPORTED_DT >= #{reportedDate} and DAYS_PAST_DUE > 90) then 1 else 0 end) = 0) then 0 else 1 end) as flag
|
||||||
FROM RU_PAYMT
|
FROM RU_PAYMT
|
||||||
WHERE FID IN
|
WHERE FID IN
|
||||||
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
<foreach item="fid" collection="fids" open="(" separator="," close=")">
|
||||||
#{fid}
|
#{fid}
|
||||||
</foreach>
|
</foreach>
|
||||||
GROUP BY FID
|
GROUP BY FID
|
||||||
WITH UR
|
WITH UR
|
||||||
</select>
|
</select>
|
||||||
|
|
|
||||||
25
src/main/resources/mybatis/mapper/indic/PhoneMapper.xml
Normal file
25
src/main/resources/mybatis/mapper/indic/PhoneMapper.xml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
|
||||||
|
<mapper namespace="ru.nbch.credit_tracker.mapper.indic.PhoneMapper">
|
||||||
|
|
||||||
|
<resultMap id="fidsDataResultMap" type="ru.nbch.credit_tracker.service.indic.PhoneService$FidsData">
|
||||||
|
<result property="phone" column="number" />
|
||||||
|
<result property="fid" column="fid" />
|
||||||
|
<result property="fileSinceDate" column="fileSinceDate" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="findFids" resultMap="fidsDataResultMap">
|
||||||
|
SELECT pn.NUMBER AS number, pn.FID AS fid, pn.FILE_SINCE_DT AS fileSinceDate
|
||||||
|
FROM PHONE_NORM pn
|
||||||
|
INNER JOIN NAME n ON n.FID = pn.FID
|
||||||
|
WHERE number in
|
||||||
|
<foreach item="phone" collection="phones" open="(" separator="," close=")">
|
||||||
|
#{phone}
|
||||||
|
</foreach>
|
||||||
|
ORDER BY fileSinceDate DESC, fid DESC
|
||||||
|
WITH UR
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<mapper namespace="ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper">
|
<mapper namespace="ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper">
|
||||||
|
|
||||||
<resultMap id="PhoneFidMapResultMap" type="ru.nbch.credit_tracker.entities.app.PhoneFidMap">
|
<resultMap id="PhoneFidMapResultMap" type="ru.nbch.credit_tracker.entities.dto.PhoneFidMap">
|
||||||
<result property="id" column="id"/>
|
<result property="id" column="id"/>
|
||||||
<result property="packageId" column="package_id"/>
|
<result property="packageId" column="package_id"/>
|
||||||
<result property="subjectId" column="subject_id"/>
|
<result property="subjectId" column="subject_id"/>
|
||||||
|
|
@ -25,36 +25,6 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<insert id="register" parameterType="java.util.List">
|
|
||||||
INSERT INTO signals_phone_fid_map (subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at)
|
|
||||||
values
|
|
||||||
<foreach collection="phoneFidMap" item="phoneFid" separator=",">
|
|
||||||
(#{phoneFid.subjectId}, #{phoneFid.fid}, #{phoneFid.phone}, #{phoneFid.packageId}, #{phoneFid.flagDebt5000}, #{phoneFid.flag90days}, #{phoneFid.calculatedAt})
|
|
||||||
</foreach>
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<insert id="registerJson" parameterType="string">
|
|
||||||
INSERT INTO signals_phone_fid_map
|
|
||||||
(subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at)
|
|
||||||
SELECT subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at
|
|
||||||
FROM json_to_recordset(#{json}::json) AS t(
|
|
||||||
subject_id varchar(255),
|
|
||||||
fid int,
|
|
||||||
phone text,
|
|
||||||
package_id bigint,
|
|
||||||
flag_debt5000 smallint,
|
|
||||||
flag_90_12 smallint,
|
|
||||||
calculated_at timestamp)
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<insert id="registerWithId" parameterType="java.util.List" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
|
|
||||||
INSERT INTO signals_phone_fid_map (subject_id, phone, package_id)
|
|
||||||
values
|
|
||||||
<foreach collection="phoneFidMap" item="phoneFid" separator=",">
|
|
||||||
(#{phoneFid.subjectId}, #{phoneFid.phone}, #{phoneFid.packageId})
|
|
||||||
</foreach>
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
|
|
||||||
<update id="updatePhoneFidMaps" parameterType="java.util.List">
|
<update id="updatePhoneFidMaps" parameterType="java.util.List">
|
||||||
<foreach collection="subjects" item="subject" separator=";">
|
<foreach collection="subjects" item="subject" separator=";">
|
||||||
|
|
@ -72,35 +42,12 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<update id="updateOne" parameterType="ru.nbch.credit_tracker.entities.app.PhoneFidMap">
|
|
||||||
UPDATE signals_phone_fid_map
|
|
||||||
SET
|
|
||||||
package_id = #{subject.packageId},
|
|
||||||
subject_id = #{subject.subjectId},
|
|
||||||
phone = #{subject.phone},
|
|
||||||
fid = #{subject.fid2},
|
|
||||||
flag_debt5000 = #{subject.flagDebt5000},
|
|
||||||
flag_90_12 = #{subject.flag90days},
|
|
||||||
calculated_at = #{subject.calculatedAt},
|
|
||||||
error_text = #{subject.errorText}
|
|
||||||
WHERE id = #{subject.id}
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<update id="updateFid" parameterType="java.util.List">
|
|
||||||
<foreach collection="subjects" item="subject" separator=";">
|
|
||||||
UPDATE signals_phone_fid_map
|
|
||||||
SET
|
|
||||||
fid = #{subject.fid}
|
|
||||||
WHERE rec_uuid = #{subject.id}
|
|
||||||
</foreach>
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<update id="updatePhoneFidMapsErrors" parameterType="java.util.List">
|
<update id="updatePhoneFidMapsErrors" parameterType="java.util.List">
|
||||||
<foreach collection="subjects" item="subject" separator=";">
|
<foreach collection="subjects" item="subject" separator=";">
|
||||||
UPDATE signals_phone_fid_map
|
UPDATE signals_phone_fid_map
|
||||||
SET
|
SET
|
||||||
error_text = #{subject.errorText}
|
error_text = #{subject.errorText}
|
||||||
WHERE id = #{subject.recUuid}
|
WHERE id = #{subject.id}
|
||||||
</foreach>
|
</foreach>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
|
@ -120,7 +67,7 @@
|
||||||
LIMIT #{limit} OFFSET #{offset}
|
LIMIT #{limit} OFFSET #{offset}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findPhoneFidMapById" resultMap="PhoneFidMapResultMap" resultType="ru.nbch.credit_tracker.entities.app.PhoneFidMap">
|
<select id="findPhoneFidMapById" resultMap="PhoneFidMapResultMap" resultType="ru.nbch.credit_tracker.entities.dto.PhoneFidMap">
|
||||||
SELECT id,
|
SELECT id,
|
||||||
package_id,
|
package_id,
|
||||||
subject_id,
|
subject_id,
|
||||||
|
|
@ -141,5 +88,11 @@
|
||||||
where package_id = #{packageId} AND fid is not null
|
where package_id = #{packageId} AND fid is not null
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="hasOldRow" resultType="java.lang.Boolean">
|
||||||
|
select EXISTS(SELECT 1
|
||||||
|
FROM signals_phone_fid_map
|
||||||
|
WHERE package_id = #{packageId}
|
||||||
|
AND calculated_at < now() - make_interval(days => #{daysCount})
|
||||||
|
)
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<mapper namespace="ru.nbch.credit_tracker.mapper.signal.UserPackageMapper">
|
<mapper namespace="ru.nbch.credit_tracker.mapper.signal.UserPackageMapper">
|
||||||
|
|
||||||
<resultMap id="packageDataResultMap" type="ru.nbch.credit_tracker.entities.app.UserPackage">
|
<resultMap id="packageDataResultMap" type="ru.nbch.credit_tracker.entities.dto.UserPackage">
|
||||||
<result property="id" column="id"/>
|
<result property="id" column="id"/>
|
||||||
<result property="userId" column="membercode"/>
|
<result property="userId" column="membercode"/>
|
||||||
<result property="packageName" column="package_name"/>
|
<result property="packageName" column="package_name"/>
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<select id="insertPackage" resultType="java.lang.Long"
|
<select id="insertPackage" resultType="java.lang.Long"
|
||||||
parameterType="ru.nbch.credit_tracker.entities.app.UserPackage">
|
parameterType="ru.nbch.credit_tracker.entities.dto.UserPackage">
|
||||||
INSERT INTO signals_user_packages (membercode, package_name, created_at, status)
|
INSERT INTO signals_user_packages (membercode, package_name, created_at, status)
|
||||||
values (#{userPackage.userId}, #{userPackage.packageName}, #{userPackage.createdAt}, #{userPackage.status}) RETURNING id
|
values (#{userPackage.userId}, #{userPackage.packageName}, #{userPackage.createdAt}, #{userPackage.status}) RETURNING id
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<select id="findPackage" resultMap="packageDataResultMap"
|
<select id="findPackage" resultMap="packageDataResultMap"
|
||||||
resultType="ru.nbch.credit_tracker.entities.app.UserPackage">
|
resultType="ru.nbch.credit_tracker.entities.dto.UserPackage">
|
||||||
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
||||||
FROM signals_user_packages
|
FROM signals_user_packages
|
||||||
WHERE id = #{id}
|
WHERE id = #{id}
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findUserPackages" resultMap="packageDataResultMap"
|
<select id="findUserPackages" resultMap="packageDataResultMap"
|
||||||
resultType="ru.nbch.credit_tracker.entities.app.UserPackage">
|
resultType="ru.nbch.credit_tracker.entities.dto.UserPackage">
|
||||||
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
||||||
FROM signals_user_packages
|
FROM signals_user_packages
|
||||||
WHERE membercode IS NOT NULL
|
WHERE membercode IS NOT NULL
|
||||||
|
|
@ -97,7 +97,7 @@
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findAllPackagesByUserId" resultMap="packageDataResultMap"
|
<select id="findAllPackagesByUserId" resultMap="packageDataResultMap"
|
||||||
resultType="ru.nbch.credit_tracker.entities.app.UserPackage">
|
resultType="ru.nbch.credit_tracker.entities.dto.UserPackage">
|
||||||
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
||||||
FROM signals_user_packages
|
FROM signals_user_packages
|
||||||
WHERE membercode IS NOT NULL
|
WHERE membercode IS NOT NULL
|
||||||
|
|
@ -105,7 +105,7 @@
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findAllPackagesByStatus" resultMap="packageDataResultMap"
|
<select id="findAllPackagesByStatus" resultMap="packageDataResultMap"
|
||||||
resultType="ru.nbch.credit_tracker.entities.app.UserPackage">
|
resultType="ru.nbch.credit_tracker.entities.dto.UserPackage">
|
||||||
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at
|
||||||
FROM signals_user_packages
|
FROM signals_user_packages
|
||||||
WHERE status = #{status}
|
WHERE status = #{status}
|
||||||
|
|
|
||||||
3
src/main/resources/sql/v1.22.ddl
Normal file
3
src/main/resources/sql/v1.22.ddl
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
CREATE INDEX IF NOT EXISTS
|
||||||
|
idx_signals_phone_fid_map_calculated_at
|
||||||
|
ON signals_phone_fid_map (calculated_at);
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
|
|
||||||
CREATE TABLE signals_user_packages (
|
|
||||||
DB_VERSION varchar(12)
|
|
||||||
);
|
|
||||||
|
|
||||||
alter table signals_user_packages
|
|
||||||
alter column LAST_SEARCHED_AT type timestamp;
|
|
||||||
alter table signals_user_packages
|
|
||||||
alter column REJECT_STATUS type varchar(255);
|
|
||||||
|
|
||||||
alter table signals_phone_fid_map
|
|
||||||
alter column SEARCHED_AT type timestamp;
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE signals_flags (
|
|
||||||
ID SERIAL PRIMARY KEY,
|
|
||||||
MAP_ID bigint,
|
|
||||||
SUBJECT_ID varchar(255),
|
|
||||||
PHONE varchar(255),
|
|
||||||
FID int,
|
|
||||||
FLAG_DEBT5000 smallint,
|
|
||||||
FLAG_90_12 smallint,
|
|
||||||
CALCULATED_AT timestamp
|
|
||||||
);
|
|
||||||
|
|
@ -1,278 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.FlagsService;
|
|
||||||
|
|
||||||
public class FlagsService2Test {
|
|
||||||
|
|
||||||
private static final LocalDate INITIAL_DATE = LocalDate.parse("2025-09-25");
|
|
||||||
|
|
||||||
private static final String RU_PASTDUEAREAR_CREATE = """
|
|
||||||
create table RU_PASTDUEARREAR
|
|
||||||
(
|
|
||||||
FID INTEGER not null,
|
|
||||||
SERIAL_NUM BIGINT not null primary key,
|
|
||||||
ACC_SERIAL_NUM BIGINT not null,
|
|
||||||
REPORTED_DT DATE not null,
|
|
||||||
AMT_PAST_DUE DECIMAL(17, 2),
|
|
||||||
DAYS_PAST_DUE BIGINT
|
|
||||||
);
|
|
||||||
""";
|
|
||||||
|
|
||||||
private static final String RU_PASTDUEAREAR_DROP = """
|
|
||||||
DROP TABLE IF EXISTS RU_PASTDUEARREAR;
|
|
||||||
""";
|
|
||||||
|
|
||||||
private static final String RU_PAYMT_DROP = """
|
|
||||||
DROP TABLE IF EXISTS RU_PAYMT;
|
|
||||||
""";
|
|
||||||
|
|
||||||
private static final String RU_PAYMT_CREATE = """
|
|
||||||
create table RU_PAYMT
|
|
||||||
(
|
|
||||||
FID INTEGER not null,
|
|
||||||
SERIAL_NUM BIGINT not null primary key,
|
|
||||||
DAYS_PAST_DUE INTEGER,
|
|
||||||
REPORTED_DT DATE not null
|
|
||||||
);
|
|
||||||
""";
|
|
||||||
|
|
||||||
private static final String FILL_RU_PASTDUEARREAR = String.format("""
|
|
||||||
INSERT INTO RU_PASTDUEARREAR VALUES
|
|
||||||
(1, 1, 1, '%s', 36000.00, 159), -- просрочка 5000 и 90_days по этой записи
|
|
||||||
(2, 2, 2, '%s', 3200.00, null), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(2, 3, 2, '%s', 6700.00, null), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(2, 4, 2, '%s', 5700.00, null), -- просрочка 5000 по этой записи
|
|
||||||
(3, 5, 3, '%s', 300000000000.00, null),
|
|
||||||
(2, 6, 2, '%s', 0.00, null), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(4, 7, 4, '%s', 4000.00, null), -- нет просрочек
|
|
||||||
(5, 8, 5, '%s', 2000.31, 182), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(5, 9, 5, '%s', 2000.31, 212), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(5, 10, 5, '%s', 2000.31, null), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(5, 11, 5, '%s', 2000.31, 273), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(5, 12, 5, '%s', 2000.31, null), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(5, 13, 5, '%s', 7000.31, 307), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(5, 14, 5, '%s', 2000.31, 338), -- не макс reported_date для того же acc_serial_num, просрочка 90_days будет взята у этой записи
|
|
||||||
(5, 15, 5, '%s', 7000.31, 368), -- Просрочка 5000 будет взята у этой записи. Уникальный acc_serial_num с макс reported_dt
|
|
||||||
(5, 16, 5, '%s', 2000.31, 399), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(5, 17, 5, '%s', 5000.31, 5), -- не макс reported_date для того же acc_serial_num
|
|
||||||
(6, 18, 6, '%s', 3000, null), -- Нет просрочки 5000, нет просрочки 90_days (90_days будет в RU_PAYMT)
|
|
||||||
(7, 19, 7, '%s', 5500, 90), -- не макс reported_date для того же acc_serial_num. 90_days будет взята отсюда
|
|
||||||
(7, 20, 7, '%s', 3000, null) -- Нет просрочки 5000. Уникальный acc_serial_num с макс reported_dt
|
|
||||||
""",
|
|
||||||
calcLocalDateFromInitialDate("2025-05-31"),
|
|
||||||
calcLocalDateFromInitialDate("2021-12-29"),
|
|
||||||
calcLocalDateFromInitialDate("2022-01-28"),
|
|
||||||
calcLocalDateFromInitialDate("2025-04-06"),
|
|
||||||
calcLocalDateFromInitialDate("2025-01-14"),
|
|
||||||
calcLocalDateFromInitialDate("2021-11-29"),
|
|
||||||
calcLocalDateFromInitialDate("2025-12-06"),
|
|
||||||
calcLocalDateFromInitialDate("2021-04-01"),
|
|
||||||
calcLocalDateFromInitialDate("2021-05-01"),
|
|
||||||
calcLocalDateFromInitialDate("2021-05-31"),
|
|
||||||
calcLocalDateFromInitialDate("2021-07-01"),
|
|
||||||
calcLocalDateFromInitialDate("2021-07-31"),
|
|
||||||
calcLocalDateFromInitialDate("2021-08-04"),
|
|
||||||
calcLocalDateFromInitialDate("2025-09-08"),
|
|
||||||
calcLocalDateFromInitialDate("2025-09-09"),
|
|
||||||
calcLocalDateFromInitialDate("2021-11-04"),
|
|
||||||
calcLocalDateFromInitialDate("2022-01-04"),
|
|
||||||
calcLocalDateFromInitialDate("2025-09-09"),
|
|
||||||
calcLocalDateFromInitialDate("2025-09-09"),
|
|
||||||
calcLocalDateFromInitialDate("2025-09-10"));
|
|
||||||
|
|
||||||
private static final String FILL_RU_PAYMT = String.format("""
|
|
||||||
INSERT INTO RU_PAYMT VALUES
|
|
||||||
(1, 1, null, '%s'),
|
|
||||||
(2, 2, 30, '%s'),
|
|
||||||
(3, 3, null, '%s'),
|
|
||||||
(3, 4, 100, '%s'),
|
|
||||||
(4, 5, 10, '%s'),
|
|
||||||
(5, 6, 10, '%s'),
|
|
||||||
(6, 7, 90, '%s'),
|
|
||||||
(6, 8, 80, '%s'),
|
|
||||||
(7, 9, null, '%s'),
|
|
||||||
(8, 10, null, '%s'),
|
|
||||||
(8, 11, 83, '%s'),
|
|
||||||
(8, 12, 91, '%s'),
|
|
||||||
(9, 13, 100, '%s')
|
|
||||||
""",
|
|
||||||
calcLocalDateFromInitialDate("2024-11-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-11-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-11-10"),
|
|
||||||
calcLocalDateFromInitialDate("2024-11-15"),
|
|
||||||
calcLocalDateFromInitialDate("2024-11-15"),
|
|
||||||
calcLocalDateFromInitialDate("2023-11-15"),
|
|
||||||
calcLocalDateFromInitialDate("2024-11-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-10-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-10-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-10-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-10-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-10-09"),
|
|
||||||
calcLocalDateFromInitialDate("2024-10-09"));
|
|
||||||
|
|
||||||
|
|
||||||
private DataSource dataSource;
|
|
||||||
private NamedParameterJdbcTemplate jdbcTemplate;
|
|
||||||
private FlagsService flagsService;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
dataSource = DataSourceBuilder.create()
|
|
||||||
.url("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=DB2;DATABASE_TO_LOWER=TRUE")
|
|
||||||
.driverClassName("org.h2.Driver")
|
|
||||||
.username("sa")
|
|
||||||
.password("")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
|
||||||
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(RU_PASTDUEAREAR_DROP);
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(RU_PAYMT_DROP);
|
|
||||||
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(RU_PASTDUEAREAR_CREATE);
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(RU_PAYMT_CREATE);
|
|
||||||
|
|
||||||
flagsService = new FlagsService(null, jdbcTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testfindFlags() {
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(FILL_RU_PASTDUEARREAR);
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(FILL_RU_PAYMT);
|
|
||||||
|
|
||||||
List<Integer> fids = new ArrayList<>(List.of(
|
|
||||||
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
2, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Нет просрочки 90_days в RU_PAYMT
|
|
||||||
3, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
4, // нет никаких просрочек
|
|
||||||
7, // нет просрочки 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
5, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
6, // нет просрочки 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
8, // нету в RU_PASTDUEARREAR, есть в RU_PAYMT
|
|
||||||
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
|
|
||||||
|
|
||||||
Assertions.assertEquals(9, resultMap.size());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
|
|
||||||
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(6).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(7).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(8).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(9).getFlag90days());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testfindFlagsWithoutRuPaymt() {
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(FILL_RU_PASTDUEARREAR);
|
|
||||||
|
|
||||||
List<Integer> fids = new ArrayList<>(List.of(
|
|
||||||
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
2, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Нет просрочки 90_days в RU_PAYMT
|
|
||||||
3, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
4, // нет никаких просрочек
|
|
||||||
7, // нет просрочки 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
5, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
6, // нет просрочки 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
8, // нету в RU_PASTDUEARREAR, есть в RU_PAYMT
|
|
||||||
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
|
|
||||||
|
|
||||||
Assertions.assertEquals(9, resultMap.size());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
|
|
||||||
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(3).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(7).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlag90days());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testfindFlagsWithoutRuPastduearreae() {
|
|
||||||
jdbcTemplate.getJdbcTemplate().execute(FILL_RU_PAYMT);
|
|
||||||
|
|
||||||
List<Integer> fids = new ArrayList<>(List.of(
|
|
||||||
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
2, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Нет просрочки 90_days в RU_PAYMT
|
|
||||||
3, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
4, // нет никаких просрочек
|
|
||||||
7, // нет просрочки 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
5, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
6, // нет просрочки 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
8, // нету в RU_PASTDUEARREAR, есть в RU_PAYMT
|
|
||||||
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
|
|
||||||
|
|
||||||
Assertions.assertEquals(9, resultMap.size());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(1).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(3).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(5).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
|
|
||||||
|
|
||||||
Assertions.assertEquals(0, resultMap.get(1).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(5).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(6).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(8).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(9).getFlag90days());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LocalDate calcLocalDateFromInitialDate(String date) {
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
long daysPassed = ChronoUnit.DAYS.between(INITIAL_DATE, now);
|
|
||||||
return LocalDate.parse(date).plusDays(daysPassed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,218 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.FlagsService;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class FlagsServiceTest {
|
|
||||||
|
|
||||||
private static final LocalDate INITIAL_DATE = LocalDate.parse("2025-09-25");
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
FlagsMapper flagsMapper;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testfindFlags() {
|
|
||||||
FlagsService flagsService = new FlagsService(flagsMapper, null);
|
|
||||||
|
|
||||||
when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(ruPastDuarearDataList);
|
|
||||||
when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(ruPaymtDataList);
|
|
||||||
|
|
||||||
List<Integer> fids = new ArrayList<>(List.of(
|
|
||||||
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
2, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Нет просрочки 90_days в RU_PAYMT
|
|
||||||
3, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
4, // нет никаких просрочек
|
|
||||||
7, // нет просрочки 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
5, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
6, // нет просрочки 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
8, // нету в RU_PASTDUEARREAR, есть в RU_PAYMT
|
|
||||||
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
|
|
||||||
|
|
||||||
Assertions.assertEquals(9, resultMap.size());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
|
|
||||||
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(6).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(7).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(8).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(9).getFlag90days());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testfindFlagsWithoutRuPaymt() {
|
|
||||||
FlagsService flagsService = new FlagsService(flagsMapper, null);
|
|
||||||
|
|
||||||
when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(ruPastDuarearDataList);
|
|
||||||
when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(new ArrayList<>());
|
|
||||||
|
|
||||||
List<Integer> fids = new ArrayList<>(List.of(
|
|
||||||
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
2, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Нет просрочки 90_days в RU_PAYMT
|
|
||||||
3, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
4, // нет никаких просрочек
|
|
||||||
7, // нет просрочки 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
5, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
6, // нет просрочки 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
8, // нету в RU_PASTDUEARREAR, есть в RU_PAYMT
|
|
||||||
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
|
|
||||||
|
|
||||||
Assertions.assertEquals(9, resultMap.size());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
|
|
||||||
|
|
||||||
Assertions.assertEquals(1, resultMap.get(1).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(3).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(5).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(7).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlag90days());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testfindFlagsWithoutRuPastduearreae() {
|
|
||||||
FlagsService flagsService = new FlagsService(flagsMapper, null);
|
|
||||||
|
|
||||||
when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(new ArrayList<>());
|
|
||||||
when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(ruPaymtDataList);
|
|
||||||
|
|
||||||
List<Integer> fids = new ArrayList<>(List.of(
|
|
||||||
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
2, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Нет просрочки 90_days в RU_PAYMT
|
|
||||||
3, // есть просрочка 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
4, // нет никаких просрочек
|
|
||||||
7, // нет просрочки 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
5, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
|
|
||||||
6, // нет просрочки 5000, нет просрочки 90_days в RU_PASTDUEARREAR. Есть просрочка 90_days в RU_PAYMT
|
|
||||||
8, // нету в RU_PASTDUEARREAR, есть в RU_PAYMT
|
|
||||||
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
|
|
||||||
|
|
||||||
Assertions.assertEquals(9, resultMap.size());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(1).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(3).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(5).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
|
|
||||||
|
|
||||||
Assertions.assertEquals(0, resultMap.get(1).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(3).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(5).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(6).getFlag90days());
|
|
||||||
Assertions.assertEquals(0, resultMap.get(7).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(8).getFlag90days());
|
|
||||||
Assertions.assertEquals(1, resultMap.get(9).getFlag90days());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private final List<FlagsService.RuPastDuarearData> ruPastDuarearDataList = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new FlagsService.RuPastDuarearData(1, BigInteger.valueOf(1), calcLocalDateFromInitialDate("2025-05-31"), BigDecimal.valueOf(36000.00), BigInteger.valueOf(159)), // просрочка 5000 и 90_days по этой записи
|
|
||||||
|
|
||||||
new FlagsService.RuPastDuarearData(2, BigInteger.valueOf(2), calcLocalDateFromInitialDate("2021-12-29"), BigDecimal.valueOf(3200.00), null), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(2, BigInteger.valueOf(2), calcLocalDateFromInitialDate("2022-01-28"), BigDecimal.valueOf(6700.00), null), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(2, BigInteger.valueOf(2), calcLocalDateFromInitialDate("2025-04-06"), BigDecimal.valueOf(5700.00), null), // просрочка 5000 по этой записи
|
|
||||||
|
|
||||||
new FlagsService.RuPastDuarearData(3, BigInteger.valueOf(3), calcLocalDateFromInitialDate("2025-01-14"), BigDecimal.valueOf(300000000000.00), null),
|
|
||||||
|
|
||||||
new FlagsService.RuPastDuarearData(2, BigInteger.valueOf(2), calcLocalDateFromInitialDate("2021-11-29"), BigDecimal.valueOf(0.00), null), // не макс reported_date для того же acc_serial_num
|
|
||||||
|
|
||||||
new FlagsService.RuPastDuarearData(4, BigInteger.valueOf(4), calcLocalDateFromInitialDate("2025-12-06"), BigDecimal.valueOf(4000.00), null), // нет просрочек
|
|
||||||
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2021-04-01"), BigDecimal.valueOf(2000.31), BigInteger.valueOf(182)), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2021-05-01"), BigDecimal.valueOf(2000.31), BigInteger.valueOf(212)), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2021-05-31"), BigDecimal.valueOf(2000.31), null), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2021-07-01"), BigDecimal.valueOf(2000.31), BigInteger.valueOf(273)), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2021-07-31"), BigDecimal.valueOf(2000.31), null), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2021-08-04"), BigDecimal.valueOf(7000.31), BigInteger.valueOf(307)), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2025-09-08"), BigDecimal.valueOf(2000.31), BigInteger.valueOf(338)), // не макс reported_date для того же acc_serial_num, просрочка 90_days будет взята у этой записи
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(51), calcLocalDateFromInitialDate("2025-09-09"), BigDecimal.valueOf(7000.31), BigInteger.valueOf(368)), // Просрочка 5000 будет взята у этой записи. Уникальный acc_serial_num с макс reported_dt
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2021-11-04"), BigDecimal.valueOf(2000.31), BigInteger.valueOf(399)), // не макс reported_date для того же acc_serial_num
|
|
||||||
new FlagsService.RuPastDuarearData(5, BigInteger.valueOf(5), calcLocalDateFromInitialDate("2022-01-04"), BigDecimal.valueOf(5000.31), BigInteger.valueOf(5)), // не макс reported_date для того же acc_serial_num
|
|
||||||
|
|
||||||
new FlagsService.RuPastDuarearData(6, BigInteger.valueOf(6), calcLocalDateFromInitialDate("2025-09-09"), BigDecimal.valueOf(3000), null), // Нет просрочки 5000, нет просрочки 90_days (90_days будет в RU_PAYMT)
|
|
||||||
|
|
||||||
new FlagsService.RuPastDuarearData(7, BigInteger.valueOf(7), calcLocalDateFromInitialDate("2025-09-09"), BigDecimal.valueOf(5500), BigInteger.valueOf(90)), // не макс reported_date для того же acc_serial_num. 90_days будет взята отсюда
|
|
||||||
new FlagsService.RuPastDuarearData(7, BigInteger.valueOf(7), calcLocalDateFromInitialDate("2025-09-10"), BigDecimal.valueOf(3000), null) // Нет просрочки 5000. Уникальный acc_serial_num с макс reported_dt
|
|
||||||
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
private final List<FlagsService.RuPaymtData> ruPaymtDataList = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new FlagsService.RuPaymtData(1, null, calcLocalDateFromInitialDate("2024-11-09")),
|
|
||||||
new FlagsService.RuPaymtData(2, BigInteger.valueOf(30), calcLocalDateFromInitialDate("2024-11-09")),
|
|
||||||
new FlagsService.RuPaymtData(3, null, calcLocalDateFromInitialDate("2024-11-10")),
|
|
||||||
new FlagsService.RuPaymtData(3, BigInteger.valueOf(100), calcLocalDateFromInitialDate("2024-11-15")),
|
|
||||||
new FlagsService.RuPaymtData(4, BigInteger.valueOf(10), calcLocalDateFromInitialDate("2024-11-15")),
|
|
||||||
new FlagsService.RuPaymtData(5, BigInteger.valueOf(10), calcLocalDateFromInitialDate("2023-11-15")),
|
|
||||||
new FlagsService.RuPaymtData(6, BigInteger.valueOf(90), calcLocalDateFromInitialDate("2024-11-09")),
|
|
||||||
new FlagsService.RuPaymtData(6, BigInteger.valueOf(80), calcLocalDateFromInitialDate("2024-10-09")),
|
|
||||||
new FlagsService.RuPaymtData(7, null, calcLocalDateFromInitialDate("2024-10-09")),
|
|
||||||
new FlagsService.RuPaymtData(8, null, calcLocalDateFromInitialDate("2024-10-09")),
|
|
||||||
new FlagsService.RuPaymtData(8, BigInteger.valueOf(83), calcLocalDateFromInitialDate("2024-10-09")),
|
|
||||||
new FlagsService.RuPaymtData(8, BigInteger.valueOf(91), calcLocalDateFromInitialDate("2024-10-09")),
|
|
||||||
new FlagsService.RuPaymtData(9, BigInteger.valueOf(100), calcLocalDateFromInitialDate("2024-10-09"))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
private LocalDate calcLocalDateFromInitialDate(String date) {
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
long daysPassed = ChronoUnit.DAYS.between(INITIAL_DATE, now);
|
|
||||||
return LocalDate.parse(date).plusDays(daysPassed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
|
||||||
import ru.nbch.credit_tracker.repository.PhoneRepository;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.PhoneService;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class PhoneService2Test {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
PhoneRepository phoneRepository;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void defineFidByPhoneTest() {
|
|
||||||
PhoneService phoneService = new PhoneService(phoneRepository);
|
|
||||||
|
|
||||||
fidsDataWithEqualSinceDt.sort(byDbOrder);
|
|
||||||
when(phoneRepository.findFids(any())).thenReturn(fidsDataWithEqualSinceDt);
|
|
||||||
|
|
||||||
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
|
|
||||||
|
|
||||||
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
|
|
||||||
Assertions.assertEquals(4, res.size());
|
|
||||||
Assertions.assertEquals("1111", res.get(124).getPhone());
|
|
||||||
Assertions.assertEquals("1112", res.get(125).getPhone());
|
|
||||||
Assertions.assertEquals("1114", res.get(126).getPhone());
|
|
||||||
Assertions.assertEquals("1115", res.get(127).getPhone());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void defineFidByPhoneTest2() {
|
|
||||||
PhoneService phoneService = new PhoneService(phoneRepository);
|
|
||||||
|
|
||||||
fidsDataWithEqualSinceDt.sort(byDbOrder);
|
|
||||||
when(phoneRepository.findFids(any())).thenReturn(fidsDataWithEqualSinceDt2);
|
|
||||||
|
|
||||||
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
|
|
||||||
|
|
||||||
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
|
|
||||||
Assertions.assertEquals(3, res.size());
|
|
||||||
Assertions.assertEquals("1112", res.get(125).getPhone());
|
|
||||||
Assertions.assertEquals("1114", res.get(126).getPhone());
|
|
||||||
Assertions.assertEquals("1115", res.get(127).getPhone());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void defineFidByPhoneTest3() {
|
|
||||||
PhoneService phoneService = new PhoneService(phoneRepository);
|
|
||||||
|
|
||||||
fidsDataWithEqualSinceDt.sort(byDbOrder);
|
|
||||||
when(phoneRepository.findFids(any())).thenReturn(fidsDataWithEqualSinceDt3);
|
|
||||||
|
|
||||||
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
|
|
||||||
|
|
||||||
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
|
|
||||||
Assertions.assertEquals(2, res.size());
|
|
||||||
Assertions.assertEquals("1114", res.get(126).getPhone());
|
|
||||||
Assertions.assertEquals("1115", res.get(127).getPhone());
|
|
||||||
}
|
|
||||||
|
|
||||||
private final List<PhoneRepository.FidsData> fidsDataWithEqualSinceDt = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new PhoneRepository.FidsData(123, "91111", LocalDate.of(2025, 9, 10)),
|
|
||||||
new PhoneRepository.FidsData(124, "91111", LocalDate.of(2025, 9, 10)),
|
|
||||||
new PhoneRepository.FidsData(125, "91112", LocalDate.of(2024, 10, 10)),
|
|
||||||
new PhoneRepository.FidsData(126, "91114", LocalDate.of(2024, 10, 11)),
|
|
||||||
new PhoneRepository.FidsData(127, "91115", LocalDate.of(2025, 9, 11)),
|
|
||||||
new PhoneRepository.FidsData(128, "91115", LocalDate.of(2025, 9, 10))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
private final List<PhoneRepository.FidsData> fidsDataWithEqualSinceDt2 = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new PhoneRepository.FidsData(125, "91112", LocalDate.of(2024, 10, 10)),
|
|
||||||
new PhoneRepository.FidsData(126, "91114", LocalDate.of(2024, 10, 11)),
|
|
||||||
new PhoneRepository.FidsData(127, "91115", LocalDate.of(2025, 9, 11)),
|
|
||||||
new PhoneRepository.FidsData(128, "91115", LocalDate.of(2025, 9, 10))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
private final List<PhoneRepository.FidsData> fidsDataWithEqualSinceDt3 = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new PhoneRepository.FidsData(126, "91114", LocalDate.of(2024, 10, 11)),
|
|
||||||
new PhoneRepository.FidsData(127, "91115", LocalDate.of(2025, 9, 11)),
|
|
||||||
new PhoneRepository.FidsData(128, "91115", LocalDate.of(2025, 9, 10))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
Comparator<PhoneRepository.FidsData> byDbOrder =
|
|
||||||
Comparator.comparing(PhoneRepository.FidsData::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC
|
|
||||||
.thenComparing(PhoneRepository.FidsData::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC
|
|
||||||
.thenComparing(PhoneRepository.FidsData::getFid, Comparator.reverseOrder());
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void defineFidsAndNameByPhoneTest() {
|
|
||||||
PhoneService phoneService = new PhoneService(phoneRepository);
|
|
||||||
|
|
||||||
// fidsDataWithNameEqualSinceDt.sort(byDbOrderWithName);
|
|
||||||
when(phoneRepository.findFidsWithName(any())).thenReturn(fidsDataWithNameEqualSinceDt);
|
|
||||||
|
|
||||||
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
|
|
||||||
|
|
||||||
Map<Integer, PhoneFidMap> res = phoneService.defineFidsAndNameByPhone(phoneFidMap);
|
|
||||||
Assertions.assertEquals(4, res.size());
|
|
||||||
Assertions.assertEquals("1111", res.get(124).getPhone());
|
|
||||||
Assertions.assertEquals("1112", res.get(125).getPhone());
|
|
||||||
Assertions.assertEquals("1114", res.get(126).getPhone());
|
|
||||||
Assertions.assertEquals("1115", res.get(127).getPhone());
|
|
||||||
|
|
||||||
Assertions.assertEquals("found124", res.get(124).getFirstName());
|
|
||||||
Assertions.assertNull(res.get(125).getFirstName());
|
|
||||||
Assertions.assertEquals("found126", res.get(126).getFirstName());
|
|
||||||
Assertions.assertNull(res.get(128));
|
|
||||||
|
|
||||||
}
|
|
||||||
private final List<PhoneRepository.FidsDataWithName> fidsDataWithNameEqualSinceDt = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new PhoneRepository.FidsDataWithName(123, "91111", LocalDate.of(2025, 9, 10), "skip", null, null, null, null),
|
|
||||||
new PhoneRepository.FidsDataWithName(123, "91111", LocalDate.of(2025, 9, 10), "skip", null, null, null, LocalDate.of(2025, 10, 9)),
|
|
||||||
new PhoneRepository.FidsDataWithName(124, "91111", LocalDate.of(2025, 9, 9), "found124", null, null, null, LocalDate.of(2025, 9, 9)),
|
|
||||||
new PhoneRepository.FidsDataWithName(124, "91111", LocalDate.of(2025, 9, 10), "skip124", null, null, null, LocalDate.of(2025, 9, 8)),
|
|
||||||
new PhoneRepository.FidsDataWithName(124, "91111", LocalDate.of(2025, 9, 9), "skip124", null, null, null, LocalDate.of(2025, 9, 8)),
|
|
||||||
new PhoneRepository.FidsDataWithName(124, "91111", LocalDate.of(2025, 9, 10), "found124", null, null, null, LocalDate.of(2025, 9, 9)),
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
new PhoneRepository.FidsDataWithName(125, "91112", LocalDate.of(2024, 10, 10), null, null, null, null, null),
|
|
||||||
|
|
||||||
new PhoneRepository.FidsDataWithName(126, "91114", LocalDate.of(2024, 10, 11), "skip126", null, null, null, null),
|
|
||||||
new PhoneRepository.FidsDataWithName(126, "91114", LocalDate.of(2024, 10, 11), "found126", null, null, null, LocalDate.of(2025, 9, 9)),
|
|
||||||
new PhoneRepository.FidsDataWithName(126, "91114", LocalDate.of(2024, 10, 5), "found126", null, null, null, LocalDate.of(2025, 9, 9)),
|
|
||||||
new PhoneRepository.FidsDataWithName(126, "91114", LocalDate.of(2024, 10, 5), "skip126", null, null, null, null),
|
|
||||||
|
|
||||||
|
|
||||||
new PhoneRepository.FidsDataWithName(127, "91115", LocalDate.of(2025, 9, 11), null, null, null, null, null),
|
|
||||||
new PhoneRepository.FidsDataWithName(128, "91115", LocalDate.of(2025, 9, 10), "found128", null, null, null, LocalDate.of(2025, 9, 9))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
//todo понять зачем в тесте использовался этот компоратор
|
|
||||||
// Comparator<PhoneRepository.FidsDataWithName> byDbOrderWithName =
|
|
||||||
// Comparator.comparing(PhoneRepository.FidsDataWithName::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC
|
|
||||||
// .thenComparing(PhoneRepository.FidsDataWithName::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC
|
|
||||||
// .thenComparing(PhoneRepository.FidsDataWithName::getFid, Comparator.reverseOrder());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
|
||||||
import ru.nbch.credit_tracker.repository.PhoneRepository;
|
|
||||||
import ru.nbch.credit_tracker.service.indic.PhoneService;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class PhoneServiceTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
PhoneRepository phoneRepository;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void defineFidByPhoneTest() {
|
|
||||||
PhoneService phoneService = new PhoneService(phoneRepository);
|
|
||||||
|
|
||||||
fidsDataWithEqualSinceDt.sort(byDbOrder);
|
|
||||||
when(phoneRepository.findFidsLong(any())).thenReturn(fidsDataWithEqualSinceDt);
|
|
||||||
|
|
||||||
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
|
|
||||||
|
|
||||||
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
|
|
||||||
Assertions.assertEquals(4, res.size());
|
|
||||||
Assertions.assertEquals("1111", res.get(124).getPhone());
|
|
||||||
Assertions.assertEquals("1112", res.get(125).getPhone());
|
|
||||||
Assertions.assertEquals("1114", res.get(126).getPhone());
|
|
||||||
Assertions.assertEquals("1115", res.get(127).getPhone());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void defineFidByPhoneTest2() {
|
|
||||||
PhoneService phoneService = new PhoneService(phoneRepository);
|
|
||||||
|
|
||||||
fidsDataWithEqualSinceDt.sort(byDbOrder);
|
|
||||||
when(phoneRepository.findFidsLong(any())).thenReturn(fidsDataWithEqualSinceDt2);
|
|
||||||
|
|
||||||
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
|
|
||||||
|
|
||||||
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
|
|
||||||
Assertions.assertEquals(3, res.size());
|
|
||||||
Assertions.assertEquals("1112", res.get(125).getPhone());
|
|
||||||
Assertions.assertEquals("1114", res.get(126).getPhone());
|
|
||||||
Assertions.assertEquals("1115", res.get(127).getPhone());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void defineFidByPhoneTest3() {
|
|
||||||
PhoneService phoneService = new PhoneService(phoneRepository);
|
|
||||||
|
|
||||||
fidsDataWithEqualSinceDt.sort(byDbOrder);
|
|
||||||
when(phoneRepository.findFidsLong(any())).thenReturn(fidsDataWithEqualSinceDt3);
|
|
||||||
|
|
||||||
List<PhoneFidMap> phoneFidMap = new ArrayList<>();
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1111").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1112").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1113").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1114").build());
|
|
||||||
phoneFidMap.add(PhoneFidMap.builder().phone("1115").build());
|
|
||||||
|
|
||||||
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
|
|
||||||
Assertions.assertEquals(2, res.size());
|
|
||||||
Assertions.assertEquals("1114", res.get(126).getPhone());
|
|
||||||
Assertions.assertEquals("1115", res.get(127).getPhone());
|
|
||||||
}
|
|
||||||
|
|
||||||
private final List<PhoneRepository.FidsDataLong> fidsDataWithEqualSinceDt = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new PhoneRepository.FidsDataLong(123, 91111L, LocalDate.of(2025, 9, 10)),
|
|
||||||
new PhoneRepository.FidsDataLong(124, 91111L, LocalDate.of(2025, 9, 10)),
|
|
||||||
new PhoneRepository.FidsDataLong(125, 91112L, LocalDate.of(2024, 10, 10)),
|
|
||||||
new PhoneRepository.FidsDataLong(126, 91114L, LocalDate.of(2024, 10, 11)),
|
|
||||||
new PhoneRepository.FidsDataLong(127, 91115L, LocalDate.of(2025, 9, 11)),
|
|
||||||
new PhoneRepository.FidsDataLong(128, 91115L, LocalDate.of(2025, 9, 10))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
private final List<PhoneRepository.FidsDataLong> fidsDataWithEqualSinceDt2 = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new PhoneRepository.FidsDataLong(125, 91112L, LocalDate.of(2024, 10, 10)),
|
|
||||||
new PhoneRepository.FidsDataLong(126, 91114L, LocalDate.of(2024, 10, 11)),
|
|
||||||
new PhoneRepository.FidsDataLong(127, 91115L, LocalDate.of(2025, 9, 11)),
|
|
||||||
new PhoneRepository.FidsDataLong(128, 91115L, LocalDate.of(2025, 9, 10))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
private final List<PhoneRepository.FidsDataLong> fidsDataWithEqualSinceDt3 = new ArrayList<>(
|
|
||||||
List.of(
|
|
||||||
new PhoneRepository.FidsDataLong(126, 91114L, LocalDate.of(2024, 10, 11)),
|
|
||||||
new PhoneRepository.FidsDataLong(127, 91115L, LocalDate.of(2025, 9, 11)),
|
|
||||||
new PhoneRepository.FidsDataLong(128, 91115L, LocalDate.of(2025, 9, 10))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
Comparator<PhoneRepository.FidsDataLong> byDbOrder =
|
|
||||||
Comparator.comparing(PhoneRepository.FidsDataLong::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC
|
|
||||||
.thenComparing(PhoneRepository.FidsDataLong::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC
|
|
||||||
.thenComparing(PhoneRepository.FidsDataLong::getFid, Comparator.reverseOrder());
|
|
||||||
}
|
|
||||||
|
|
@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_error.MonitoringReportErrors;
|
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_error.MonitoringReportErrors;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Person;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Person;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Persons;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Persons;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue