diff --git a/pom.xml b/pom.xml index f876eb6..ffd17aa 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-aop + org.mybatis.spring.boot mybatis-spring-boot-starter @@ -122,8 +126,83 @@ 3.0.4 test + + org.mockito + mockito-junit-jupiter + test + + + + docker-push-dev + + + + + io.fabric8 + docker-maven-plugin + 0.45.0 + + + Build and deploy docker container + install + + + push + + + + + + + ${project.artifactId}:${project.version} + ${registry.url} + + ${project.basedir}/Dockerfile + + + + + ${project.build.directory}/${project.build.finalName}.jar + . + + + ${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar + . + + + ${project.basedir}/start-credit-tracker.sh + . + + + ${project.basedir}/credit-tracker.properties + . + + + ${project.basedir}/monitoring-request.xsd + . + + + ${project.basedir}/signal-package.xsd + . + + + + + + ${project.version} + + + + + + + + + + + credit-tracker @@ -181,65 +260,7 @@ - - io.fabric8 - docker-maven-plugin - 0.45.0 - - - Build and deploy docker container - install - - build - push - - - - - - - ${project.artifactId}:${project.version} - ${registry.url} - - ${project.basedir}/Dockerfile - - - - - ${project.build.directory}/${project.build.finalName}.jar - . - - - ${project.basedir}/apm-agent/elastic-apm-agent-1.45.0.jar - . - - - ${project.basedir}/start-credit-tracker.sh - . - - - ${project.basedir}/credit-tracker.properties - . - - - ${project.basedir}/monitoring-request.xsd - . - - - ${project.basedir}/signal-package.xsd - . - - - - - - ${project.version} - - - - - - + diff --git a/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java b/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java new file mode 100644 index 0000000..7802484 --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/component/MapperTimingAspect.java @@ -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); + } + } + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java new file mode 100644 index 0000000..bd8bd3c --- /dev/null +++ b/src/main/java/ru/nbch/credit_tracker/config/rest/filters/HttpLoggingFilter.java @@ -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 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 reqHeaders = headersMap(req); + Map 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 headersMap(HttpServletRequest req) { + return Collections.list(req.getHeaderNames()).stream() + .collect(Collectors.toMap(h -> h, req::getHeader, (a, b) -> a, LinkedHashMap::new)); + } + + private static Map headersMap(HttpServletResponse resp) { + return resp.getHeaderNames().stream() + .collect(Collectors.toMap(h -> h, resp::getHeader, (a, b) -> a, LinkedHashMap::new)); + } + + private static void mask(Map headers) { + headers.replaceAll((k, v) -> SENSITIVE_HEADERS.contains(k.toLowerCase()) ? "***" : v); + } +} diff --git a/src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java b/src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java index 0e42995..80f216f 100644 --- a/src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java +++ b/src/main/java/ru/nbch/credit_tracker/mapper/signal/PhoneFidMapMapper.java @@ -15,6 +15,7 @@ public interface PhoneFidMapMapper { List findFullPhoneFidMap(@Param("packageId") Integer packageId, @Param("offset") int offset, @Param("limit") int limit); void updatePhoneFidMaps(@Param("subjects") List subjects); + void updatePhoneFid(@Param("subject") PhoneFidMap subject); void updatePhoneFidMapsErrors(@Param("subjects") List subjects); diff --git a/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java b/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java index 1f30550..1a8e25f 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/MonitoringService.java @@ -1,8 +1,22 @@ 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 org.apache.commons.lang3.StringUtils; -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.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.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 */ @@ -60,9 +59,9 @@ public class MonitoringService { } public void run() { - ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("monitoring-")); - long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15; - scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES); +// ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("monitoring-")); +// long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15; +// scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES); } private void monitor() { diff --git a/src/main/java/ru/nbch/credit_tracker/service/SignalService.java b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java index 138a075..eb7db82 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/SignalService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/SignalService.java @@ -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.user_request.monitoring_request.MonitoringRequest; 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.PersonService; import ru.nbch.credit_tracker.service.indic.PhoneService; @@ -43,6 +44,7 @@ public class SignalService { private final HitsService hitsService; private final UserPackageService userPackageService; private final PhoneFidMapService phoneFidMapService; + private final PhoneFidMapMapper phoneFidMapMapper; private final PhoneService phoneService; private final FlagsService flagsService; private final PersonService personService; @@ -54,6 +56,7 @@ public class SignalService { HitsService hitsService, UserPackageService userPackageService, PhoneFidMapService phoneFidMapService, + PhoneFidMapMapper mapper, PhoneService phoneService, FlagsService flagsService, PersonService personService, @@ -62,6 +65,7 @@ public class SignalService { this.hitsService = hitsService; this.userPackageService = userPackageService; this.phoneFidMapService = phoneFidMapService; + this.phoneFidMapMapper = mapper; this.phoneService = phoneService; this.flagsService = flagsService; this.personService = personService; @@ -125,7 +129,7 @@ public class SignalService { } if (!filteredItems.isEmpty()) { - boolean fidsFound = updateFlags(filteredItems, packageId); + boolean fidsFound = updateFlags2(filteredItems, packageId); if (noFidsFound) { noFidsFound = !fidsFound; } @@ -187,6 +191,26 @@ public class SignalService { return fidsFound; } + public boolean updateFlags2(List subjects, Integer packageId) { + log.info("Start calculating fids and flags for subjects batch. PackageId: {}", packageId); + Map fidsMap = phoneService.defineFidByPhone(subjects); + Map flagsDataMap = flagsService.findFlags(fidsMap.keySet().stream().toList()); + for (Map.Entry 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) { UserPackage userPackage = UserPackage.builder() .userId(request.getUserId()) diff --git a/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java b/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java index 19549fb..6b0a373 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/UpdatingFlagsService.java @@ -1,7 +1,10 @@ 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 org.springframework.scheduling.concurrent.CustomizableThreadFactory; import org.springframework.stereotype.Service; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; 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.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 * По обновленным пакетам формируется новый запрос постановки на мониторинг в официальный сервис сигналов @@ -43,8 +38,8 @@ public class UpdatingFlagsService { } public void run() { - ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("updating-flags-")); - scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS); +// ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("updating-flags-")); +// scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS); } private void update() { diff --git a/src/main/java/ru/nbch/credit_tracker/service/indic/FlagsService.java b/src/main/java/ru/nbch/credit_tracker/service/indic/FlagsService.java index f2bafa2..5a11f68 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/indic/FlagsService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/indic/FlagsService.java @@ -1,20 +1,21 @@ 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.util.HashMap; import java.util.List; 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 public class FlagsService { + private static final Logger log = LoggerFactory.getLogger(FlagsService.class); private final FlagsMapper mapper; public FlagsService(FlagsMapper mapper) { @@ -25,11 +26,13 @@ public class FlagsService { if (fids.isEmpty()) { return new HashMap<>(); } - Map result = new HashMap<>(); - Map flags5000 = calcFlag5000(fids); - Map flags90DaysByPastDueArrear = calcFlag90DaysByPastDueArrear(fids); - Map flags90DaysByRuPaymt = calcFlag90DaysByRuPaymt(fids); + List distinctFids = fids.stream().distinct().toList(); + log.debug("Fids count: {}", distinctFids.size()); + Map flags5000 = calcFlag5000(distinctFids); + Map flags90DaysByPastDueArrear = calcFlag90DaysByPastDueArrear(distinctFids); + Map flags90DaysByRuPaymt = calcFlag90DaysByRuPaymt(distinctFids); + Map result = new HashMap<>(); fids.forEach(fid -> { Integer flagDebt5000 = flags5000.get(fid); if (flagDebt5000 == null) { @@ -55,15 +58,11 @@ public class FlagsService { * Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 0. */ private Map calcFlag5000(List fids) { - return mapper.findFlagsDebt5000(fids).stream() - .collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag, - (existing, replacement) -> { - if (existing == 1) { - return existing; - } else { - return replacement; - } - })); + log.debug("Start calculating flag 5000"); + List rows = mapper.findFlagsDebt5000(fids); + Map res = makeFidFlagMapByRs(fids, rows); + log.debug("Complete calculating flag 5000"); + return res; } /** @@ -72,31 +71,33 @@ public class FlagsService { * Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0. */ private Map calcFlag90DaysByPastDueArrear(List fids) { + log.debug("Start calculating flag 90 by PastDueArrear"); LocalDate yearAgo = LocalDate.now().minusYears(1); - return mapper.findFlag90ByPastDueArrear(fids, yearAgo).stream() - .collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag, - (existing, replacement) -> { - if (existing == 1) { - return existing; - } else { - return replacement; - } - })); + List rows = mapper.findFlag90ByPastDueArrear(fids, yearAgo); + Map res = makeFidFlagMapByRs(fids, rows); + log.debug("Complete calculating flag 90 by PastDueArrear"); + return res; } private Map calcFlag90DaysByRuPaymt(List fids) { + log.debug("Start calculating flag 90 by ruPaymt"); LocalDate yearAgo = LocalDate.now().minusYears(1); - return mapper.findFlag90ByRuPaymt(fids, yearAgo).stream() - .collect(Collectors.toMap(FlagFidData::getFid, FlagFidData::getFlag, - (existing, replacement) -> { - if (existing == 1) { - return existing; - } else { - return replacement; - } - })); + List rows = mapper.findFlag90ByRuPaymt(fids, yearAgo); + Map res = makeFidFlagMapByRs(fids, rows); + log.debug("Complete calculating flag 90 by ruPaymt"); + return res; } + private Map makeFidFlagMapByRs(List fids, List rows) { + Map 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 @Setter @AllArgsConstructor diff --git a/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java b/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java index d063be1..5b8e1a6 100644 --- a/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java +++ b/src/main/java/ru/nbch/credit_tracker/service/indic/PhoneService.java @@ -1,17 +1,19 @@ 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.util.Comparator; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; 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 public class PhoneService { @@ -31,6 +33,37 @@ public class PhoneService { return convertFidsDataToMap(mapper.findFids(phones)); } + public Map defineFidByPhone(List subjects) { + Map phoneFidMap = new HashMap<>(); + List phones = subjects.stream(). + map(subject -> "9" + subject.getPhone()) + .toList(); + + subjects.sort( + Comparator.comparing( + PhoneFidMap::getPhone, + Comparator.naturalOrder() + ) + ); + + //отсортированный список по NUMBER, FID и FILE_SINCE_DT + List phonesByFid = mapper.findFids(phones); + Iterator 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 convertFidsDataToMap(List fidsData) { if (fidsData == null || fidsData.isEmpty()) { return new HashMap<>(); @@ -50,6 +83,8 @@ public class PhoneService { @Getter @Setter + @AllArgsConstructor + @NoArgsConstructor public static class FidsData { private Integer fid; private String phone; diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 0825d76..88ce91c 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -8,7 +8,7 @@ - %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n utf-8 diff --git a/src/main/resources/mybatis/mapper/indic/FlagsMapper.xml b/src/main/resources/mybatis/mapper/indic/FlagsMapper.xml index 24572db..ccdde14 100644 --- a/src/main/resources/mybatis/mapper/indic/FlagsMapper.xml +++ b/src/main/resources/mybatis/mapper/indic/FlagsMapper.xml @@ -11,70 +11,70 @@ \ No newline at end of file diff --git a/src/main/resources/mybatis/mapper/indic/PhoneMapper.xml b/src/main/resources/mybatis/mapper/indic/PhoneMapper.xml index bd754a9..856a06d 100644 --- a/src/main/resources/mybatis/mapper/indic/PhoneMapper.xml +++ b/src/main/resources/mybatis/mapper/indic/PhoneMapper.xml @@ -12,14 +12,21 @@ \ No newline at end of file diff --git a/src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml b/src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml index 9d668d9..3ff64c4 100644 --- a/src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml +++ b/src/main/resources/mybatis/mapper/signal/PhoneFidMapMapper.xml @@ -42,6 +42,17 @@ + + 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 signals_phone_fid_map diff --git a/src/test/java/ru/nbch/credit_tracker/service/PhoneServiceTest.java b/src/test/java/ru/nbch/credit_tracker/service/PhoneServiceTest.java new file mode 100644 index 0000000..cba98b0 --- /dev/null +++ b/src/test/java/ru/nbch/credit_tracker/service/PhoneServiceTest.java @@ -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 = new ArrayList<>(); + phoneFidMap.add(PhoneFidMap.builder().phone("1111").build()); + phoneFidMap.add(PhoneFidMap.builder().phone("1112").build()); + phoneFidMap.add(PhoneFidMap.builder().phone("1114").build()); + + Map 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 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 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()); +}