logging rest request; logging query time for every mapper; optimization query and refactoring some methods
This commit is contained in:
parent
fdbec299d6
commit
bddc5bb1fa
14 changed files with 482 additions and 192 deletions
139
pom.xml
139
pom.xml
|
|
@ -27,6 +27,10 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mybatis.spring.boot</groupId>
|
<groupId>org.mybatis.spring.boot</groupId>
|
||||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||||
|
|
@ -122,8 +126,83 @@
|
||||||
<version>3.0.4</version>
|
<version>3.0.4</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>docker-push-dev</id>
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>io.fabric8</groupId>
|
||||||
|
<artifactId>docker-maven-plugin</artifactId>
|
||||||
|
<version>0.45.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>Build and deploy docker container</id>
|
||||||
|
<phase>install</phase>
|
||||||
|
<goals>
|
||||||
|
<!--<goal>build</goal>-->
|
||||||
|
<goal>push</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<images>
|
||||||
|
<image>
|
||||||
|
<name>${project.artifactId}:${project.version}</name>
|
||||||
|
<registry>${registry.url}</registry>
|
||||||
|
<build>
|
||||||
|
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
|
||||||
|
<assembly>
|
||||||
|
<inline>
|
||||||
|
<files>
|
||||||
|
<file>
|
||||||
|
<source>${project.build.directory}/${project.build.finalName}.jar</source>
|
||||||
|
<outputDirectory>.</outputDirectory>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<source>${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar</source>
|
||||||
|
<outputDirectory>.</outputDirectory>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<source>${project.basedir}/start-credit-tracker.sh</source>
|
||||||
|
<outputDirectory>.</outputDirectory>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<source>${project.basedir}/credit-tracker.properties</source>
|
||||||
|
<outputDirectory>.</outputDirectory>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<source>${project.basedir}/monitoring-request.xsd</source>
|
||||||
|
<outputDirectory>.</outputDirectory>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<source>${project.basedir}/signal-package.xsd</source>
|
||||||
|
<outputDirectory>.</outputDirectory>
|
||||||
|
</file>
|
||||||
|
</files>
|
||||||
|
</inline>
|
||||||
|
</assembly>
|
||||||
|
<tags>
|
||||||
|
<tag>${project.version}</tag>
|
||||||
|
</tags>
|
||||||
|
</build>
|
||||||
|
</image>
|
||||||
|
</images>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
<build>
|
<build>
|
||||||
<finalName>credit-tracker</finalName>
|
<finalName>credit-tracker</finalName>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|
@ -181,65 +260,7 @@
|
||||||
</includeOnlyProperties>
|
</includeOnlyProperties>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>io.fabric8</groupId>
|
|
||||||
<artifactId>docker-maven-plugin</artifactId>
|
|
||||||
<version>0.45.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>Build and deploy docker container</id>
|
|
||||||
<phase>install</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>build</goal>
|
|
||||||
<goal>push</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<images>
|
|
||||||
<image>
|
|
||||||
<name>${project.artifactId}:${project.version}</name>
|
|
||||||
<registry>${registry.url}</registry>
|
|
||||||
<build>
|
|
||||||
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
|
|
||||||
<assembly>
|
|
||||||
<inline>
|
|
||||||
<files>
|
|
||||||
<file>
|
|
||||||
<source>${project.build.directory}/${project.build.finalName}.jar</source>
|
|
||||||
<outputDirectory>.</outputDirectory>
|
|
||||||
</file>
|
|
||||||
<file>
|
|
||||||
<source>${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar</source>
|
|
||||||
<outputDirectory>.</outputDirectory>
|
|
||||||
</file>
|
|
||||||
<file>
|
|
||||||
<source>${project.basedir}/start-credit-tracker.sh</source>
|
|
||||||
<outputDirectory>.</outputDirectory>
|
|
||||||
</file>
|
|
||||||
<file>
|
|
||||||
<source>${project.basedir}/credit-tracker.properties</source>
|
|
||||||
<outputDirectory>.</outputDirectory>
|
|
||||||
</file>
|
|
||||||
<file>
|
|
||||||
<source>${project.basedir}/monitoring-request.xsd</source>
|
|
||||||
<outputDirectory>.</outputDirectory>
|
|
||||||
</file>
|
|
||||||
<file>
|
|
||||||
<source>${project.basedir}/signal-package.xsd</source>
|
|
||||||
<outputDirectory>.</outputDirectory>
|
|
||||||
</file>
|
|
||||||
</files>
|
|
||||||
</inline>
|
|
||||||
</assembly>
|
|
||||||
<tags>
|
|
||||||
<tag>${project.version}</tag>
|
|
||||||
</tags>
|
|
||||||
</build>
|
|
||||||
</image>
|
|
||||||
</images>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
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 MapperTimingAspect {
|
||||||
|
@Around("within(@org.apache.ibatis.annotations.Mapper *)")
|
||||||
|
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 > 200) {
|
||||||
|
log.warn("Slow mapper call {} took {} ms", method, tookMs);
|
||||||
|
} else {
|
||||||
|
log.debug("Mapper call {} took {} ms", method, tookMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
package ru.nbch.credit_tracker.config.rest.filters;
|
||||||
|
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||||
|
import org.springframework.web.util.ContentCachingResponseWrapper;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@Order(0)
|
||||||
|
public class HttpLoggingFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private static final Set<String> SENSITIVE_HEADERS = Set.of("authorization", "cookie", "set-cookie");
|
||||||
|
private static final int MAX_BODY = 10 * 1024;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||||
|
String path = request.getRequestURI();
|
||||||
|
return path.startsWith("/actuator/health") || path.startsWith("/swagger")
|
||||||
|
|| path.startsWith("/v3/api-docs") || path.startsWith("/static/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
long startNs = System.nanoTime();
|
||||||
|
|
||||||
|
ContentCachingRequestWrapper req = wrapRequest(request);
|
||||||
|
ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response);
|
||||||
|
|
||||||
|
String correlationId = Optional.ofNullable(request.getHeader("X-Correlation-Id"))
|
||||||
|
.filter(StringUtils::hasText)
|
||||||
|
.orElse(UUID.randomUUID().toString());
|
||||||
|
resp.setHeader("X-Correlation-Id", correlationId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
chain.doFilter(req, resp);
|
||||||
|
} finally {
|
||||||
|
long tookMs = (System.nanoTime() - startNs) / 1_000_000;
|
||||||
|
|
||||||
|
String requestBody = readBody(req.getContentAsByteArray(), req.getCharacterEncoding());
|
||||||
|
String responseBody = readBody(resp.getContentAsByteArray(), resp.getCharacterEncoding());
|
||||||
|
|
||||||
|
Map<String, String> reqHeaders = headersMap(req);
|
||||||
|
Map<String, String> respHeaders = headersMap(resp);
|
||||||
|
|
||||||
|
mask(reqHeaders);
|
||||||
|
mask(respHeaders);
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"HTTP {} {}{} | status={} | took={}ms | cid={} | reqHeaders={} | reqBody={} | respHeaders={} | respBody={}",
|
||||||
|
req.getMethod(),
|
||||||
|
req.getRequestURI(),
|
||||||
|
req.getQueryString() == null ? "" : "?" + req.getQueryString(),
|
||||||
|
resp.getStatus(),
|
||||||
|
tookMs,
|
||||||
|
correlationId,
|
||||||
|
reqHeaders,
|
||||||
|
requestBody,
|
||||||
|
respHeaders,
|
||||||
|
responseBody
|
||||||
|
);
|
||||||
|
|
||||||
|
resp.copyBodyToResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) {
|
||||||
|
return (request instanceof ContentCachingRequestWrapper c) ? c : new ContentCachingRequestWrapper(request, MAX_BODY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readBody(byte[] buf, String encoding) {
|
||||||
|
if (buf == null || buf.length == 0) return "";
|
||||||
|
var bytes = buf.length > MAX_BODY ? Arrays.copyOf(buf, MAX_BODY) : buf;
|
||||||
|
String body = new String(bytes, encoding != null ? java.nio.charset.Charset.forName(encoding) : StandardCharsets.UTF_8);
|
||||||
|
if (buf.length > MAX_BODY) body += "…[truncated]";
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> headersMap(HttpServletRequest req) {
|
||||||
|
return Collections.list(req.getHeaderNames()).stream()
|
||||||
|
.collect(Collectors.toMap(h -> h, req::getHeader, (a, b) -> a, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> headersMap(HttpServletResponse resp) {
|
||||||
|
return resp.getHeaderNames().stream()
|
||||||
|
.collect(Collectors.toMap(h -> h, resp::getHeader, (a, b) -> a, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void mask(Map<String, String> headers) {
|
||||||
|
headers.replaceAll((k, v) -> SENSITIVE_HEADERS.contains(k.toLowerCase()) ? "***" : v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ public interface PhoneFidMapMapper {
|
||||||
List<PhoneFidMap> findFullPhoneFidMap(@Param("packageId") Integer packageId, @Param("offset") int offset, @Param("limit") int limit);
|
List<PhoneFidMap> findFullPhoneFidMap(@Param("packageId") Integer packageId, @Param("offset") int offset, @Param("limit") int limit);
|
||||||
|
|
||||||
void updatePhoneFidMaps(@Param("subjects") List<PhoneFidMap> subjects);
|
void updatePhoneFidMaps(@Param("subjects") List<PhoneFidMap> subjects);
|
||||||
|
void updatePhoneFid(@Param("subject") PhoneFidMap subject);
|
||||||
|
|
||||||
void updatePhoneFidMapsErrors(@Param("subjects") List<PhoneFidMap> subjects);
|
void updatePhoneFidMapsErrors(@Param("subjects") List<PhoneFidMap> subjects);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,22 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
package ru.nbch.credit_tracker.service;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
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.dto.Hit;
|
import ru.nbch.credit_tracker.entities.dto.Hit;
|
||||||
|
|
@ -22,21 +36,6 @@ import ru.nbch.credit_tracker.service.xml.stax.MonitoringSignalResponseStaxXmlWr
|
||||||
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
|
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
import ru.nbch.credit_tracker.utils.CTUtil;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipOutputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сервис периодического опроса официального сервиса сигналов на наличие новых отчетов по пакетам находящимся в статусе ON_MONITORING
|
* Сервис периодического опроса официального сервиса сигналов на наличие новых отчетов по пакетам находящимся в статусе ON_MONITORING
|
||||||
*/
|
*/
|
||||||
|
|
@ -60,9 +59,9 @@ public class MonitoringService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("monitoring-"));
|
// ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("monitoring-"));
|
||||||
long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15;
|
// long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15;
|
||||||
scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES);
|
// scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void monitor() {
|
private void monitor() {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ 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.mapper.signal.PhoneFidMapMapper;
|
||||||
import ru.nbch.credit_tracker.service.indic.FlagsService;
|
import ru.nbch.credit_tracker.service.indic.FlagsService;
|
||||||
import ru.nbch.credit_tracker.service.indic.PersonService;
|
import ru.nbch.credit_tracker.service.indic.PersonService;
|
||||||
import ru.nbch.credit_tracker.service.indic.PhoneService;
|
import ru.nbch.credit_tracker.service.indic.PhoneService;
|
||||||
|
|
@ -43,6 +44,7 @@ public class SignalService {
|
||||||
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 PhoneFidMapMapper phoneFidMapMapper;
|
||||||
private final PhoneService phoneService;
|
private final PhoneService phoneService;
|
||||||
private final FlagsService flagsService;
|
private final FlagsService flagsService;
|
||||||
private final PersonService personService;
|
private final PersonService personService;
|
||||||
|
|
@ -54,6 +56,7 @@ public class SignalService {
|
||||||
HitsService hitsService,
|
HitsService hitsService,
|
||||||
UserPackageService userPackageService,
|
UserPackageService userPackageService,
|
||||||
PhoneFidMapService phoneFidMapService,
|
PhoneFidMapService phoneFidMapService,
|
||||||
|
PhoneFidMapMapper mapper,
|
||||||
PhoneService phoneService,
|
PhoneService phoneService,
|
||||||
FlagsService flagsService,
|
FlagsService flagsService,
|
||||||
PersonService personService,
|
PersonService personService,
|
||||||
|
|
@ -62,6 +65,7 @@ public class SignalService {
|
||||||
this.hitsService = hitsService;
|
this.hitsService = hitsService;
|
||||||
this.userPackageService = userPackageService;
|
this.userPackageService = userPackageService;
|
||||||
this.phoneFidMapService = phoneFidMapService;
|
this.phoneFidMapService = phoneFidMapService;
|
||||||
|
this.phoneFidMapMapper = mapper;
|
||||||
this.phoneService = phoneService;
|
this.phoneService = phoneService;
|
||||||
this.flagsService = flagsService;
|
this.flagsService = flagsService;
|
||||||
this.personService = personService;
|
this.personService = personService;
|
||||||
|
|
@ -125,7 +129,7 @@ public class SignalService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filteredItems.isEmpty()) {
|
if (!filteredItems.isEmpty()) {
|
||||||
boolean fidsFound = updateFlags(filteredItems, packageId);
|
boolean fidsFound = updateFlags2(filteredItems, packageId);
|
||||||
if (noFidsFound) {
|
if (noFidsFound) {
|
||||||
noFidsFound = !fidsFound;
|
noFidsFound = !fidsFound;
|
||||||
}
|
}
|
||||||
|
|
@ -187,6 +191,26 @@ public class SignalService {
|
||||||
return fidsFound;
|
return fidsFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean updateFlags2(List<PhoneFidMap> subjects, Integer packageId) {
|
||||||
|
log.info("Start calculating fids and flags for subjects batch. PackageId: {}", packageId);
|
||||||
|
Map<Integer, PhoneFidMap> fidsMap = phoneService.defineFidByPhone(subjects);
|
||||||
|
Map<Integer, FlagsService.FlagsData> flagsDataMap = flagsService.findFlags(fidsMap.keySet().stream().toList());
|
||||||
|
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);
|
||||||
|
phoneFidMap.setFlagDebt5000(flagsData.getFlagDebt5000());
|
||||||
|
phoneFidMap.setFlag90days(flagsData.getFlag90days());
|
||||||
|
phoneFidMap.setCalculatedAt(LocalDateTime.now());
|
||||||
|
|
||||||
|
phoneFidMapMapper.updatePhoneFid(phoneFidMap);
|
||||||
|
}
|
||||||
|
log.info("Finish calculating fids and flags for subjects. PackageId: {}. Batch size: {}", packageId, subjects.size());
|
||||||
|
return !fidsMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public void rejectPackage(MonitoringRequest request) {
|
public void rejectPackage(MonitoringRequest request) {
|
||||||
UserPackage userPackage = UserPackage.builder()
|
UserPackage userPackage = UserPackage.builder()
|
||||||
.userId(request.getUserId())
|
.userId(request.getUserId())
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
package ru.nbch.credit_tracker.service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
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.dto.PhoneFidMap;
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
|
|
@ -9,14 +12,6 @@ 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;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сервис периодического обновления фидов и флагов просрочек по пакетам находящимся в статусе ON_MONITORING
|
* Сервис периодического обновления фидов и флагов просрочек по пакетам находящимся в статусе ON_MONITORING
|
||||||
* По обновленным пакетам формируется новый запрос постановки на мониторинг в официальный сервис сигналов
|
* По обновленным пакетам формируется новый запрос постановки на мониторинг в официальный сервис сигналов
|
||||||
|
|
@ -43,8 +38,8 @@ public class UpdatingFlagsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("updating-flags-"));
|
// ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("updating-flags-"));
|
||||||
scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS);
|
// scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update() {
|
private void update() {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
package ru.nbch.credit_tracker.service.indic;
|
package ru.nbch.credit_tracker.service.indic;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
|
||||||
|
|
||||||
@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;
|
||||||
|
|
||||||
public FlagsService(FlagsMapper mapper) {
|
public FlagsService(FlagsMapper mapper) {
|
||||||
|
|
@ -25,11 +26,13 @@ public class FlagsService {
|
||||||
if (fids.isEmpty()) {
|
if (fids.isEmpty()) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
Map<Integer, FlagsData> result = new HashMap<>();
|
List<Integer> distinctFids = fids.stream().distinct().toList();
|
||||||
Map<Integer, Integer> flags5000 = calcFlag5000(fids);
|
log.debug("Fids count: {}", distinctFids.size());
|
||||||
Map<Integer, Integer> flags90DaysByPastDueArrear = calcFlag90DaysByPastDueArrear(fids);
|
Map<Integer, Integer> flags5000 = calcFlag5000(distinctFids);
|
||||||
Map<Integer, Integer> flags90DaysByRuPaymt = calcFlag90DaysByRuPaymt(fids);
|
Map<Integer, Integer> flags90DaysByPastDueArrear = calcFlag90DaysByPastDueArrear(distinctFids);
|
||||||
|
Map<Integer, Integer> flags90DaysByRuPaymt = calcFlag90DaysByRuPaymt(distinctFids);
|
||||||
|
|
||||||
|
Map<Integer, FlagsData> result = new HashMap<>();
|
||||||
fids.forEach(fid -> {
|
fids.forEach(fid -> {
|
||||||
Integer flagDebt5000 = flags5000.get(fid);
|
Integer flagDebt5000 = flags5000.get(fid);
|
||||||
if (flagDebt5000 == null) {
|
if (flagDebt5000 == null) {
|
||||||
|
|
@ -55,15 +58,11 @@ public class FlagsService {
|
||||||
* Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 0.
|
* Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 0.
|
||||||
*/
|
*/
|
||||||
private Map<Integer, Integer> calcFlag5000(List<Integer> fids) {
|
private Map<Integer, Integer> calcFlag5000(List<Integer> fids) {
|
||||||
return mapper.findFlagsDebt5000(fids).stream()
|
log.debug("Start calculating flag 5000");
|
||||||
.collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag,
|
List<FlagFidData> rows = mapper.findFlagsDebt5000(fids);
|
||||||
(existing, replacement) -> {
|
Map<Integer, Integer> res = makeFidFlagMapByRs(fids, rows);
|
||||||
if (existing == 1) {
|
log.debug("Complete calculating flag 5000");
|
||||||
return existing;
|
return res;
|
||||||
} else {
|
|
||||||
return replacement;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,31 +71,33 @@ public class FlagsService {
|
||||||
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
||||||
*/
|
*/
|
||||||
private Map<Integer, Integer> calcFlag90DaysByPastDueArrear(List<Integer> fids) {
|
private Map<Integer, Integer> calcFlag90DaysByPastDueArrear(List<Integer> fids) {
|
||||||
|
log.debug("Start calculating flag 90 by PastDueArrear");
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
||||||
return mapper.findFlag90ByPastDueArrear(fids, yearAgo).stream()
|
List<FlagFidData> rows = mapper.findFlag90ByPastDueArrear(fids, yearAgo);
|
||||||
.collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag,
|
Map<Integer, Integer> res = makeFidFlagMapByRs(fids, rows);
|
||||||
(existing, replacement) -> {
|
log.debug("Complete calculating flag 90 by PastDueArrear");
|
||||||
if (existing == 1) {
|
return res;
|
||||||
return existing;
|
|
||||||
} else {
|
|
||||||
return replacement;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Integer, Integer> calcFlag90DaysByRuPaymt(List<Integer> fids) {
|
private Map<Integer, Integer> calcFlag90DaysByRuPaymt(List<Integer> fids) {
|
||||||
|
log.debug("Start calculating flag 90 by ruPaymt");
|
||||||
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
||||||
return mapper.findFlag90ByRuPaymt(fids, yearAgo).stream()
|
List<FlagFidData> rows = mapper.findFlag90ByRuPaymt(fids, yearAgo);
|
||||||
.collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag,
|
Map<Integer, Integer> res = makeFidFlagMapByRs(fids, rows);
|
||||||
(existing, replacement) -> {
|
log.debug("Complete calculating flag 90 by ruPaymt");
|
||||||
if (existing == 1) {
|
return res;
|
||||||
return existing;
|
|
||||||
} else {
|
|
||||||
return replacement;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<Integer, Integer> makeFidFlagMapByRs(List<Integer> fids, List<FlagFidData> rows) {
|
||||||
|
Map<Integer, Integer> result = new HashMap<>();
|
||||||
|
for (Integer fid : fids) {
|
||||||
|
result.put(fid, 0);
|
||||||
|
}
|
||||||
|
for (FlagFidData row : rows) {
|
||||||
|
result.put(row.getFid(), row.getFlag() != null ? row.getFlag() : 0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
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.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
|
import ru.nbch.credit_tracker.mapper.indic.PhoneMapper;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PhoneService {
|
public class PhoneService {
|
||||||
|
|
@ -31,6 +33,37 @@ public class PhoneService {
|
||||||
return convertFidsDataToMap(mapper.findFids(phones));
|
return convertFidsDataToMap(mapper.findFids(phones));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<Integer, PhoneFidMap> defineFidByPhone(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()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
//отсортированный список по NUMBER, FID и FILE_SINCE_DT
|
||||||
|
List<FidsData> phonesByFid = mapper.findFids(phones);
|
||||||
|
Iterator<FidsData> iterator = phonesByFid.iterator();
|
||||||
|
for (PhoneFidMap phoneFid : subjects) {
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
FidsData fidsData = iterator.next();
|
||||||
|
if (fidsData.getPhone().equals(phoneFid.getPhone())) {
|
||||||
|
//fixme доступ по ссылке, страшно, придумать что-то еще
|
||||||
|
phoneFidMap.put(fidsData.getFid(), phoneFid);
|
||||||
|
iterator.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return phoneFidMap;
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Integer> convertFidsDataToMap(List<FidsData> fidsData) {
|
private Map<String, Integer> convertFidsDataToMap(List<FidsData> fidsData) {
|
||||||
if (fidsData == null || fidsData.isEmpty()) {
|
if (fidsData == null || fidsData.isEmpty()) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
|
|
@ -50,6 +83,8 @@ public class PhoneService {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public static class FidsData {
|
public static class FidsData {
|
||||||
private Integer fid;
|
private Integer fid;
|
||||||
private String phone;
|
private String phone;
|
||||||
|
|
|
||||||
|
|
@ -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} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
<charset>utf-8</charset>
|
<charset>utf-8</charset>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
|
||||||
|
|
@ -11,70 +11,70 @@
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<select id="findFlagsDebt5000" resultMap="FlagsFidDataResultMap">
|
<select id="findFlagsDebt5000" resultMap="FlagsFidDataResultMap">
|
||||||
SELECT rp.FID as fid,
|
WITH latest AS (
|
||||||
CASE
|
SELECT
|
||||||
WHEN EXISTS (SELECT 1
|
fid,
|
||||||
FROM RU_PASTDUEARREAR rp2
|
acc_serial_num,
|
||||||
WHERE rp2.FID = rp.FID
|
amt_past_due,
|
||||||
AND rp2.ACC_SERIAL_NUM = rp.ACC_SERIAL_NUM
|
ROW_NUMBER() OVER (PARTITION BY fid, acc_serial_num ORDER BY reported_dt DESC) AS rn
|
||||||
AND rp2.REPORTED_DT = rp.MAX_REP_DATE
|
|
||||||
AND rp2.AMT_PAST_DUE > 5000) THEN 1
|
|
||||||
ELSE 0
|
|
||||||
END as flag
|
|
||||||
FROM (SELECT FID,
|
|
||||||
ACC_SERIAL_NUM,
|
|
||||||
MAX(REPORTED_DT) as MAX_REP_DATE
|
|
||||||
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, ACC_SERIAL_NUM) rp
|
SELECT
|
||||||
GROUP BY rp.FID, rp.ACC_SERIAL_NUM, rp.MAX_REP_DATE
|
fid,
|
||||||
|
CASE WHEN SUM(CASE WHEN amt_past_due > 5000 THEN 1 ELSE 0 END) > 0
|
||||||
|
THEN 1 ELSE 0
|
||||||
|
END AS flag
|
||||||
|
FROM latest WHERE rn = 1
|
||||||
|
GROUP BY fid
|
||||||
WITH UR
|
WITH UR
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findFlag90ByPastDueArrear" resultMap="FlagsFidDataResultMap">
|
<select id="findFlag90ByPastDueArrear" resultMap="FlagsFidDataResultMap">
|
||||||
SELECT rp.FID as fid,
|
WITH latest AS (
|
||||||
CASE
|
SELECT
|
||||||
WHEN EXISTS (SELECT 1
|
r.fid,
|
||||||
FROM RU_PASTDUEARREAR rp2
|
r.days_past_due,
|
||||||
WHERE rp2.FID = rp.FID
|
ROW_NUMBER() OVER (PARTITION BY r.fid ORDER BY r.reported_dt DESC) AS rn
|
||||||
AND rp2.REPORTED_DT >= #{reportedDate}
|
FROM RU_PASTDUEARREAR r
|
||||||
AND rp2.DAYS_PAST_DUE > 90) THEN 1
|
WHERE r.fid IN
|
||||||
ELSE 0
|
|
||||||
END as flag
|
|
||||||
FROM (SELECT FID,
|
|
||||||
DAYS_PAST_DUE
|
|
||||||
FROM RU_PASTDUEARREAR
|
|
||||||
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, DAYS_PAST_DUE) rp
|
AND r.reported_dt >= #{reportedDate}
|
||||||
GROUP BY rp.FID, rp.DAYS_PAST_DUE
|
)
|
||||||
|
SELECT
|
||||||
|
fid,
|
||||||
|
CASE WHEN MAX(CASE WHEN days_past_due > 90 THEN 1 ELSE 0 END) = 1
|
||||||
|
THEN 1 ELSE 0
|
||||||
|
END AS flag
|
||||||
|
FROM latest WHERE rn = 1
|
||||||
|
GROUP BY fid
|
||||||
WITH UR
|
WITH UR
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="findFlag90ByRuPaymt" resultMap="FlagsFidDataResultMap">
|
<select id="findFlag90ByRuPaymt" resultMap="FlagsFidDataResultMap">
|
||||||
SELECT rp.FID as fid,
|
WITH latest AS (
|
||||||
CASE
|
SELECT
|
||||||
WHEN EXISTS (SELECT 1
|
r.fid,
|
||||||
FROM RU_PAYMT rp2
|
r.days_past_due,
|
||||||
WHERE rp2.FID = rp.FID
|
ROW_NUMBER() OVER (PARTITION BY r.fid ORDER BY r.reported_dt DESC) AS rn
|
||||||
AND rp2.REPORTED_DT >= #{reportedDate}
|
FROM RU_PAYMT r
|
||||||
AND rp2.DAYS_PAST_DUE > 90) THEN 1
|
WHERE r.fid IN
|
||||||
ELSE 0
|
|
||||||
END as flag
|
|
||||||
FROM (SELECT FID,
|
|
||||||
DAYS_PAST_DUE
|
|
||||||
FROM RU_PAYMT
|
|
||||||
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, DAYS_PAST_DUE) rp
|
AND r.reported_dt >= #{reportedDate}
|
||||||
GROUP BY rp.FID, rp.DAYS_PAST_DUE
|
)
|
||||||
|
SELECT
|
||||||
|
fid,
|
||||||
|
CASE WHEN MAX(CASE WHEN days_past_due > 90 THEN 1 ELSE 0 END) = 1
|
||||||
|
THEN 1 ELSE 0
|
||||||
|
END AS flag
|
||||||
|
FROM latest WHERE rn = 1
|
||||||
|
GROUP BY fid
|
||||||
WITH UR
|
WITH UR
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -12,14 +12,21 @@
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<select id="findFids" resultMap="fidsDataResultMap">
|
<select id="findFids" resultMap="fidsDataResultMap">
|
||||||
SELECT pn.NUMBER AS number, pn.FID AS fid, pn.FILE_SINCE_DT AS fileSinceDate
|
SELECT
|
||||||
FROM PHONE_NORM pn
|
pn.number,
|
||||||
INNER JOIN NAME n ON n.FID = pn.FID
|
pn.fid,
|
||||||
|
pn.file_since_dt
|
||||||
|
FROM indic.PHONE_NORM pn
|
||||||
|
JOIN (SELECT DISTINCT fid FROM indic.NAME) nf
|
||||||
|
ON nf.fid = pn.fid
|
||||||
WHERE number in
|
WHERE number in
|
||||||
<foreach item="phone" collection="phones" open="(" separator="," close=")">
|
<foreach item="phone" collection="phones" open="(" separator="," close=")">
|
||||||
#{phone}
|
#{phone}
|
||||||
</foreach>
|
</foreach>
|
||||||
ORDER BY fileSinceDate DESC, fid DESC
|
ORDER BY
|
||||||
|
pn.number ASC,
|
||||||
|
pn.file_since_dt DESC,
|
||||||
|
pn.fid DESC
|
||||||
WITH UR
|
WITH UR
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -42,6 +42,17 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updatePhoneFid" parameterType="ru.nbch.credit_tracker.entities.dto.PhoneFidMap">
|
||||||
|
UPDATE signals_phone_fid_map
|
||||||
|
SET
|
||||||
|
fid = #{subject.fid},
|
||||||
|
flag_debt5000 = #{subject.flagDebt5000},
|
||||||
|
flag_90_12 = #{subject.flag90days},
|
||||||
|
calculated_at = #{subject.calculatedAt},
|
||||||
|
error_text = #{subject.errorText}
|
||||||
|
WHERE id = #{subject.id}
|
||||||
|
</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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
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 org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
|
||||||
|
import ru.nbch.credit_tracker.mapper.indic.PhoneMapper;
|
||||||
|
import ru.nbch.credit_tracker.service.indic.PhoneService;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
public class PhoneServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
PhoneMapper phoneMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defineFidByPhoneTest() {
|
||||||
|
PhoneService phoneService = new PhoneService(phoneMapper);
|
||||||
|
|
||||||
|
fidsDataWithEqualSinceDt.sort(byDbOrder);
|
||||||
|
when(phoneMapper.findFids(Mockito.anyList())).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("1114").build());
|
||||||
|
|
||||||
|
Map<Integer, PhoneFidMap> res = phoneService.defineFidByPhone(phoneFidMap);
|
||||||
|
Assertions.assertEquals(3, res.size());
|
||||||
|
Assertions.assertEquals("1111", res.get(124).getPhone());
|
||||||
|
Assertions.assertEquals("1112", res.get(125).getPhone());
|
||||||
|
Assertions.assertEquals("1114", res.get(126).getPhone());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<PhoneService.FidsData> fidsDataWithEqualSinceDt = new ArrayList<>(
|
||||||
|
List.of(
|
||||||
|
new PhoneService.FidsData(123, "1111", LocalDate.of(2025, 9, 10)),
|
||||||
|
new PhoneService.FidsData(124, "1111", LocalDate.of(2025, 9, 10)),
|
||||||
|
new PhoneService.FidsData(125, "1112", LocalDate.of(2024, 10, 10)),
|
||||||
|
new PhoneService.FidsData(126, "1114", LocalDate.of(2024, 10, 11))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Comparator<PhoneService.FidsData> byDbOrder =
|
||||||
|
Comparator.comparing(PhoneService.FidsData::getPhone, Comparator.nullsFirst(Comparator.naturalOrder())) // pn.number ASC
|
||||||
|
.thenComparing(PhoneService.FidsData::getFileSinceDate, Comparator.nullsLast(Comparator.reverseOrder())) // file_since_dt DESC
|
||||||
|
.thenComparing(PhoneService.FidsData::getFid, Comparator.reverseOrder());
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue