установка пакета с учетом кэш таблицы phones_map

This commit is contained in:
etreschenkov 2025-12-23 18:16:53 +03:00
parent d87444dac1
commit 77ec90a92e
49 changed files with 1000 additions and 980 deletions

View file

@ -13,8 +13,8 @@ public class CreditTrackerApplication {
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);
updateProcessingPackagesService.run(); // updateProcessingPackagesService.run();
monitoringService.run(); // monitoringService.run();
} }
} }

View file

@ -1,124 +0,0 @@
package ru.nbch.credit_tracker.builder;
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.service.indic.PersonService;
import ru.nbch.credit_tracker.utils.CTUtil;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@Slf4j
public class PersonFactoryBuilder {
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 PersonService.PersonData personData;
private Long uid;
public static PersonFactoryBuilder builder() {
return new PersonFactoryBuilder();
}
public PersonFactoryBuilder personData(PersonService.PersonData personData) {
this.personData = personData;
return this;
}
public PersonFactoryBuilder uid(Long uid) {
this.uid = uid;
return this;
}
public Person build() {
if (personData == null) {
return null;
}
PersonService.NameData nameData = personData.getName();
PersonService.PassportData passportData = personData.getPassport();
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 "";
}
};
}
}
}

View file

@ -79,6 +79,9 @@ public class MonitoringRequestValidator {
if (request.getPassword() != null && validationResult.getPassword() == null) { if (request.getPassword() != null && validationResult.getPassword() == null) {
validationResult.setPassword(request.getPassword()); validationResult.setPassword(request.getPassword());
} }
if (!request.getSignalTypes().isEmpty() && validationResult.getSignalTypes().isEmpty()) {
validationResult.setSignalTypes(request.getSignalTypes());
}
request.getSubjects().getSubject().clear(); request.getSubjects().getSubject().clear();
} catch (SignalException e) { } catch (SignalException e) {
validationResult.addError(new MonitoringValidationError(-1, "", e)); validationResult.addError(new MonitoringValidationError(-1, "", e));

View file

@ -0,0 +1,41 @@
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 org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
@MappedTypes(Long.class)
public class LongTypeHandler extends BaseTypeHandler<Long> {
@Override
public void setNonNullParameter(
PreparedStatement ps, int i, Long parameter, JdbcType jdbcType
) throws SQLException {
ps.setString(i, parameter.toString());
}
@Override
public Long getNullableResult(ResultSet rs, String columnName) throws SQLException {
return parse(rs.getString(columnName));
}
@Override
public Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return parse(rs.getString(columnIndex));
}
@Override
public Long getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return parse(cs.getString(columnIndex));
}
private Long parse(String value) {
if (value == null || value.isBlank()) {
return null;
}
return Long.valueOf(value);
}
}

View file

@ -5,33 +5,31 @@ import java.util.function.Supplier;
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.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper;
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
import ru.nbch.credit_tracker.model.impl.PartFilePayload; import ru.nbch.credit_tracker.model.impl.PartFilePayload;
import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload; import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload;
import ru.nbch.credit_tracker.model.impl.SubjectPayload; import ru.nbch.credit_tracker.model.impl.SubjectPayload;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
import ru.nbch.credit_tracker.service.task.SetupParam; import ru.nbch.credit_tracker.service.task.SetupParam;
import ru.nbch.credit_tracker.service.task.impl.KickPipeLineDefaultImpl; import ru.nbch.credit_tracker.service.task.impl.KickPipeLineDefaultImpl;
import ru.nbch.credit_tracker.service.task.impl.KickPipeLineRepeatedRestoreImpl; import ru.nbch.credit_tracker.service.task.impl.KickPipeLineRepeatedRestoreImpl;
import ru.nbch.credit_tracker.service.task.impl.XmlMergeCoordinator; 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.IPipeLineStarter;
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator; import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
@Configuration @Configuration
public class PipelineStarterConfig { public class PipelineStarterConfig {
@Bean @Bean
public Function<SetupParam, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory(StaxXmlProcessor xml, public Function<SetupParam, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory(CreditTrackerSettings creditTrackerSettings,
CreditTrackerSettings creditTrackerSettings,
UserPackageMapper userPackageMapper, UserPackageMapper userPackageMapper,
PackagesRecordsMapper phoneFidMapMapper) { PackageRecordsService packageRecordsService) {
return (setupParam) -> switch (setupParam.mode()) { return (setupParam) -> switch (setupParam.mode()) {
case DEFAULT -> case DEFAULT ->
new KickPipeLineDefaultImpl(xml, setupParam, userPackageMapper, phoneFidMapMapper, creditTrackerSettings); new KickPipeLineDefaultImpl(setupParam, userPackageMapper, packageRecordsService, creditTrackerSettings);
case RESTORE -> case RESTORE ->
new KickPipeLineDefaultImpl(xml, setupParam, userPackageMapper, phoneFidMapMapper, creditTrackerSettings); new KickPipeLineDefaultImpl(setupParam, userPackageMapper, packageRecordsService, creditTrackerSettings);
case REPEATED_RESTORE -> case REPEATED_RESTORE ->
new KickPipeLineRepeatedRestoreImpl(xml, setupParam, userPackageMapper, phoneFidMapMapper, creditTrackerSettings); new KickPipeLineRepeatedRestoreImpl(setupParam, userPackageMapper, packageRecordsService, creditTrackerSettings);
}; };
} }

View file

@ -0,0 +1,28 @@
package ru.nbch.credit_tracker.entities.app;
import java.time.LocalDate;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class PackageRecordWithPhone {
//PackageRecordsMap fields
private Long packageId;
private String subjectId;
private String phone;
//PhonesMap fields
private Integer fid;
private String name1;
private String first;
private String middle;
private LocalDate birthDt;
private String serNum;
private String idType;
private Integer flagDebt5000;
private Integer flag90days;
}

View file

@ -16,6 +16,7 @@ import lombok.Setter;
public class PhonesMap { public class PhonesMap {
private Long id; private Long id;
private Integer fid; private Integer fid;
private Long phone;
private String name1; private String name1;
private String first; private String first;
private String middle; private String middle;

View file

@ -1,18 +1,22 @@
package ru.nbch.credit_tracker.entities.app; package ru.nbch.credit_tracker.entities.app;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.time.LocalDateTime;
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserPackage { public class UserPackage {
private Long id; private Long id;
private String userId; private String userId;
private String packageName; private String packageName;
private String signalTypes;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private String status; private String status;
private LocalDateTime deactivatedAt; private LocalDateTime deactivatedAt;

View file

@ -0,0 +1,24 @@
package ru.nbch.credit_tracker.entities.indic;
import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Id {
private Integer fid;
private String number;
private String serNum;
private String idNum;
private LocalDate issDate;
private String idType;
private String idType2;
private LocalDate fileSinceDate;
}

View file

@ -1,13 +1,17 @@
package ru.nbch.credit_tracker.entities.indic; package ru.nbch.credit_tracker.entities.indic;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@Getter @Getter
@Setter @Setter
@Builder @Builder
@NoArgsConstructor
@AllArgsConstructor
public class Name { public class Name {
private Integer fid; private Integer fid;
private String number; private String number;

View file

@ -1,7 +1,13 @@
package ru.nbch.credit_tracker.entities.user_request.monitoring_request; package ru.nbch.credit_tracker.entities.user_request.monitoring_request;
import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -26,6 +32,7 @@ public class MonitoringRequest {
protected String packageName; protected String packageName;
@XmlElement(name = "Subjects", required = true) @XmlElement(name = "Subjects", required = true)
protected Subjects subjects; protected Subjects subjects;
protected List<Integer> signalTypes = new ArrayList<>();
public Subjects getSubjects() { public Subjects getSubjects() {
if (subjects == null) { if (subjects == null) {

View file

@ -108,7 +108,7 @@ public class SignalFacadeV3 {
validationResult = monitoringRequestValidator.readAndValidateMonitoringRequest(tmpReqFilePath); validationResult = monitoringRequestValidator.readAndValidateMonitoringRequest(tmpReqFilePath);
if (!validationResult.getValidationErrors().isEmpty()) { if (!validationResult.getValidationErrors().isEmpty()) {
MonitoringValidationError firstError = validationResult.getValidationErrors().getFirst(); MonitoringValidationError firstError = validationResult.getValidationErrors().getFirst();
userPackageService.rejectPackage(validationResult.getUserId(), validationResult.getPackageName()); userPackageService.rejectPackage(validationResult.getUserId(), validationResult.getPackageName(), validationResult.getSignalTypes());
Files.delete(tmpReqFilePath); Files.delete(tmpReqFilePath);
throw firstError.getSignalException(); throw firstError.getSignalException();
} }
@ -127,6 +127,7 @@ public class SignalFacadeV3 {
String packageName = validationResult.getPackageName(); String packageName = validationResult.getPackageName();
String userId = validationResult.getUserId(); String userId = validationResult.getUserId();
String password = validationResult.getPassword(); String password = validationResult.getPassword();
List<Integer> signalTypes = validationResult.getSignalTypes();
Path parsedFilePath = tmpReqFilePath.resolveSibling(Path.of(userId.substring(0, 6) + "_" + packageName + ".xml")); Path parsedFilePath = tmpReqFilePath.resolveSibling(Path.of(userId.substring(0, 6) + "_" + packageName + ".xml"));
try { try {
@ -138,17 +139,17 @@ public class SignalFacadeV3 {
// проверка авторизации // проверка авторизации
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(userId, password); AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(userId, password);
if (!authResult.isSuccess()) { if (!authResult.isSuccess()) {
userPackageService.rejectPackage(userId, packageName); userPackageService.rejectPackage(userId, packageName, signalTypes);
throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError); throw clientExcp(authResult.getError(), XmlErrorFormat.MonitoringError);
} }
// проверка на уникальность пакета // проверка на уникальность пакета
if (userPackageService.isPackageNotUnique(userId, packageName)) { // if (userPackageService.isPackageNotUnique(userId, packageName)) {
userPackageService.rejectPackage(userId, packageName); // userPackageService.rejectPackage(userId, packageName, signalTypes);
throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError); // throw clientExcp(SignalError.ERROR_007, XmlErrorFormat.MonitoringError);
} // }
Long packageId = userPackageService.registerPackage(userId, packageName); Long packageId = userPackageService.registerPackage(userId, packageName, signalTypes);
LogUtil.addMdcLogKey("%s %d".formatted(packageName, packageId)); LogUtil.addMdcLogKey("%s %d".formatted(packageName, packageId));
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.ACCEPTED.name()); log.info("Package registered. PackageId {}. Status: {}", packageId, Status.ACCEPTED.name());
Pipeline pipeline = pipelinePackageManager.build(new SetupParam(packageId, parsedFilePath, PipelineMode.DEFAULT)); Pipeline pipeline = pipelinePackageManager.build(new SetupParam(packageId, parsedFilePath, PipelineMode.DEFAULT));

View file

@ -5,14 +5,9 @@ import java.util.List;
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.indic.PaymentsFlag; import ru.nbch.credit_tracker.entities.indic.PaymentsFlag;
import ru.nbch.credit_tracker.service.indic.FlagsService;
@Mapper @Mapper
public interface IndicFlagsMapper { public interface IndicFlagsMapper {
List<FlagsService.RuPastDuarearData> findRuPastDuarearData(@Param("fids") List<Integer> fids);
List<FlagsService.RuPaymtData> findRuPaymtData(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate);
List<PaymentsFlag> findFlagsDebt5000(@Param("fids") List<Integer> fids); List<PaymentsFlag> findFlagsDebt5000(@Param("fids") List<Integer> fids);
List<PaymentsFlag> findFlag90ByPastDueArrear(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate); List<PaymentsFlag> findFlag90ByPastDueArrear(@Param("fids") List<Integer> fids, @Param("reportedDate") LocalDate reportedDate);

View file

@ -1,15 +1,15 @@
package ru.nbch.credit_tracker.mapper.indic; package ru.nbch.credit_tracker.mapper.indic;
import java.util.List;
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.service.indic.PersonService; import ru.nbch.credit_tracker.entities.indic.Id;
import ru.nbch.credit_tracker.entities.indic.Name;
import java.util.List;
@Mapper @Mapper
public interface PersonMapper { public interface PersonMapper {
List<PersonService.NameData> findNameData(@Param("fids") List<Integer> fids); List<Name> findNameData(@Param("phones") List<String> phones);
List<PersonService.PassportData> findPassportData(@Param("fids") List<Integer> fids); List<Id> findPassportData(@Param("fids") List<Integer> fids);
} }

View file

@ -0,0 +1,11 @@
package ru.nbch.credit_tracker.mapper.signal;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import ru.nbch.credit_tracker.entities.app.PackageRecordWithPhone;
@Mapper
public interface PackagesRecordsJoinMapper {
List<PackageRecordWithPhone> findPackagesRecordsJoinPage(@Param("packageId") Long packageId, @Param("limit") Integer limit, @Param("offset") Integer offset);
}

View file

@ -0,0 +1,15 @@
package ru.nbch.credit_tracker.mapper.signal;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import ru.nbch.credit_tracker.entities.app.PhonesMap;
@Mapper
public interface PhonesMapMapper {
List<PhonesMap> getCachedData(@Param("phones") List<Long> phones);
void updateIdCachedData(@Param("json") String json);
void updateFlagCachedData(@Param("json") String json);
void registerJson(@Param("json") String json);
void setFidJson(@Param("json") String json);
}

View file

@ -0,0 +1,15 @@
package ru.nbch.credit_tracker.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class FlagData {
private Long phone;
private Integer flag_debt5000;
private Integer flag_90_12;
}

View file

@ -2,15 +2,19 @@ package ru.nbch.credit_tracker.model;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@Getter @Getter
@Setter @Setter
@Builder @Builder
//todo подумать над неймингом класс @NoArgsConstructor
@AllArgsConstructor
public class IdData { public class IdData {
private Long phone;
private Integer fid; private Integer fid;
private String serNum; private String serNum;
private String idNum; private String idNum;

View file

@ -9,7 +9,6 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@Builder @Builder
//todo подумать над неймингом класс
public class NameData { public class NameData {
private Integer fid; private Integer fid;
private String firstName; private String firstName;

View file

@ -10,8 +10,9 @@ import lombok.Setter;
public class SubjectProfile { public class SubjectProfile {
private String identifier; private String identifier;
private Long mapId; private Long mapId;
private String phone; private Long phone;
private Integer fid; private Integer fid;
private NameData nameData; private NameData nameData;
private IdData idData; private IdData idData;
private FlagData flagData;
} }

View file

@ -7,6 +7,7 @@ public class ValidationResult {
private String packageName; private String packageName;
private String userId; private String userId;
private String password; private String password;
private List<Integer> signalTypes = new ArrayList<>();
private List<MonitoringValidationError> validationErrors = new ArrayList<>(); private List<MonitoringValidationError> validationErrors = new ArrayList<>();
public void setPackageName(String packageName) { public void setPackageName(String packageName) {
@ -40,6 +41,14 @@ public class ValidationResult {
this.password = password; this.password = password;
} }
public List<Integer> getSignalTypes() {
return signalTypes;
}
public void setSignalTypes(List<Integer> signalTypes) {
this.signalTypes = signalTypes;
}
public List<MonitoringValidationError> getValidationErrors() { public List<MonitoringValidationError> getValidationErrors() {
return validationErrors; return validationErrors;
} }

View file

@ -2,4 +2,6 @@ package ru.nbch.credit_tracker.model.impl;
public enum PackageVariable { public enum PackageVariable {
packageId, packageId,
cacheMisses,
cacheHits
} }

View file

@ -1,7 +1,9 @@
package ru.nbch.credit_tracker.service; package ru.nbch.credit_tracker.service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.app.UserPackage; import ru.nbch.credit_tracker.entities.app.UserPackage;
@ -27,20 +29,25 @@ public class UserPackageService {
} }
public Long registerPackage(String userId, String packageName) { public Long registerPackage(String userId, String packageName, List<Integer> signalTypes) {
signalTypes.sort(Comparator.naturalOrder());
String types = signalTypes.stream().map(Object::toString).collect(Collectors.joining(","));
UserPackage userPackage = UserPackage.builder() UserPackage userPackage = UserPackage.builder()
.userId(userId) .userId(userId)
.packageName(packageName) .packageName(packageName)
.signalTypes(types)
.createdAt(LocalDateTime.now()) .createdAt(LocalDateTime.now())
.status(Status.ACCEPTED.name()) .status(Status.ACCEPTED.name())
.build(); .build();
return userPackageService.insertPackage(userPackage); return userPackageService.insertPackage(userPackage);
} }
public void rejectPackage(String userId, String packageName) { public void rejectPackage(String userId, String packageName, List<Integer> signalTypes) {
String types = signalTypes.stream().map(Object::toString).collect(Collectors.joining(","));
UserPackage userPackage = UserPackage.builder() UserPackage userPackage = UserPackage.builder()
.userId(userId) .userId(userId)
.packageName(packageName) .packageName(packageName)
.signalTypes(types)
.createdAt(LocalDateTime.now()) .createdAt(LocalDateTime.now())
.status(Status.REJECTED.name()) .status(Status.REJECTED.name())
.build(); .build();

View file

@ -51,6 +51,11 @@ public class ValidationService {
throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Subject"); throw clientExcp(SignalError.ERROR_002, packageName, XmlErrorFormat.MonitoringError, "Subject");
} }
boolean validValues = request.getSignalTypes().stream().allMatch(integer -> integer == 1 || integer == 2);
if (!validValues) {
throw clientExcp(SignalError.ERROR_010, packageName, XmlErrorFormat.MonitoringError, "SignalTypes");
}
for (Subject subject : request.getSubjects().getSubject()) { for (Subject subject : request.getSubjects().getSubject()) {
if (!validateNPId(subject.getId())) { if (!validateNPId(subject.getId())) {
throw clientExcp(SignalError.ERROR_010, packageName, XmlErrorFormat.MonitoringError, subject.getId()); throw clientExcp(SignalError.ERROR_010, packageName, XmlErrorFormat.MonitoringError, subject.getId());

View file

@ -3,202 +3,14 @@ package ru.nbch.credit_tracker.service.indic;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.time.LocalDate; 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 lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; 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.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.mapper.indic.IndicFlagsMapper;
@Service @Service
public class FlagsService { public class FlagsService {
private static final Logger log = LoggerFactory.getLogger(FlagsService.class);
private final IndicFlagsMapper mapper;
private static final String SELECT_RU_PASDUEARREAR_DATA =
"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(IndicFlagsMapper mapper,
@Qualifier("jdbcTemplateIndic") NamedParameterJdbcTemplate jdbcTemplate) {
this.mapper = mapper;
this.jdbcTemplate = jdbcTemplate;
}
public Map<Integer, FlagsData> findFlags(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<>();
findFlagsRuPastDueArrear(distinctFids, flags5000, flags90DaysByPastDueArrear);
findFlagsRuPaymt(distinctFids, flags90DaysByRuPaymt);
Map<Integer, 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 FlagsData(flagDebt5000, flag90days));
});
return result;
}
/**
* Выбирает данные из RU_PASTDUEARREAR и ищет по ним флаги просрочек
* По FID из RU_PASTDUEARREAR выбираются все уникальные ACC_SERIAL_NUM с максимальной датой REPORTED_DT.
* Если по хотя бы одной такой записи AMT_PAST_DUE > 5000, то flag500 устанавливается в 1.
* Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 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) {
log.debug("Start calculating flag 5000 and 90 days by RU_PASTDUEARREAR");
List<RuPastDuarearData> ruPastDuarearDataList = mapper.findRuPastDuarearData(fids);
ruPastDuarearDataList.sort(Comparator.comparing(FlagsService.RuPastDuarearData::getFid) // сортируем сначала по фиду
.thenComparing(FlagsService.RuPastDuarearData::getReportedDate, Comparator.reverseOrder())); // Затем сортируем по REPORTED_DT по убыванию
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 {
flag90Days.put(fid, 0);
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
*
* flag90Days = 1, если выполняется хотя бы одно из условий:
* В INDIC.RU_PAYMT у данного FID есть запись с DAYS_PAST_DUE 90 и REPORTED_DT >= текущая дата 12 месяцев.
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
* @param fids - отсортирован по возрастанию фидов
* @param flag90Days - рещультирующая мапа флагов просрочек 90_days
*/
private void findFlagsRuPaymt(List<Integer> fids, Map<Integer, Integer> flag90Days) {
log.debug("Start calculating flag 90 days by RU_PAPAYMT");
LocalDate yearAgo = LocalDate.now().minusYears(1);
List<RuPaymtData> ruPaymtDataList = mapper.findRuPaymtData(fids, yearAgo);
ruPaymtDataList.sort(Comparator.comparing(RuPaymtData::getFid, Comparator.naturalOrder()));
for (Integer fid : fids) {
Iterator<RuPaymtData> iterator = ruPaymtDataList.iterator();
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 {
flag90Days.put(fid, 0);
iterator.remove();
}
} else {
iterator.remove();
}
}
}
}
flag90Days.putIfAbsent(fid, 0);
}
log.debug("Complete calculating flag 90 days by RU_PAPAYMT");
}
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor

View file

@ -1,20 +1,12 @@
package ru.nbch.credit_tracker.service.indic; package ru.nbch.credit_tracker.service.indic;
import java.time.LocalDate; 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;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
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;
@Slf4j @Slf4j
@Service @Service
@ -26,165 +18,6 @@ public class PersonService {
this.mapper = mapper; this.mapper = mapper;
} }
public Map<Integer, PersonData> findPersonData(List<Integer> fids) {
if (fids.isEmpty()) {
return new HashMap<>();
}
Map<Integer, PersonData> personDataMap = new HashMap<>();
//делаем тоже самое что сделали signalService.updateFlags2(userPackage);
Map<Integer, NameData> nameDataMap = findNameData(fids);
Map<Integer, PassportData> passortDataMap = findPassportData(fids);
fids.forEach(fid -> {
NameData person = nameDataMap.get(fid);
PassportData passort = passortDataMap.get(fid);
if (person != null && passort != null && requiredFieldPresent(person, passort)) {
personDataMap.put(fid, new PersonData(person, passort));
} else {
log.warn("Person does not have required fields. Fid {}", fid);
}
});
return personDataMap;
}
private Map<Integer, NameData> findNameData(List<Integer> fids) {
List<NameData> persons = mapper.findNameData(fids);
return persons.stream()
.collect(Collectors.toMap(NameData::getFid, nameData -> nameData,
(existing, replacement) -> {
LocalDate existingDate = existing.getFileSinceDate();
LocalDate replacementDate = replacement.getFileSinceDate();
if (existingDate != null && replacementDate != null) {
if (existingDate.isAfter(replacementDate)) {
return existing;
} else {
return replacement;
}
} else if (existingDate != null) {
return existing;
} else {
return replacement;
}
}));
}
private Map<Integer, PassportData> findPassportData(List<Integer> fids) {
Map<Integer, PassportData> resultMap = new HashMap<>();
List<PassportData> passports = mapper.findPassportData(fids);
Map<Integer, List<PassportData>> passportsMap = passports.stream()
.collect(Collectors.groupingBy(PassportData::getFid));
fids.forEach(fid -> {
PassportData passport = findPassport(passportsMap.get(fid));
if (passport != null) {
resultMap.put(fid, passport);
}
});
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) {
if (passports == null || passports.isEmpty()) {
return null;
}
List<PassportData> documents = passports.stream()
.filter(this::isDUL)
.toList(); // берем только ДУЛ
if (documents.isEmpty()) {
return null;
}
// Отдаем приоритет паспортам РФ
PassportData passport = documents.stream()
.filter(p -> "21".equals(p.getIdType2()) || "21".equals(p.getIdType()))
.sorted(
Comparator.comparing(
PassportData::getIssDate,
Comparator.nullsLast(Comparator.reverseOrder())
).thenComparing(
PassportData::getFileSinceDate,
Comparator.nullsLast(Comparator.reverseOrder())
)
).findFirst().orElse(null);
if (passport != null) {
return passport;
}
// Если паспорт РФ не найден, смотри остальные ДУЛ'ы и берем первый
passport = documents.stream()
.sorted(
Comparator.comparing(
PassportData::getIssDate,
Comparator.nullsLast(Comparator.reverseOrder())
).thenComparing(
PassportData::getFileSinceDate,
Comparator.nullsLast(Comparator.reverseOrder())
)
).findFirst().orElse(null);
return passport;
}
private boolean isDUL(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));
}
private boolean requiredFieldPresent(NameData nameData, PassportData passportData) {
boolean isDocTypeNotNull = StringUtils.isNotBlank(passportData.idType) || StringUtils.isNotBlank(passportData.idType2);
return !StringUtils.isAllBlank(nameData.firstName, nameData.lastName, passportData.idNum) && nameData.birthDate != null && isDocTypeNotNull;
}
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public static class PersonData { public static class PersonData {

View file

@ -1,97 +1,87 @@
package ru.nbch.credit_tracker.service.indic; package ru.nbch.credit_tracker.service.indic;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.indic.Id;
import ru.nbch.credit_tracker.entities.indic.Name;
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 ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.utils.CTUtil;
@Slf4j @Slf4j
@Service @Service
public class PersonServiceV2 { public class PersonServiceV2 {
private final PersonMapper mapper; private final PersonMapper mapper;
private final Comparator<Id> byDatesDesc =
Comparator.comparing(Id::getIssDate, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(Id::getFileSinceDate, Comparator.nullsLast(Comparator.naturalOrder()));
private final Comparator<Name> byDateThenIdNullSafe =
Comparator.comparing(Name::getFileSinceDate, Comparator.nullsFirst(Comparator.naturalOrder()))
.thenComparing(Name::getFid);
public PersonServiceV2(PersonMapper mapper) { public PersonServiceV2(PersonMapper mapper) {
this.mapper = mapper; this.mapper = mapper;
} }
public void filledPassportsData(List<SubjectProfile> subjectProfiles) { public Map<Integer, Id> filledPassportsData(List<Integer> fids) {
List<Integer> fids = subjectProfiles.stream().map(SubjectProfile::getFid).collect(Collectors.toList());
if (fids.isEmpty()) { if (fids.isEmpty()) {
return; return new HashMap<>();
} }
List<PersonService.PassportData> passports = mapper.findPassportData(fids); List<Id> passports = mapper.findPassportData(fids);
Map<Integer, List<PersonService.PassportData>> passportsMap = passports.stream() Map<Integer, Id> idByFid = 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) .filter(this::isDUL)
.toList(); // берем только ДУЛ .collect(Collectors.groupingBy(
Id::getFid,
if (documents.isEmpty()) { Collectors.collectingAndThen(
return null; Collectors.toList(),
} docs -> docs.stream()
// Отдаем приоритет паспортам РФ
PersonService.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( .max(byDatesDesc)
Comparator.comparing( .or(() -> docs.stream().max(byDatesDesc))
PersonService.PassportData::getIssDate, .orElse(null)
Comparator.nullsLast(Comparator.reverseOrder())
).thenComparing(
PersonService.PassportData::getFileSinceDate,
Comparator.nullsLast(Comparator.reverseOrder())
) )
).findFirst().orElse(null); ));
return idByFid;
if (passport != null) {
return passport;
} }
// Если паспорт РФ не найден, смотри остальные ДУЛ'ы и берем первый /**
passport = documents.stream() * Поиск данных по таблицам PHONE_NORM и NAME по списку номеров телефонов
.sorted( *
Comparator.comparing( * @param subjects
PersonService.PassportData::getIssDate, * @return - отображение NAME к номеру телефону, отфильтрованному по логике
Comparator.nullsLast(Comparator.reverseOrder()) * FID с максимальным значением FILE_SINCE_DT. Если FILE_SINCE_DT оказался одинаковый, берется максимальный FID
).thenComparing( */
PersonService.PassportData::getFileSinceDate, public Map<String, Name> findNameByNumber(List<SubjectProfile> subjects) {
Comparator.nullsLast(Comparator.reverseOrder()) List<String> phones = subjects.stream()
.map(subject -> CTUtil.normalizePhoneNumber(subject.getPhone().toString()))
.toList();
List<Name> names = mapper.findNameData(phones);
return names.stream()
.filter(name ->
StringUtils.isNotEmpty(name.getFirst()) &&
StringUtils.isNotEmpty(name.getLast())
) )
).findFirst().orElse(null); .collect(Collectors.toMap(
return passport; Name::getNumber,
Function.identity(),
BinaryOperator.maxBy(byDateThenIdNullSafe)
));
} }
//todo подлежит рефакторингу; private boolean isDUL(Id p) {
private boolean isDUL(PersonService.PassportData p) {
Integer idType; Integer idType;
Double idType2; Double idType2;
try { try {

View file

@ -5,21 +5,15 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; 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 lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap; import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
import ru.nbch.credit_tracker.entities.app.PhonesMap; import ru.nbch.credit_tracker.entities.app.PhonesMap;
import ru.nbch.credit_tracker.entities.indic.Name; import ru.nbch.credit_tracker.entities.indic.Name;
import ru.nbch.credit_tracker.mapper.indic.PersonMapper;
import ru.nbch.credit_tracker.mapper.signal.FlagDetailMapper; import ru.nbch.credit_tracker.mapper.signal.FlagDetailMapper;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper; import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper;
import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.repository.PhoneRepository; import ru.nbch.credit_tracker.repository.PhoneRepository;
import ru.nbch.credit_tracker.utils.CTUtil;
@Slf4j @Slf4j
@Service @Service
@ -27,6 +21,7 @@ public class PhoneService2 {
private final PhoneRepository phoneRepository; private final PhoneRepository phoneRepository;
private final PackagesRecordsMapper phoneFidMapMapper; private final PackagesRecordsMapper phoneFidMapMapper;
private final PersonMapper personMapper;
private final FlagDetailMapper flagDetailMapper; private final FlagDetailMapper flagDetailMapper;
private final ObjectMapper entityToJsonMapper; private final ObjectMapper entityToJsonMapper;
private final Comparator<Name> byDateThenIdNullSafe = private final Comparator<Name> byDateThenIdNullSafe =
@ -35,65 +30,16 @@ public class PhoneService2 {
public PhoneService2(PhoneRepository phoneRepository, public PhoneService2(PhoneRepository phoneRepository,
PackagesRecordsMapper phoneFidMapMapper, PackagesRecordsMapper phoneFidMapMapper,
PersonMapper personMapper,
FlagDetailMapper flagDetailMapper, FlagDetailMapper flagDetailMapper,
ObjectMapper entityToJsonMapper) { ObjectMapper entityToJsonMapper) {
this.phoneRepository = phoneRepository; this.phoneRepository = phoneRepository;
this.phoneFidMapMapper = phoneFidMapMapper; this.phoneFidMapMapper = phoneFidMapMapper;
this.personMapper = personMapper;
this.flagDetailMapper = flagDetailMapper; this.flagDetailMapper = flagDetailMapper;
this.entityToJsonMapper = entityToJsonMapper; this.entityToJsonMapper = entityToJsonMapper;
} }
/**
* Поиск данных по таблицам 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()
.filter(name ->
StringUtils.isNotEmpty(name.getFirst()) &&
StringUtils.isNotEmpty(name.getLast())
)
.collect(Collectors.toMap(
Name::getNumber,
Function.identity(),
BinaryOperator.maxBy(byDateThenIdNullSafe)
));
}
/**
* Поиск данных по таблицам NAME по списку FID
* Если пакет ACCEPTED, то в базе могут находиться записи с уже рассчитанными FID
* Нужен для исключения долгих запросов findNameByPhones
* Смотри UpdateProcessingPackagesService:processingRestore
*
* @param subjects
* @return - отображение NAME к FID, отфильтрованному по логике
* FID с максимальным значением FILE_SINCE_DT. Если FILE_SINCE_DT оказался одинаковый, берется максимальный FID
*/
public Map<Integer, Name> nameByFid(List<SubjectProfile> subjects) {
List<Integer> fids = subjects.stream()
.map(SubjectProfile::getFid)
.toList();
List<Name> names = phoneRepository.findNameByFids(fids);
return names.stream()
.collect(Collectors.toMap(
Name::getFid,
Function.identity(),
BinaryOperator.maxBy(byDateThenIdNullSafe)
));
}
public List<Long> registerSubjects(List<PackagesRecordsMap> subjects) { public List<Long> registerSubjects(List<PackagesRecordsMap> subjects) {
try { try {
String json = entityToJsonMapper.writeValueAsString(subjects.stream() String json = entityToJsonMapper.writeValueAsString(subjects.stream()

View file

@ -0,0 +1,111 @@
package ru.nbch.credit_tracker.service.signal;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
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.app.PackageRecordWithPhone;
import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
import ru.nbch.credit_tracker.entities.app.PhonesMap;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsJoinMapper;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper;
import ru.nbch.credit_tracker.mapper.signal.PhonesMapMapper;
import ru.nbch.credit_tracker.model.FlagData;
import ru.nbch.credit_tracker.model.IdData;
import ru.nbch.credit_tracker.model.SubjectProfile;
/**
* Сервис предназначен для сохранения и поиска субъектов по пакету
* Взаимодействие происходит с двумя таблицами:
* signals_packages_records - полный список записей из пакета
* signals_phones_map - уникальный набор телефонов с актуальными перс. данными и флагами
*/
@Service
@Slf4j
public class PackageRecordsService {
private final PhonesMapMapper phonesMapMapper;
private final PackagesRecordsMapper packagesRecordsMapper;
private final PackagesRecordsJoinMapper packagesRecordsJoinMapper;
private final ObjectMapper entityToJsonMapper;
public PackageRecordsService(PhonesMapMapper phonesMapMapper,
PackagesRecordsMapper packagesRecordsMapper,
PackagesRecordsJoinMapper packagesRecordsJoinMapper,
ObjectMapper entityToJsonMapper) {
this.phonesMapMapper = phonesMapMapper;
this.packagesRecordsMapper = packagesRecordsMapper;
this.packagesRecordsJoinMapper = packagesRecordsJoinMapper;
this.entityToJsonMapper = entityToJsonMapper;
}
public List<PackageRecordWithPhone> pageCachedPhonesByPackageId(Long packageId, Integer limit, Integer offset) {
return packagesRecordsJoinMapper.findPackagesRecordsJoinPage(packageId, limit, offset);
}
public Map<Long, PhonesMap> findCachedPhones(List<SubjectProfile> subjects) {
List<Long> phones = subjects.stream()
.map(SubjectProfile::getPhone)
.toList();
List<PhonesMap> phonesMaps = phonesMapMapper.getCachedData(phones);
return phonesMaps.stream().collect(Collectors.toMap(PhonesMap::getPhone, Function.identity()));
}
public List<PackagesRecordsMap> findFullPhoneFidMap(Long packageId, Integer limit, Integer offset) {
return packagesRecordsMapper.findFullPhoneFidMap(packageId, limit, offset);
}
public void saveToCache(List<PhonesMap> phonesMaps) {
try {
String json = entityToJsonMapper.writeValueAsString(phonesMaps.stream()
.filter(Objects::nonNull)
.map(phoneMap -> new HashMap<String, Object>() {{
put("fid", phoneMap.getFid());
put("phone", phoneMap.getPhone());
put("name_1", phoneMap.getName1());
put("first", phoneMap.getFirst());
put("middle", phoneMap.getMiddle());
put("birth_dt", phoneMap.getBirthDt());
}}).toList());
phonesMapMapper.registerJson(json);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public void updateIdCache(List<IdData> idData) {
try {
String json = entityToJsonMapper.writeValueAsString(idData.stream()
.filter(Objects::nonNull)
.map(phoneMap -> new HashMap<String, Object>() {{
put("phone", phoneMap.getPhone());
put("ser_num", phoneMap.getSerNum());
put("id_type", phoneMap.getIdType());
}}).toList());
phonesMapMapper.updateIdCachedData(json);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public void updateFlagCache(List<FlagData> flagData) {
try {
String json = entityToJsonMapper.writeValueAsString(flagData.stream()
.filter(Objects::nonNull)
.map(phoneMap -> new HashMap<String, Object>() {{
put("phone", phoneMap.getPhone());
put("flag_debt5000", phoneMap.getFlag_debt5000());
put("flag_90_12", phoneMap.getFlag_90_12());
}}).toList());
phonesMapMapper.updateFlagCachedData(json);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -6,6 +6,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ru.nbch.credit_tracker.model.PipelineContext;
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator; import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
import ru.nbch.credit_tracker.utils.LogUtil; import ru.nbch.credit_tracker.utils.LogUtil;
@ -17,6 +18,7 @@ public class Pipeline {
private Future<?> starterFuture; private Future<?> starterFuture;
private Future<?> terminatorFuture; private Future<?> terminatorFuture;
private final AtomicBoolean closed = new AtomicBoolean(false); private final AtomicBoolean closed = new AtomicBoolean(false);
private PipelineContext<?> context;
private volatile long startTime; private volatile long startTime;
public Pipeline() { public Pipeline() {
@ -70,4 +72,12 @@ public class Pipeline {
public long getStartTime() { public long getStartTime() {
return startTime; return startTime;
} }
public void setContext(PipelineContext<?> context) {
this.context = context;
}
public <T extends Enum<T>> PipelineContext<T> obtainContext(Class<T> keyClass) {
return (PipelineContext<T>) context;
}
} }

View file

@ -5,12 +5,14 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
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.enums.RejectedStatus; import ru.nbch.credit_tracker.enums.RejectedStatus;
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
import ru.nbch.credit_tracker.model.impl.PackageVariable;
import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload; import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload;
import ru.nbch.credit_tracker.service.MonitoringErrorProcesingService; import ru.nbch.credit_tracker.service.MonitoringErrorProcesingService;
import ru.nbch.credit_tracker.service.signal.SignalRestService; import ru.nbch.credit_tracker.service.signal.SignalRestService;
@ -98,6 +100,15 @@ public class PipelinePackageOrchestrator {
try { try {
long finishTime = System.currentTimeMillis(); long finishTime = System.currentTimeMillis();
log.info("pipeline time passed: {} ms", finishTime - pipeline.getStartTime()); log.info("pipeline time passed: {} ms", finishTime - pipeline.getStartTime());
SignalXmlFilePayload res = (SignalXmlFilePayload) v;
var ctx = pipeline.obtainContext(PackageVariable.class);
AtomicInteger cacheHits = ctx.get(PackageVariable.cacheHits);
AtomicInteger cacheMisses = ctx.get(PackageVariable.cacheMisses);
log.info(
"Cache stats: hits={}, misses={}, total={}",
cacheHits.get(),
cacheMisses.get(),
cacheHits.get() + cacheMisses.get());
if (e instanceof XmlMergeCoordinator.PipelineTerminatorException) { if (e instanceof XmlMergeCoordinator.PipelineTerminatorException) {
log.info("when complete: terminator was interrupted."); log.info("when complete: terminator was interrupted.");
return; return;
@ -106,9 +117,9 @@ public class PipelinePackageOrchestrator {
return; return;
} }
userPackageMapper.setLastSearchedDt(packageId); userPackageMapper.setLastSearchedDt(packageId);
SignalXmlFilePayload res = (SignalXmlFilePayload) v;
log.trace("Signal file by path: {} is completed", res.signalXmlFilePath()); log.trace("Signal file by path: {} is completed", res.signalXmlFilePath());
boolean success = signalRestService.setupMonitoring(res.signalXmlFilePath()); boolean success = true;
// signalRestService.setupMonitoring(res.signalXmlFilePath());
if (success) { if (success) {
userPackageMapper.updatePackageOnMonitoringSuccess(packageId, LocalDateTime.now()); userPackageMapper.updatePackageOnMonitoringSuccess(packageId, LocalDateTime.now());
monitoringErrorProcesingService.findErrors(packageId); monitoringErrorProcesingService.findErrors(packageId);

View file

@ -7,29 +7,41 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.builder.PersonFactoryBuilderV2; import ru.nbch.credit_tracker.builder.PersonFactoryBuilderV2;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
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.indic.Id;
import ru.nbch.credit_tracker.model.IdData;
import ru.nbch.credit_tracker.model.SubjectProfile; import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.model.impl.PartFilePayload; import ru.nbch.credit_tracker.model.impl.PartFilePayload;
import ru.nbch.credit_tracker.model.impl.SubjectPayload; import ru.nbch.credit_tracker.model.impl.SubjectPayload;
import ru.nbch.credit_tracker.service.indic.PersonServiceV2; import ru.nbch.credit_tracker.service.indic.PersonServiceV2;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
import ru.nbch.credit_tracker.service.task.Handler; import ru.nbch.credit_tracker.service.task.Handler;
import ru.nbch.credit_tracker.service.xml.stax.SignalsStaxXmlWriterV2; import ru.nbch.credit_tracker.service.xml.stax.SignalsStaxXmlWriterV2;
import ru.nbch.credit_tracker.utils.CTUtil;
import static ru.nbch.credit_tracker.utils.CTUtil.defineIdType;
@Service @Service
@Slf4j @Slf4j
public class FidIdEnricher implements Handler<SubjectPayload, PartFilePayload> { public class FidIdEnricher implements Handler<SubjectPayload, PartFilePayload> {
private final PersonServiceV2 personService; private final PersonServiceV2 personService;
private final PackageRecordsService packageRecordsService;
private final CreditTrackerSettings creditTrackerSettings; private final CreditTrackerSettings creditTrackerSettings;
public FidIdEnricher(PersonServiceV2 personService, public FidIdEnricher(PersonServiceV2 personService,
PackageRecordsService packageRecordsService,
CreditTrackerSettings creditTrackerSettings) { CreditTrackerSettings creditTrackerSettings) {
this.personService = personService; this.personService = personService;
this.packageRecordsService = packageRecordsService;
this.creditTrackerSettings = creditTrackerSettings; this.creditTrackerSettings = creditTrackerSettings;
} }
@ -37,11 +49,40 @@ public class FidIdEnricher implements Handler<SubjectPayload, PartFilePayload> {
public PartFilePayload handle(SubjectPayload taskPayload) { public PartFilePayload handle(SubjectPayload taskPayload) {
List<SubjectProfile> subjectsProfile = taskPayload.getSubjects(); List<SubjectProfile> subjectsProfile = taskPayload.getSubjects();
log.debug("FidIdEnricher handle by packageId: {}; size: {}", taskPayload.getPackageId(), subjectsProfile.size()); log.debug("FidIdEnricher handle by packageId: {}; size: {}", taskPayload.getPackageId(), subjectsProfile.size());
personService.filledPassportsData(subjectsProfile);
List<Person> personOnProcessing = subjectsProfile.stream() List<Integer> noIdDataFids = subjectsProfile.stream()
.filter(subjectProfile -> subjectProfile.getIdData() != null && subjectProfile.getNameData() != null) .filter(subjectProfile -> subjectProfile.getIdData() == null)
.map(subjectProfile -> PersonFactoryBuilderV2.builder().personData(subjectProfile).build()) .map(SubjectProfile::getFid)
.toList(); .toList();
Map<Integer, Id> idByFid = personService.filledPassportsData(noIdDataFids);
List<IdData> idCacheOnUpdate = new ArrayList<>();
List<Person> personOnProcessing = subjectsProfile.stream()
.flatMap(subjectProfile -> {
if (subjectProfile.getIdData() == null) {
Id id = idByFid.get(subjectProfile.getFid());
if (id == null) {
return Stream.empty();
}
String normSerNum = CTUtil.normalize(id.getSerNum());
String normIdNum = CTUtil.normalize(id.getIdNum());
String serNum = StringUtils.isNotBlank(normSerNum) ? normSerNum + normIdNum : normIdNum;
IdData idData = IdData.builder()
.serNum(serNum)
.idType(defineIdType(id.getIdType(), id.getIdType2()))
.fid(subjectProfile.getFid())
.phone(subjectProfile.getPhone())
.build();
idCacheOnUpdate.add(idData);
subjectProfile.setIdData(idData);
}
return Stream.of(PersonFactoryBuilderV2.builder()
.personData(subjectProfile)
.build());
})
.toList();
packageRecordsService.updateIdCache(idCacheOnUpdate);
log.debug("personOnProcessing size: {}", personOnProcessing.size()); log.debug("personOnProcessing size: {}", personOnProcessing.size());
Long packageId = taskPayload.getPackageId(); Long packageId = taskPayload.getPackageId();
Path partPath = writeSignals(personOnProcessing, taskPayload); Path partPath = writeSignals(personOnProcessing, taskPayload);

View file

@ -1,18 +1,24 @@
package ru.nbch.credit_tracker.service.task.impl; package ru.nbch.credit_tracker.service.task.impl;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
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.PhonesMap; import ru.nbch.credit_tracker.entities.app.PhonesMap;
import ru.nbch.credit_tracker.entities.indic.Name; import ru.nbch.credit_tracker.entities.indic.Name;
import ru.nbch.credit_tracker.model.FlagData;
import ru.nbch.credit_tracker.model.IdData;
import ru.nbch.credit_tracker.model.NameData; import ru.nbch.credit_tracker.model.NameData;
import ru.nbch.credit_tracker.model.PipelineContext;
import ru.nbch.credit_tracker.model.SubjectProfile; import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.model.impl.PackageVariable; import ru.nbch.credit_tracker.model.impl.PackageVariable;
import ru.nbch.credit_tracker.model.impl.SubjectPayload; import ru.nbch.credit_tracker.model.impl.SubjectPayload;
import ru.nbch.credit_tracker.service.indic.PhoneService2; import ru.nbch.credit_tracker.service.indic.PersonServiceV2;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
import ru.nbch.credit_tracker.service.task.Handler; import ru.nbch.credit_tracker.service.task.Handler;
import ru.nbch.credit_tracker.utils.CTUtil; import ru.nbch.credit_tracker.utils.CTUtil;
@ -24,13 +30,16 @@ import ru.nbch.credit_tracker.utils.CTUtil;
@Service @Service
@Slf4j @Slf4j
public class FidNameEnricher implements Handler<SubjectPayload, SubjectPayload> { public class FidNameEnricher implements Handler<SubjectPayload, SubjectPayload> {
private final PhoneService2 phoneService2; private final PersonServiceV2 personService;
private final CreditTrackerSettings creditTrackerSettings; private final CreditTrackerSettings creditTrackerSettings;
private final PackageRecordsService packageRecordsService;
public FidNameEnricher(PhoneService2 phoneService2, public FidNameEnricher(PersonServiceV2 personService,
CreditTrackerSettings creditTrackerSettings) { CreditTrackerSettings creditTrackerSettings,
this.phoneService2 = phoneService2; PackageRecordsService packageRecordsService) {
this.personService = personService;
this.creditTrackerSettings = creditTrackerSettings; this.creditTrackerSettings = creditTrackerSettings;
this.packageRecordsService = packageRecordsService;
} }
@Override @Override
@ -39,50 +48,81 @@ public class FidNameEnricher implements Handler<SubjectPayload, SubjectPayload>
var ctx = obtainContext(PackageVariable.class, taskPayload); var ctx = obtainContext(PackageVariable.class, taskPayload);
Long packageId = ctx.get(PackageVariable.packageId); Long packageId = ctx.get(PackageVariable.packageId);
log.debug("NameEnricherStage handle by packageId: {}, size of bucket for save: {}", packageId, subjects.size()); log.debug("NameEnricherStage handle by packageId: {}, size of bucket for save: {}", packageId, subjects.size());
//найдем телефоны в табличном кэше
if (subjects.getFirst().getFid() == null) { Map<Long, PhonesMap> cachedRecords = packageRecordsService.findCachedPhones(subjects);
processByNumber(subjects); processByNumber(subjects, cachedRecords, ctx);
} else {
processByFid(subjects);
}
return taskPayload; return taskPayload;
} }
private void processByNumber(List<SubjectProfile> subjects) { private void processByNumber(List<SubjectProfile> subjects,
LocalDateTime now = LocalDateTime.now(); Map<Long, PhonesMap> cachedRecords,
Map<String, Name> nameByPhone = phoneService2.findNameByNumber(subjects); PipelineContext<PackageVariable> context) {
List<PhonesMap> subjectForSave = subjects.stream().map(subject -> { List<SubjectProfile> noFidsData = subjects.stream()
Name name = nameByPhone.get(CTUtil.normalizePhoneNumber(subject.getPhone())); .filter(subjectProfile -> !cachedRecords.containsKey(subjectProfile.getPhone()))
if (name != null) { .toList();
NameData nameData = NameData.builder()
.middleName(name.getMiddle())
.firstName(name.getFirst())
.lastName(name.getLast())
.fileSinceDate(name.getFileSinceDate())
.birthDate(name.getBirthDate())
.build();
subject.setFid(name.getFid()); Map<String, Name> nameByPhone = personService.findNameByNumber(noFidsData);
subject.setNameData(nameData); AtomicInteger cacheHits = context.get(PackageVariable.cacheHits);
AtomicInteger cacheMisses = context.get(PackageVariable.cacheMisses);
List<PhonesMap> subjectForSave = subjects.stream().flatMap(subject -> {
Long phone = subject.getPhone();
if (cachedRecords.containsKey(phone)) {
cacheHits.incrementAndGet();
fillByCache(subject, cachedRecords.get(phone));
} else { } else {
subject.setFid(null); cacheMisses.incrementAndGet();
Name name = nameByPhone.get(CTUtil.normalizePhoneNumber(phone.toString()));
if (name == null) {
return Stream.empty();
} }
fillByName(subject, name);
return PhonesMap.builder() return Stream.of(PhonesMap.builder()
.id(subject.getMapId())
.fid(subject.getFid()) .fid(subject.getFid())
.calculatedAt(now) .phone(phone)
.build(); .name1(name.getLast())
.first(name.getFirst())
.middle(name.getMiddle())
.birthDt(name.getBirthDate())
.build());
}
return Stream.empty();
}).toList(); }).toList();
phoneService2.updateFid(subjectForSave); packageRecordsService.saveToCache(subjectForSave);
} }
private void processByFid(List<SubjectProfile> subjects) { private void fillByCache(SubjectProfile subjectProfile, PhonesMap cachedRecord) {
Map<Integer, Name> nameByPhone = phoneService2.nameByFid(subjects); NameData nameData = NameData.builder()
subjects.forEach(subject -> { .middleName(cachedRecord.getMiddle())
Name name = nameByPhone.get(subject.getFid()); .firstName(cachedRecord.getFirst())
if (name != null) { .lastName(cachedRecord.getName1())
.birthDate(cachedRecord.getBirthDt())
.build();
subjectProfile.setNameData(nameData);
Optional.of(cachedRecord)
.filter(cr -> cachedRecord.getSerNum() != null && cachedRecord.getIdType() != null)
.map(cr -> Optional.of(
(IdData.builder()
.idNum(cr.getSerNum())
.idType(cr.getIdType())
.build()
)))
.ifPresent(idData -> subjectProfile.setIdData(idData.get()));
Optional.of(cachedRecord)
.filter(cr -> cachedRecord.getFlagDebt5000() != null && cachedRecord.getFlag90days() != null)
.map(cr -> Optional.of(
(FlagData.builder()
.flag_debt5000(cr.getFlagDebt5000())
.flag_90_12(cr.getFlag90days())
.build()
)))
.ifPresent(flagData -> subjectProfile.setFlagData(flagData.get()));
}
private void fillByName(SubjectProfile subjectProfile, Name name) {
NameData nameData = NameData.builder() NameData nameData = NameData.builder()
.middleName(name.getMiddle()) .middleName(name.getMiddle())
.firstName(name.getFirst()) .firstName(name.getFirst())
@ -91,9 +131,8 @@ public class FidNameEnricher implements Handler<SubjectPayload, SubjectPayload>
.birthDate(name.getBirthDate()) .birthDate(name.getBirthDate())
.build(); .build();
subject.setNameData(nameData); subjectProfile.setFid(name.getFid());
} subjectProfile.setNameData(nameData);
});
} }
@Override @Override

View file

@ -1,33 +1,36 @@
package ru.nbch.credit_tracker.service.task.impl; package ru.nbch.credit_tracker.service.task.impl;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
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.FlagDetail; import ru.nbch.credit_tracker.model.FlagData;
import ru.nbch.credit_tracker.model.SubjectProfile; import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.model.impl.SubjectPayload; import ru.nbch.credit_tracker.model.impl.SubjectPayload;
import ru.nbch.credit_tracker.service.indic.FlagsService2; import ru.nbch.credit_tracker.service.indic.FlagsService2;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
@Slf4j @Slf4j
@Service @Service
public class FlagsEnricher implements Consumer<SubjectPayload> { public class FlagsEnricher implements Consumer<SubjectPayload> {
private final FlagsService2 flagsService; private final FlagsService2 flagsService;
private final PackageRecordsService packageRecordsService;
private final ExecutorService ioPool; private final ExecutorService ioPool;
public FlagsEnricher(FlagsService2 flagsService, public FlagsEnricher(FlagsService2 flagsService,
PackageRecordsService packageRecordsService,
CreditTrackerSettings creditTrackerSettings) { CreditTrackerSettings creditTrackerSettings) {
this.flagsService = flagsService; this.flagsService = flagsService;
this.packageRecordsService = packageRecordsService;
this.ioPool = new ThreadPoolExecutor(creditTrackerSettings.getPipeline().flagEnricherStageConcurrency(), this.ioPool = new ThreadPoolExecutor(creditTrackerSettings.getPipeline().flagEnricherStageConcurrency(),
10, 10,
0L, TimeUnit.MINUTES, 0L, TimeUnit.MINUTES,
@ -49,50 +52,38 @@ public class FlagsEnricher implements Consumer<SubjectPayload> {
List<SubjectProfile> subjects = subjectPayload.getSubjects(); List<SubjectProfile> subjects = subjectPayload.getSubjects();
log.debug("FlagsEnricher handle by packageId: {}, size: {}", subjectPayload.getPackageId(), subjects.size()); log.debug("FlagsEnricher handle by packageId: {}, size: {}", subjectPayload.getPackageId(), subjects.size());
List<Integer> fids = subjects.stream() List<Integer> noFlagDataFids = subjects.stream()
.filter(subjectProfile -> subjectProfile.getFlagData() == null)
.map(SubjectProfile::getFid) .map(SubjectProfile::getFid)
.filter(Objects::nonNull)
.toList(); .toList();
LocalDate yearAgo = LocalDate.now().minusYears(1); LocalDate yearAgo = LocalDate.now().minusYears(1);
Map<Integer, Integer> flagsDebt5000 = flagsService.findFlagsDebt5000(fids); Map<Integer, Integer> flagsDebt5000 = flagsService.findFlagsDebt5000(noFlagDataFids);
Map<Integer, Integer> flag90ByPastDueArrear = flagsService.findFlag90ByPastDueArrear(fids, yearAgo); Map<Integer, Integer> flag90ByPastDueArrear = flagsService.findFlag90ByPastDueArrear(noFlagDataFids, yearAgo);
Map<Integer, Integer> flag90ByRuPaymt = flagsService.findFlag90ByRuPaymt(fids, yearAgo); Map<Integer, Integer> flag90ByRuPaymt = flagsService.findFlag90ByRuPaymt(noFlagDataFids, yearAgo);
List<FlagDetail> flagDetails = subjects.stream() List<FlagData> flagCacheOnUpdate = subjects.stream()
.filter(subjectProfile -> subjectProfile.getFid() != null) .filter(subjectProfile -> subjectProfile.getFid() != null)
.map(subject -> { .flatMap(subject -> {
if (subject.getFlagData() == null) {
Integer debt5000 = flagsDebt5000.getOrDefault(subject.getFid(), 0); Integer debt5000 = flagsDebt5000.getOrDefault(subject.getFid(), 0);
int pastDue90 = flag90ByPastDueArrear.getOrDefault(subject.getFid(), 0); int pastDue90 = flag90ByPastDueArrear.getOrDefault(subject.getFid(), 0);
int paymt90 = flag90ByRuPaymt.getOrDefault(subject.getFid(), 0); int paymt90 = flag90ByRuPaymt.getOrDefault(subject.getFid(), 0);
Integer flagDays90 = Math.max(pastDue90, paymt90); Integer flagDays90 = Math.max(pastDue90, paymt90);
return FlagDetail.builder() FlagData flagData = FlagData.builder()
.mapId(subject.getMapId()) .flag_90_12(flagDays90)
.subjectId(subject.getIdentifier()) .flag_debt5000(debt5000)
.packageId(subjectPayload.getPackageId())
.fid(subject.getFid())
.phone(subject.getPhone()) .phone(subject.getPhone())
.flagDebt5000(debt5000)
.flag90days(flagDays90)
.calculatedAt(LocalDateTime.now())
.build(); .build();
subject.setFlagData(flagData);
return Stream.of(flagData);
}
return Stream.empty();
}).toList(); }).toList();
log.debug("updating calculated flags size {}", flagDetails.size()); packageRecordsService.updateFlagCache(flagCacheOnUpdate);
flagsService.updateCalculationFlags(flagDetails);
if (update) {
//если signals_phone_fid_map#fid == null, удалить signals_flags с таким map_id
List<Long> phoneFidMapIdsWithNullFid = subjects.stream()
.filter(subject -> subject.getFid() == null)
.map(SubjectProfile::getMapId)
.filter(Objects::nonNull)
.toList();
if (!phoneFidMapIdsWithNullFid.isEmpty()) {
log.debug("deleting flags for signals_phone_fid_map#fid == null; amount: {}", phoneFidMapIdsWithNullFid.size());
flagsService.deleteFlags(phoneFidMapIdsWithNullFid);
}
}
} }
@Override @Override

View file

@ -1,8 +1,8 @@
package ru.nbch.credit_tracker.service.task.impl; package ru.nbch.credit_tracker.service.task.impl;
import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
@ -10,24 +10,21 @@ import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
import ru.nbch.credit_tracker.entities.app.UserPackage; import ru.nbch.credit_tracker.entities.app.UserPackage;
import ru.nbch.credit_tracker.enums.PoisonType; import ru.nbch.credit_tracker.enums.PoisonType;
import ru.nbch.credit_tracker.exceptions.SignalClientException; import ru.nbch.credit_tracker.exceptions.SignalClientException;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper;
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
import ru.nbch.credit_tracker.model.PipelineContext; import ru.nbch.credit_tracker.model.PipelineContext;
import ru.nbch.credit_tracker.model.SubjectProfile; import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.model.impl.PackageVariable; import ru.nbch.credit_tracker.model.impl.PackageVariable;
import ru.nbch.credit_tracker.model.impl.SubjectPayload; import ru.nbch.credit_tracker.model.impl.SubjectPayload;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
import ru.nbch.credit_tracker.service.task.SetupParam; import ru.nbch.credit_tracker.service.task.SetupParam;
import ru.nbch.credit_tracker.service.task.setup.IPipeLineStarter; 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; import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
public abstract class KickPipeLine implements IPipeLineStarter<SubjectPayload> { public abstract class KickPipeLine implements IPipeLineStarter<SubjectPayload> {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
protected final Long packageId; protected final Long packageId;
private final Path pkgPath;
private final StaxXmlProcessor xmlProcessor;
protected final UserPackageMapper userPackageMapper; protected final UserPackageMapper userPackageMapper;
protected final PackagesRecordsMapper phoneFidMapMapper; protected final PackageRecordsService packageRecordsService;
protected final CreditTrackerSettings creditTrackerSettings; protected final CreditTrackerSettings creditTrackerSettings;
private final int BATCH_SIZE; private final int BATCH_SIZE;
private boolean isInterrupted = false; private boolean isInterrupted = false;
@ -35,16 +32,13 @@ public abstract class KickPipeLine implements IPipeLineStarter<SubjectPayload> {
private PipelineContext<PackageVariable> context; private PipelineContext<PackageVariable> context;
public KickPipeLine(StaxXmlProcessor xmlProcessor, public KickPipeLine(SetupParam setupParam,
SetupParam setupParam,
UserPackageMapper userPackageMapper, UserPackageMapper userPackageMapper,
PackagesRecordsMapper phoneFidMapMapper, PackageRecordsService packageRecordsService,
CreditTrackerSettings creditTrackerSettings) { CreditTrackerSettings creditTrackerSettings) {
this.packageId = setupParam.packageId(); this.packageId = setupParam.packageId();
this.pkgPath = setupParam.xmlReqPath();
this.xmlProcessor = xmlProcessor;
this.userPackageMapper = userPackageMapper; this.userPackageMapper = userPackageMapper;
this.phoneFidMapMapper = phoneFidMapMapper; this.packageRecordsService = packageRecordsService;
this.creditTrackerSettings = creditTrackerSettings; this.creditTrackerSettings = creditTrackerSettings;
this.BATCH_SIZE = creditTrackerSettings.getPipeline().subjectBatchSize(); this.BATCH_SIZE = creditTrackerSettings.getPipeline().subjectBatchSize();
} }
@ -66,6 +60,8 @@ public abstract class KickPipeLine implements IPipeLineStarter<SubjectPayload> {
try { try {
log.info("Start kicker: mode:{}, packageId: {};", mode(), packageId); log.info("Start kicker: mode:{}, packageId: {};", mode(), packageId);
context.store(PackageVariable.packageId, packageId); context.store(PackageVariable.packageId, packageId);
context.store(PackageVariable.cacheMisses, new AtomicInteger());
context.store(PackageVariable.cacheHits, new AtomicInteger());
int limit = BATCH_SIZE; int limit = BATCH_SIZE;
UserPackage userPackage = userPackageMapper.findPackage(packageId); UserPackage userPackage = userPackageMapper.findPackage(packageId);
List<PackagesRecordsMap> page = nextPage(limit); List<PackagesRecordsMap> page = nextPage(limit);
@ -74,7 +70,7 @@ public abstract class KickPipeLine implements IPipeLineStarter<SubjectPayload> {
List<SubjectProfile> subjectProfiles = page.stream().map(phoneFidMap -> SubjectProfile.builder() List<SubjectProfile> subjectProfiles = page.stream().map(phoneFidMap -> SubjectProfile.builder()
.mapId(phoneFidMap.getId()) .mapId(phoneFidMap.getId())
.identifier(phoneFidMap.getSubjectId()) .identifier(phoneFidMap.getSubjectId())
.phone(phoneFidMap.getPhone()) .phone(Long.valueOf(phoneFidMap.getPhone()))
.build()).toList(); .build()).toList();
try { try {
SubjectPayload payload = new SubjectPayload(packageId, userPackage.getUserId(), userPackage.getPackageName(), subjectProfiles); SubjectPayload payload = new SubjectPayload(packageId, userPackage.getUserId(), userPackage.getPackageName(), subjectProfiles);

View file

@ -3,19 +3,18 @@ package ru.nbch.credit_tracker.service.task.impl;
import java.util.List; import java.util.List;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap; import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper;
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
import ru.nbch.credit_tracker.service.task.SetupParam; import ru.nbch.credit_tracker.service.task.SetupParam;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
public class KickPipeLineDefaultImpl extends KickPipeLine { public class KickPipeLineDefaultImpl extends KickPipeLine {
private boolean cachedPhonesWereFound = false;
public KickPipeLineDefaultImpl(StaxXmlProcessor xmlProcessor, public KickPipeLineDefaultImpl(SetupParam setupParam,
SetupParam setupParam,
UserPackageMapper userPackageMapper, UserPackageMapper userPackageMapper,
PackagesRecordsMapper phoneFidMapMapper, PackageRecordsService packageRecordsService,
CreditTrackerSettings creditTrackerSettings) { CreditTrackerSettings creditTrackerSettings) {
super(xmlProcessor, setupParam, userPackageMapper, phoneFidMapMapper, creditTrackerSettings); super(setupParam, userPackageMapper, packageRecordsService, creditTrackerSettings);
} }
@Override @Override
@ -25,7 +24,7 @@ public class KickPipeLineDefaultImpl extends KickPipeLine {
@Override @Override
protected List<PackagesRecordsMap> nextPage(Integer limit) { protected List<PackagesRecordsMap> nextPage(Integer limit) {
return phoneFidMapMapper.findFullPhoneFidMap(packageId, limit, offset); return packageRecordsService.findFullPhoneFidMap(packageId, limit, offset);
} }
} }

View file

@ -4,21 +4,19 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap; import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper;
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
import ru.nbch.credit_tracker.service.task.SetupParam; import ru.nbch.credit_tracker.service.task.SetupParam;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
public class KickPipeLineRepeatedRestoreImpl extends KickPipeLine { public class KickPipeLineRepeatedRestoreImpl extends KickPipeLine {
private boolean oldRowsWereFound = false; private boolean oldRowsWereFound = false;
private final Integer daysToUpdateFlags; private final Integer daysToUpdateFlags;
public KickPipeLineRepeatedRestoreImpl(StaxXmlProcessor xmlProcessor, public KickPipeLineRepeatedRestoreImpl(SetupParam setupParam,
SetupParam setupParam,
UserPackageMapper userPackageMapper, UserPackageMapper userPackageMapper,
PackagesRecordsMapper phoneFidMapMapper, PackageRecordsService packageRecordsService,
CreditTrackerSettings creditTrackerSettings) { CreditTrackerSettings creditTrackerSettings) {
super(xmlProcessor, setupParam, userPackageMapper, phoneFidMapMapper, creditTrackerSettings); super(setupParam, userPackageMapper, packageRecordsService, creditTrackerSettings);
this.daysToUpdateFlags = creditTrackerSettings.getDaysToUpdateFlags().intValue(); this.daysToUpdateFlags = creditTrackerSettings.getDaysToUpdateFlags().intValue();
} }

View file

@ -4,20 +4,18 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap; import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
import ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper;
import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper; import ru.nbch.credit_tracker.mapper.signal.UserPackageMapper;
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
import ru.nbch.credit_tracker.service.task.SetupParam; import ru.nbch.credit_tracker.service.task.SetupParam;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
public class KickPipeLineRestoreImpl extends KickPipeLine { public class KickPipeLineRestoreImpl extends KickPipeLine {
private boolean nullFidsWereFound = false; private boolean nullFidsWereFound = false;
public KickPipeLineRestoreImpl(StaxXmlProcessor xmlProcessor, public KickPipeLineRestoreImpl(SetupParam setupParam,
SetupParam setupParam,
UserPackageMapper userPackageMapper, UserPackageMapper userPackageMapper,
PackagesRecordsMapper phoneFidMapMapper, PackageRecordsService packageRecordsService,
CreditTrackerSettings creditTrackerSettings) { CreditTrackerSettings creditTrackerSettings) {
super(xmlProcessor, setupParam, userPackageMapper, phoneFidMapMapper, creditTrackerSettings); super(setupParam, userPackageMapper, packageRecordsService, creditTrackerSettings);
} }
@Override @Override

View file

@ -83,6 +83,7 @@ public class PipeLineBuilderV2<FIRST extends StagePayload, LAST extends StagePay
pipeLineTerminator.setPollingQueue(lastQueue); pipeLineTerminator.setPollingQueue(lastQueue);
p.setTerminator(pipeLineTerminator); p.setTerminator(pipeLineTerminator);
p.setStages(stages); p.setStages(stages);
p.setContext(context);
return p; return p;
} }

View file

@ -110,4 +110,17 @@ public abstract class BaseStaxReader<T> implements StaxReader<T> {
} }
return input.substring(idx + 1); return input.substring(idx + 1);
} }
/**
* Пропускает текущий элемент целиком (вместе со вложенными).
* Reader должен стоять на START_ELEMENT.
*/
protected void skipElement(XMLStreamReader r) throws XMLStreamException {
int depth = 1;
while (depth > 0 && r.hasNext()) {
int e = r.next();
if (e == XMLStreamConstants.START_ELEMENT) depth++;
else if (e == XMLStreamConstants.END_ELEMENT) depth--;
}
}
} }

View file

@ -1,9 +1,8 @@
package ru.nbch.credit_tracker.service.xml.stax; package ru.nbch.credit_tracker.service.xml.stax;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
public class MonitoringRequestStaxReader extends BaseStaxReader<MonitoringRequest> { public class MonitoringRequestStaxReader extends BaseStaxReader<MonitoringRequest> {
@ -18,22 +17,19 @@ public class MonitoringRequestStaxReader extends BaseStaxReader<MonitoringReques
} }
@Override @Override
protected boolean innerProcess(XMLStreamReader reader, MonitoringRequest obj) { protected boolean innerProcess(XMLStreamReader reader, MonitoringRequest obj) throws XMLStreamException {
String text = buffer.toString(); String text = buffer.toString();
String currPath = getPath(); String currPath = getPath();
switch (currPath) { switch (currPath) {
case "/MonitoringRequest/UserId" -> case "/MonitoringRequest/UserId" -> obj.setUserId(text);
obj.setUserId(text); case "/MonitoringRequest/Password" -> obj.setPassword(text);
case "/MonitoringRequest/Password" -> case "/MonitoringRequest/PackageName" -> obj.setPackageName(text);
obj.setPassword(text); case "/MonitoringRequest/SignalTypes/SignalType" -> {
case "/MonitoringRequest/PackageName" -> if (!text.isEmpty()) obj.getSignalTypes().add(Integer.parseInt(text));
obj.setPackageName(text); }
case "/MonitoringRequest/Subjects/Subject" -> case "/MonitoringRequest/Subjects/Subject" -> obj.finalizeSubject();
obj.finalizeSubject(); case "/MonitoringRequest/Subjects/Subject/Id" -> obj.getCurrentSubject().setId(text);
case "/MonitoringRequest/Subjects/Subject/Id" -> case "/MonitoringRequest/Subjects/Subject/ClientId" -> obj.getCurrentSubject().setClientId(text);
obj.getCurrentSubject().setId(text);
case "/MonitoringRequest/Subjects/Subject/ClientId" ->
obj.getCurrentSubject().setClientId(text);
} }
return false; return false;
} }

View file

@ -92,6 +92,31 @@ public class CTUtil {
return "9" + phoneNumber; return "9" + phoneNumber;
} }
public static String defineIdType(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 "";
}
};
}
}
public static Path workingPathToReqByPackage(String root, UserPackage userPackage) { public static Path workingPathToReqByPackage(String root, UserPackage userPackage) {
return Path.of(root, "tmp", userPackage.getUserId().substring(0, 6) + "_" +userPackage.getPackageName() + ".xml"); return Path.of(root, "tmp", userPackage.getUserId().substring(0, 6) + "_" +userPackage.getPackageName() + ".xml");
} }

View file

@ -5,31 +5,41 @@
<mapper namespace="ru.nbch.credit_tracker.mapper.indic.PersonMapper"> <mapper namespace="ru.nbch.credit_tracker.mapper.indic.PersonMapper">
<resultMap id="nameDataResultMap" type="ru.nbch.credit_tracker.service.indic.PersonService$NameData"> <resultMap id="nameDataResultMap" type="ru.nbch.credit_tracker.entities.indic.Name">
<result property="fid" column="FID" /> <result property="fid" column="fid"/>
<result property="firstName" column="FIRST" /> <result property="number" column="number"/>
<result property="lastName" column="NAME_1" /> <result property="fileSinceDate" column="file_since_dt_name"/>
<result property="middleName" column="MIDDLE" /> <result property="first" column="first"/>
<result property="birthDate" column="BIRTH_DT" /> <result property="last" column="NAME_1"/>
<result property="fileSinceDate" column="FILE_SINCE_DT" /> <result property="middle" column="middle"/>
<result property="birthDate" column="birth_dt"/>
</resultMap> </resultMap>
<resultMap id="passportDataResultMap" type="ru.nbch.credit_tracker.service.indic.PersonService$PassportData"> <resultMap id="passportDataResultMap" type="ru.nbch.credit_tracker.entities.indic.Id">
<result property="fid" column="FID" /> <result property="fid" column="FID"/>
<result property="serNum" column="SER_NUM" /> <result property="serNum" column="SER_NUM"/>
<result property="idNum" column="ID_NUM" /> <result property="idNum" column="ID_NUM"/>
<result property="issDate" column="ISS_DTE" /> <result property="issDate" column="ISS_DTE"/>
<result property="fileSinceDate" column="FILE_SINCE_DT" /> <result property="fileSinceDate" column="FILE_SINCE_DT"/>
<result property="idType" column="ID_TYPE" /> <result property="idType" column="ID_TYPE"/>
<result property="idType2" column="ID_TYPE2" /> <result property="idType2" column="ID_TYPE2"/>
</resultMap> </resultMap>
<select id="findNameData" resultMap="nameDataResultMap"> <select id="findNameData" resultMap="nameDataResultMap">
SELECT FID, FIRST, NAME_1, MIDDLE, BIRTH_DT, FILE_SINCE_DT SELECT
FROM NAME pn.number as number,
WHERE FID IN pn.fid as fid,
<foreach item="fid" collection="fids" open="(" separator="," close=")"> nf.first as first,
#{fid} nf.middle as middle,
nf.name_1 as name_1,
nf.birth_dt as 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
<foreach item="phone" collection="phones" open="(" separator="," close=")">
#{phone}
</foreach> </foreach>
WITH UR WITH UR
</select> </select>

View file

@ -0,0 +1,48 @@
<?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.signal.PackagesRecordsJoinMapper">
<resultMap id="PackageRecordWithPhone" type="ru.nbch.credit_tracker.entities.app.PackageRecordWithPhone">
<result property="packageId" column="package_id"/>
<result property="subjectId" column="subject_id"/>
<result property="phone" column="phone"/>
<result property="fid" column="fid"/>
<result property="name1" column="name_1"/>
<result property="first" column="first"/>
<result property="middle" column="middle"/>
<result property="birthDt" column="birth_dt"/>
<result property="serNum" column="ser_num"/>
<result property="idType" column="id_type"/>
<result property="flagDebt5000" column="flag_debt5000"/>
<result property="flag90days" column="flag_90_12"/>
</resultMap>
<select id="findPackagesRecordsJoinPage" resultMap="PackageRecordWithPhone" resultType="java.util.List">
select spr.id,
spr.package_id,
spr.subject_id,
spr.phone,
sup.fid,
sup.name_1,
sup.first,
sup.middle,
sup.birth_dt,
sup.ser_num,
sup.id_type,
sup.flag_debt5000,
sup.flag_90_12
from signals_packages_records spr
join signals_phones_map sup on cast(spr.phone as bigint) = sup.phone
where spr.package_id = #{packageId}
and sup.fid is not null
ORDER BY spr.id
LIMIT
#{limit}
OFFSET
#{offset}
</select>
</mapper>

View file

@ -3,17 +3,44 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ru.nbch.credit_tracker.mapper.signal.PackagesRecordsMapper"> <mapper namespace="ru.nbch.credit_tracker.mapper.signal.PhonesMapMapper">
<resultMap id="PhoneFidMapResultMap" type="ru.nbch.credit_tracker.entities.app.PackagesRecordsMap"> <resultMap id="PhoneMap" type="ru.nbch.credit_tracker.entities.app.PhonesMap">
<result property="id" column="id"/> <result property="fid" column="fid"/>
<result property="packageId" column="package_id"/>
<result property="subjectId" column="subject_id"/>
<result property="phone" column="phone"/> <result property="phone" column="phone"/>
<result property="errorText" column="error_text"/> <result property="name1" column="name_1"/>
<result property="first" column="first"/>
<result property="middle" column="middle"/>
<result property="birthDt" column="birth_dt"/>
<result property="serNum" column="ser_num"/>
<result property="idType" column="id_type"/>
<result property="flagDebt5000" column="flag_debt5000"/>
<result property="flag90days" column="flag_90_12"/>
<result property="searchedAt" column="searched_at"/>
<result property="calculatedAt" column="calculated_at"/>
</resultMap> </resultMap>
<select id="registerJson" parameterType="string" resultType="long"> <select id="getCachedData" resultMap="PhoneMap" resultType="java.util.List">
SELECT fid,
phone,
name_1,
first,
middle,
birth_dt,
ser_num,
id_type,
flag_debt5000,
flag_90_12,
searched_at,
calculated_at
FROM signals_phones_map
WHERE phone in
<foreach item="phone" collection="phones" open="(" separator="," close=")">
#{phone}
</foreach>
</select>
<select id="registerJson" parameterType="string">
WITH src AS (SELECT row_number() OVER () AS rn, WITH src AS (SELECT row_number() OVER () AS rn,
fid, fid,
phone, phone,
@ -39,10 +66,39 @@
middle, middle,
birth_dt birth_dt
FROM src FROM src
ORDER BY rn ON CONFLICT (phone) DO UPDATE
RETURNING id; SET fid = EXCLUDED.fid,
phone = EXCLUDED.phone,
name_1 = EXCLUDED.name_1,
first = EXCLUDED.first,
middle = EXCLUDED.middle,
birth_dt = EXCLUDED.birth_dt
</select> </select>
<update id="updateIdCachedData" parameterType="string">
update signals_phones_map dst
set ser_num = src.ser_num,
id_type = src.id_type
FROM json_to_recordset(#{json}::json) AS src(
phone bigint,
ser_num varchar(255),
id_type varchar(255)
)
where dst.phone = src.phone;
</update>
<update id="updateFlagCachedData" parameterType="string">
update signals_phones_map dst
set flag_debt5000 = src.flag_debt5000,
flag_90_12 = src.flag_90_12
FROM json_to_recordset(#{json}::json) AS src(
phone bigint,
flag_debt5000 smallint,
flag_90_12 smallint
)
where dst.phone = src.phone;
</update>
<update id="setFidJson" parameterType="string"> <update id="setFidJson" parameterType="string">
update signals_phones_map dst update signals_phones_map dst
set fid = src.fid, set fid = src.fid,
@ -55,6 +111,7 @@
</update> </update>
<!-- <select id="pageByPackageIdAndOlderThanN" resultMap="PhoneFidMapResultMap" resultType="java.util.List">--> <!-- <select id="pageByPackageIdAndOlderThanN" resultMap="PhoneFidMapResultMap" resultType="java.util.List">-->
<!-- SELECT id,--> <!-- SELECT id,-->
<!-- package_id,--> <!-- package_id,-->

View file

@ -16,6 +16,7 @@
<result property="monitoringAt" column="monitoring_at"/> <result property="monitoringAt" column="monitoring_at"/>
<result property="lastSearchedAt" column="last_searched_at"/> <result property="lastSearchedAt" column="last_searched_at"/>
<result property="rejectStatus" column="reject_status"/> <result property="rejectStatus" column="reject_status"/>
<result property="signalTypes" column="signal_types"/>
</resultMap> </resultMap>
<select id="isPackageNotUnique" resultType="boolean"> <select id="isPackageNotUnique" resultType="boolean">
@ -62,8 +63,8 @@
<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.app.UserPackage">
INSERT INTO signals_user_packages (membercode, package_name, created_at, status) INSERT INTO signals_user_packages (membercode, package_name, signal_types, created_at, status)
values (#{userPackage.userId}, #{userPackage.packageName}, #{userPackage.createdAt}, #{userPackage.status}) RETURNING id values (#{userPackage.userId}, #{userPackage.packageName}, #{userPackage.signalTypes}, #{userPackage.createdAt}, #{userPackage.status}) RETURNING id
</select> </select>
<update id="updatePackageStatus"> <update id="updatePackageStatus">
@ -96,17 +97,35 @@
WHERE id = #{id} WHERE id = #{id}
</update> </update>
<select id="findPackage" resultMap="packageDataResultMap" <select id="findPackage" resultMap="packageDataResultMap">
resultType="ru.nbch.credit_tracker.entities.app.UserPackage"> SELECT id,
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at, last_searched_at, reject_status membercode,
package_name,
created_at,
status,
deactivated_at,
last_downloaded_report,
monitoring_at,
last_searched_at,
reject_status,
signal_types
FROM signals_user_packages FROM signals_user_packages
WHERE id = #{id} WHERE id = #{id}
LIMIT 1 LIMIT 1
</select> </select>
<select id="findUserPackages" resultMap="packageDataResultMap" <select id="findUserPackages" resultMap="packageDataResultMap">
resultType="ru.nbch.credit_tracker.entities.app.UserPackage"> SELECT id,
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at, last_searched_at, reject_status membercode,
package_name,
created_at,
status,
deactivated_at,
last_downloaded_report,
monitoring_at,
last_searched_at,
reject_status,
signal_types
FROM signals_user_packages FROM signals_user_packages
WHERE membercode IS NOT NULL WHERE membercode IS NOT NULL
AND LEFT(membercode, 6) = #{userId} AND LEFT(membercode, 6) = #{userId}
@ -116,17 +135,35 @@
</foreach> </foreach>
</select> </select>
<select id="findAllPackagesByUserId" resultMap="packageDataResultMap" <select id="findAllPackagesByUserId" resultMap="packageDataResultMap">
resultType="ru.nbch.credit_tracker.entities.app.UserPackage"> SELECT id,
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at, last_searched_at, reject_status membercode,
package_name,
created_at,
status,
deactivated_at,
last_downloaded_report,
monitoring_at,
last_searched_at,
reject_status,
signal_types
FROM signals_user_packages FROM signals_user_packages
WHERE membercode IS NOT NULL WHERE membercode IS NOT NULL
AND LEFT(membercode, 6) = #{userId} AND LEFT(membercode, 6) = #{userId}
</select> </select>
<select id="findAllPackagesByStatus" resultMap="packageDataResultMap" <select id="findAllPackagesByStatus" resultMap="packageDataResultMap">
resultType="ru.nbch.credit_tracker.entities.app.UserPackage"> SELECT id,
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at, last_searched_at, reject_status membercode,
package_name,
created_at,
status,
deactivated_at,
last_downloaded_report,
monitoring_at,
last_searched_at,
reject_status,
signal_types
FROM signals_user_packages FROM signals_user_packages
WHERE status in WHERE status in
<foreach collection="statuses" item="status" separator="," open="(" close=")"> <foreach collection="statuses" item="status" separator="," open="(" close=")">
@ -135,7 +172,17 @@
</select> </select>
<select id="findByMemberCodeAndPackageName" resultMap="packageDataResultMap"> <select id="findByMemberCodeAndPackageName" resultMap="packageDataResultMap">
SELECT id, membercode, package_name, created_at, status, deactivated_at, last_downloaded_report, monitoring_at, last_searched_at, reject_status SELECT id,
membercode,
package_name,
created_at,
status,
deactivated_at,
last_downloaded_report,
monitoring_at,
last_searched_at,
reject_status,
signal_types
FROM signals_user_packages FROM signals_user_packages
WHERE LEFT(membercode, 6) = #{memberCode} AND package_name = #{packageName} WHERE LEFT(membercode, 6) = #{memberCode} AND package_name = #{packageName}
</select> </select>

View file

@ -5,6 +5,8 @@ CREATE TABLE app_version
alter table signals_user_packages alter table signals_user_packages
add LAST_SEARCHED_AT timestamp; add LAST_SEARCHED_AT timestamp;
alter table signals_user_packages
add signal_types varchar(255);
alter table signals_user_packages alter table signals_user_packages
add REJECT_STATUS varchar(255); add REJECT_STATUS varchar(255);
@ -47,6 +49,8 @@ CREATE TABLE signals_phones_map
ALTER TABLE signals_phones_map ALTER TABLE signals_phones_map
ADD CONSTRAINT signals_phones_map_phone_key UNIQUE (PHONE); ADD CONSTRAINT signals_phones_map_phone_key UNIQUE (PHONE);
alter table signals_phone_fid_map rename to signals_packages_records; alter table signals_phone_fid_map rename to signals_packages_records;
alter table signals_packages_records drop column fid; alter table signals_packages_records drop column fid;
alter table signals_packages_records drop column flag_debt5000; alter table signals_packages_records drop column flag_debt5000;

View file

@ -5,9 +5,7 @@ import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceBuilder;
@ -144,7 +142,7 @@ public class FlagsService2Test {
jdbcTemplate.getJdbcTemplate().execute(RU_PASTDUEAREAR_CREATE); jdbcTemplate.getJdbcTemplate().execute(RU_PASTDUEAREAR_CREATE);
jdbcTemplate.getJdbcTemplate().execute(RU_PAYMT_CREATE); jdbcTemplate.getJdbcTemplate().execute(RU_PAYMT_CREATE);
flagsService = new FlagsService(null, jdbcTemplate); // flagsService = new FlagsService(null, jdbcTemplate);
} }
@Test @Test
@ -164,28 +162,28 @@ public class FlagsService2Test {
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT 9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
); );
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids); // Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
//
Assertions.assertEquals(9, resultMap.size()); // Assertions.assertEquals(9, resultMap.size());
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
//
Assertions.assertEquals(1, resultMap.get(1).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(1).getFlag90days());
Assertions.assertEquals(0, resultMap.get(2).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
Assertions.assertEquals(1, resultMap.get(3).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(3).getFlag90days());
Assertions.assertEquals(0, resultMap.get(4).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
Assertions.assertEquals(1, resultMap.get(5).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(5).getFlag90days());
Assertions.assertEquals(1, resultMap.get(6).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(6).getFlag90days());
Assertions.assertEquals(1, resultMap.get(7).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(7).getFlag90days());
Assertions.assertEquals(1, resultMap.get(8).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(8).getFlag90days());
Assertions.assertEquals(1, resultMap.get(9).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(9).getFlag90days());
} }
@Test @Test
@ -204,28 +202,28 @@ public class FlagsService2Test {
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT 9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
); );
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids); // Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
//
Assertions.assertEquals(9, resultMap.size()); // Assertions.assertEquals(9, resultMap.size());
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
//
Assertions.assertEquals(1, resultMap.get(1).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(1).getFlag90days());
Assertions.assertEquals(0, resultMap.get(2).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
Assertions.assertEquals(0, resultMap.get(3).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(3).getFlag90days());
Assertions.assertEquals(0, resultMap.get(4).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
Assertions.assertEquals(1, resultMap.get(5).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(5).getFlag90days());
Assertions.assertEquals(0, resultMap.get(6).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(6).getFlag90days());
Assertions.assertEquals(1, resultMap.get(7).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(7).getFlag90days());
Assertions.assertEquals(0, resultMap.get(8).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(8).getFlag90days());
Assertions.assertEquals(0, resultMap.get(9).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(9).getFlag90days());
} }
@Test @Test
@ -244,28 +242,28 @@ public class FlagsService2Test {
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT 9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
); );
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids); // Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
//
Assertions.assertEquals(9, resultMap.size()); // Assertions.assertEquals(9, resultMap.size());
Assertions.assertEquals(0, resultMap.get(1).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(1).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(2).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(2).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(3).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(3).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(5).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(5).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
//
Assertions.assertEquals(0, resultMap.get(1).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(1).getFlag90days());
Assertions.assertEquals(0, resultMap.get(2).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
Assertions.assertEquals(1, resultMap.get(3).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(3).getFlag90days());
Assertions.assertEquals(0, resultMap.get(4).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
Assertions.assertEquals(0, resultMap.get(5).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(5).getFlag90days());
Assertions.assertEquals(1, resultMap.get(6).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(6).getFlag90days());
Assertions.assertEquals(0, resultMap.get(7).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(7).getFlag90days());
Assertions.assertEquals(1, resultMap.get(8).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(8).getFlag90days());
Assertions.assertEquals(1, resultMap.get(9).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(9).getFlag90days());
} }
private static LocalDate calcLocalDateFromInitialDate(String date) { private static LocalDate calcLocalDateFromInitialDate(String date) {

View file

@ -1,14 +1,5 @@
package ru.nbch.credit_tracker.service; 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.IndicFlagsMapper;
import ru.nbch.credit_tracker.service.indic.FlagsService;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.time.LocalDate; import java.time.LocalDate;
@ -16,9 +7,12 @@ import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.mockito.Mockito.when; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import ru.nbch.credit_tracker.mapper.indic.IndicFlagsMapper;
import ru.nbch.credit_tracker.service.indic.FlagsService;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class FlagsServiceTest { public class FlagsServiceTest {
@ -30,10 +24,10 @@ public class FlagsServiceTest {
@Test @Test
public void testfindFlags() { public void testfindFlags() {
FlagsService flagsService = new FlagsService(flagsMapper, null); // FlagsService flagsService = new FlagsService(flagsMapper, null);
when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(ruPastDuarearDataList); // when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(ruPastDuarearDataList);
when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(ruPaymtDataList); // when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(ruPaymtDataList);
List<Integer> fids = new ArrayList<>(List.of( List<Integer> fids = new ArrayList<>(List.of(
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR 1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
@ -47,36 +41,36 @@ public class FlagsServiceTest {
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT 9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
); );
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids); // Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids);
//
Assertions.assertEquals(9, resultMap.size()); // Assertions.assertEquals(9, resultMap.size());
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000());
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000());
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000());
//
Assertions.assertEquals(1, resultMap.get(1).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(1).getFlag90days());
Assertions.assertEquals(0, resultMap.get(2).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(2).getFlag90days());
Assertions.assertEquals(1, resultMap.get(3).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(3).getFlag90days());
Assertions.assertEquals(0, resultMap.get(4).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(4).getFlag90days());
Assertions.assertEquals(1, resultMap.get(5).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(5).getFlag90days());
Assertions.assertEquals(1, resultMap.get(6).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(6).getFlag90days());
Assertions.assertEquals(1, resultMap.get(7).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(7).getFlag90days());
Assertions.assertEquals(1, resultMap.get(8).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(8).getFlag90days());
Assertions.assertEquals(1, resultMap.get(9).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(9).getFlag90days());
} }
@Test @Test
public void testfindFlagsWithoutRuPaymt() { public void testfindFlagsWithoutRuPaymt() {
FlagsService flagsService = new FlagsService(flagsMapper, null); // FlagsService2 flagsService = new FlagsService2(flagsMapper, null, new ObjectMapper());
when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(ruPastDuarearDataList); // when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(ruPastDuarearDataList);
when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(new ArrayList<>()); // when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(new ArrayList<>());
List<Integer> fids = new ArrayList<>(List.of( List<Integer> fids = new ArrayList<>(List.of(
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR 1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
@ -90,37 +84,38 @@ public class FlagsServiceTest {
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT 9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
); );
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids); // Map<Integer, Integer> resultMap = flagsService.findFlagsDebt5000(fids);
//
Assertions.assertEquals(9, resultMap.size()); // Assertions.assertEquals(9, resultMap.size());
Assertions.assertEquals(1, resultMap.get(1).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(1));
Assertions.assertEquals(1, resultMap.get(2).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(2));
Assertions.assertEquals(1, resultMap.get(3).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(3));
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(4));
Assertions.assertEquals(1, resultMap.get(5).getFlagDebt5000()); // Assertions.assertEquals(1, resultMap.get(5));
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(6));
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(7));
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(8));
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(9));
//
Assertions.assertEquals(1, resultMap.get(1).getFlag90days()); // resultMap = flagsService.findFlag90ByPastDueArrear(fids, LocalDate.now().minusYears(1));
Assertions.assertEquals(0, resultMap.get(2).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(1));
Assertions.assertEquals(0, resultMap.get(3).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(2));
Assertions.assertEquals(0, resultMap.get(4).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(3));
Assertions.assertEquals(1, resultMap.get(5).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(4));
Assertions.assertEquals(0, resultMap.get(6).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(5));
Assertions.assertEquals(1, resultMap.get(7).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(6));
Assertions.assertEquals(0, resultMap.get(8).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(7));
Assertions.assertEquals(0, resultMap.get(9).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(8));
// Assertions.assertEquals(0, resultMap.get(9));
} }
@Test @Test
public void testfindFlagsWithoutRuPastduearreae() { public void testfindFlagsWithoutRuPastduearreae() {
FlagsService flagsService = new FlagsService(flagsMapper, null); // FlagsService2 flagsService = new FlagsService2(flagsMapper, null, new ObjectMapper());
when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(new ArrayList<>()); // when(flagsMapper.findRuPastDuarearData(Mockito.anyList())).thenReturn(new ArrayList<>());
when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(ruPaymtDataList); // when(flagsMapper.findRuPaymtData(Mockito.anyList(), Mockito.any())).thenReturn(ruPaymtDataList);
List<Integer> fids = new ArrayList<>(List.of( List<Integer> fids = new ArrayList<>(List.of(
1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR 1, // есть просрочка 5000, есть просрочка 90_days в RU_PASTDUEARREAR
@ -134,28 +129,29 @@ public class FlagsServiceTest {
9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT 9) // нету в RU_PASTDUEARREAR, нету в RU_PAYMT
); );
Map<Integer, FlagsService.FlagsData> resultMap = flagsService.findFlags(fids); // Map<Integer, Integer> resultMap = flagsService.findFlagsDebt5000(fids);
//
Assertions.assertEquals(9, resultMap.size()); // Assertions.assertEquals(9, resultMap.size());
Assertions.assertEquals(0, resultMap.get(1).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(1));
Assertions.assertEquals(0, resultMap.get(2).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(2));
Assertions.assertEquals(0, resultMap.get(3).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(3));
Assertions.assertEquals(0, resultMap.get(4).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(4));
Assertions.assertEquals(0, resultMap.get(5).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(5));
Assertions.assertEquals(0, resultMap.get(6).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(6));
Assertions.assertEquals(0, resultMap.get(7).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(7));
Assertions.assertEquals(0, resultMap.get(8).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(8));
Assertions.assertEquals(0, resultMap.get(9).getFlagDebt5000()); // Assertions.assertEquals(0, resultMap.get(9));
//
Assertions.assertEquals(0, resultMap.get(1).getFlag90days()); // resultMap = flagsService.findFlag90ByRuPaymt(fids,LocalDate.now().minusYears(1) );
Assertions.assertEquals(0, resultMap.get(2).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(1));
Assertions.assertEquals(1, resultMap.get(3).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(2));
Assertions.assertEquals(0, resultMap.get(4).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(3));
Assertions.assertEquals(0, resultMap.get(5).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(4));
Assertions.assertEquals(1, resultMap.get(6).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(5));
Assertions.assertEquals(0, resultMap.get(7).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(6));
Assertions.assertEquals(1, resultMap.get(8).getFlag90days()); // Assertions.assertEquals(0, resultMap.get(7));
Assertions.assertEquals(1, resultMap.get(9).getFlag90days()); // Assertions.assertEquals(1, resultMap.get(8));
// Assertions.assertEquals(1, resultMap.get(9));
} }