- изменена БД: добавлены новые поля, флаги вынесены в отдельную таблицу.

This commit is contained in:
etreschenkov 2025-11-18 15:38:44 +03:00
parent 4cfdd75dd9
commit 89f6d58f98
17 changed files with 241 additions and 215 deletions

View file

@ -0,0 +1,20 @@
package ru.nbch.credit_tracker.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public ObjectMapper entityToJsonMapper() {
return new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
}

View file

@ -5,12 +5,9 @@ import java.util.function.Supplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
import ru.nbch.credit_tracker.model.impl.PartFilePayload;
import ru.nbch.credit_tracker.model.impl.SignalXmlFilePayload;
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
import ru.nbch.credit_tracker.service.indic.FlagsService2;
import ru.nbch.credit_tracker.service.task.impl.FlagsEnricher;
import ru.nbch.credit_tracker.service.task.impl.KickPipeLineImpl;
import ru.nbch.credit_tracker.service.task.impl.XmlMergeCoordinator;
import ru.nbch.credit_tracker.service.task.setup.IPipeLineStarter;
@ -28,9 +25,4 @@ public class PipelineStarterConfig {
public Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory(CreditTrackerSettings creditTrackerSettings) {
return () -> new XmlMergeCoordinator(creditTrackerSettings);
}
@Bean
public Supplier<FlagsEnricher> flagEnricherFactory(FlagsService2 flagsService, PhoneFidMapMapper mapper) {
return () -> new FlagsEnricher(flagsService, mapper);
}
}

View file

@ -0,0 +1,21 @@
package ru.nbch.credit_tracker.entities.app;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class FlagDetail {
private Long id;
private Long mapId;
private Long packageId;
private String subjectId;
private String phone;
private Integer fid;
private Integer flagDebt5000;
private Integer flag90days;
private LocalDateTime calculatedAt;
}

View file

@ -8,7 +8,7 @@ import ru.nbch.credit_tracker.entities.indic.PaymentsFlag;
import ru.nbch.credit_tracker.service.indic.FlagsService;
@Mapper
public interface FlagsMapper {
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);

View file

@ -0,0 +1,9 @@
package ru.nbch.credit_tracker.mapper.signal;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface FlagDetailMapper {
void registerCalcFlags(@Param("json") String json);
}

View file

@ -13,7 +13,7 @@ public interface PhoneFidMapMapper {
void registerSubjects(@Param("subjects") List<Subject> subjects, @Param("packageId") Long packageId);
void register(@Param("phoneFidMap") List<PhoneFidMap> phoneFidMap);
void registerJson(@Param("json") String json);
List<Long> registerJson(@Param("json") String json);
void registerWithId(@Param("phoneFidMap") List<PhoneFidMap> phoneFidMap);
List<PhoneFidMap> findFullPhoneFidMap(@Param("packageId") Long packageId, @Param("offset") int offset, @Param("limit") int limit);

View file

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

View file

@ -12,7 +12,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
import ru.nbch.credit_tracker.mapper.indic.IndicFlagsMapper;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -24,7 +24,7 @@ import ru.nbch.credit_tracker.model.SubjectProfile;
public class FlagsService {
private static final Logger log = LoggerFactory.getLogger(FlagsService.class);
private final FlagsMapper mapper;
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 " +
@ -42,7 +42,7 @@ public class FlagsService {
private final NamedParameterJdbcTemplate jdbcTemplate;
public FlagsService(FlagsMapper mapper,
public FlagsService(IndicFlagsMapper mapper,
@Qualifier("jdbcTemplateIndic") NamedParameterJdbcTemplate jdbcTemplate) {
this.mapper = mapper;
this.jdbcTemplate = jdbcTemplate;

View file

@ -1,21 +1,32 @@
package ru.nbch.credit_tracker.service.indic;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.app.FlagDetail;
import ru.nbch.credit_tracker.entities.indic.PaymentsFlag;
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
import ru.nbch.credit_tracker.mapper.indic.IndicFlagsMapper;
import ru.nbch.credit_tracker.mapper.signal.FlagDetailMapper;
@Slf4j
@Service
public class FlagsService2 {
private final FlagsMapper flagsMapper;
private final IndicFlagsMapper flagsMapper;
private final FlagDetailMapper flagDetailMapper;
private final ObjectMapper entityToJsonMapper;
public FlagsService2(FlagsMapper flagsMapper) {
public FlagsService2(IndicFlagsMapper flagsMapper,
FlagDetailMapper flagDetailMapper,
ObjectMapper entityToJsonMapper) {
this.flagsMapper = flagsMapper;
this.flagDetailMapper = flagDetailMapper;
this.entityToJsonMapper = entityToJsonMapper;
}
public Map<Integer, Integer> findFlagsDebt5000(List<Integer> fids) {
@ -33,5 +44,25 @@ public class FlagsService2 {
.collect(Collectors.toMap(PaymentsFlag::getFid, PaymentsFlag::getFlag));
}
public void registerCalculationFlags(List<FlagDetail> flagDetails) {
try {
//fixme, временное решение
String jsonFlagDetail = entityToJsonMapper.writeValueAsString(flagDetails.stream()
.map(flagDetail -> new HashMap<String, Object>() {{
put("subject_id", flagDetail.getSubjectId());
put("fid", flagDetail.getFid());
put("phone", flagDetail.getPhone());
put("map_id", flagDetail.getMapId());
put("package_id", flagDetail.getPackageId());
put("flag_debt5000", flagDetail.getFlagDebt5000());
put("flag_90_12", flagDetail.getFlag90days());
put("calculated_at", flagDetail.getCalculatedAt());
}}).toList());
flagDetailMapper.registerCalcFlags(jsonFlagDetail);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -1,6 +1,9 @@
package ru.nbch.credit_tracker.service.indic;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BinaryOperator;
@ -8,7 +11,9 @@ 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.PhoneFidMap;
import ru.nbch.credit_tracker.entities.indic.Name;
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.repository.PhoneRepository;
import ru.nbch.credit_tracker.utils.CTUtil;
@ -18,16 +23,23 @@ import ru.nbch.credit_tracker.utils.CTUtil;
public class PhoneService2 {
private final PhoneRepository phoneRepository;
private final PhoneFidMapMapper phoneFidMapMapper;
private final ObjectMapper entityToJsonMapper;
private final Comparator<Name> byDateThenIdNullSafe =
Comparator.comparing(Name::getFileSinceDate, Comparator.nullsFirst(Comparator.naturalOrder()))
.thenComparing(Name::getFid);
public PhoneService2(PhoneRepository phoneRepository) {
public PhoneService2(PhoneRepository phoneRepository,
PhoneFidMapMapper phoneFidMapMapper,
ObjectMapper entityToJsonMapper) {
this.phoneRepository = phoneRepository;
this.phoneFidMapMapper = phoneFidMapMapper;
this.entityToJsonMapper = entityToJsonMapper;
}
/**
* Поиск данных по таблицам PHONE_NORM и NAME по списку номеров телефонов
*
* @param subjects
* @return - отображение NAME к номеру телефону, отфильтрованному по логике
* FID с максимальным значением FILE_SINCE_DT. Если FILE_SINCE_DT оказался одинаковый, берется максимальный FID
@ -46,4 +58,21 @@ public class PhoneService2 {
BinaryOperator.maxBy(byDateThenIdNullSafe)
));
}
public List<Long> registerSubjects(List<PhoneFidMap> subjects) {
try {
//fixme, временное решение
String json = entityToJsonMapper.writeValueAsString(subjects.stream()
.map(phoneFidMap -> new HashMap<String, Object>() {{
put("subject_id", phoneFidMap.getSubjectId());
put("fid", phoneFidMap.getFid());
put("phone", phoneFidMap.getPhone());
put("package_id", phoneFidMap.getPackageId());
put("calculated_at", phoneFidMap.getCalculatedAt());
}}).toList());
return phoneFidMapMapper.registerJson(json);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -1,139 +0,0 @@
package ru.nbch.credit_tracker.service.task.impl;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
import ru.nbch.credit_tracker.service.indic.FlagsService2;
@Slf4j
public class FlagsEnricher implements Runnable {
private final FlagsService2 flagsService;
private final PhoneFidMapMapper phoneFidMapMapper;
private BlockingQueue<SubjectPayload> in;
private final CompletableFuture<Void> done = new CompletableFuture<>();
private final ExecutorService ioPool;
private final ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
public FlagsEnricher(FlagsService2 flagsService,
PhoneFidMapMapper phoneFidMapMapper) {
this.flagsService = flagsService;
this.phoneFidMapMapper = phoneFidMapMapper;
this.ioPool = new ThreadPoolExecutor(10,
10,
0L, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(),
r -> {
Thread t = new Thread(r);
t.setName("queue-handler-%s-%d".formatted(this.getClass().getSimpleName(), t.threadId()));
return t;
}
);
}
@Override
public void run() {
List<Future<?>> inFlight = new ArrayList<>();
while (!Thread.currentThread().isInterrupted()) {
try {
SubjectPayload subjectPayload = in.poll(5, TimeUnit.SECONDS);
if (subjectPayload == null) {
continue;
}
if (subjectPayload.isPoison()) {
log.debug("Got poison");
for (Future<?> f : inFlight) {
f.get();
}
done.complete(null);
return;
}
inFlight.add(ioPool.submit(() -> process(subjectPayload)));
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("Error: {}", ExceptionUtils.getStackTrace(e));
}
}
}
public void process(SubjectPayload subjectPayload) {
List<SubjectProfile> subjects = subjectPayload.getSubjects();
log.debug("FlagsEnricher handle by packageId: {}, size: {}", subjectPayload.getPackageId(), subjects.size());
List<Integer> fids = subjects.stream()
.map(SubjectProfile::getFid)
.filter(Objects::nonNull)
.toList();
LocalDate yearAgo = LocalDate.now().minusYears(1);
Map<Integer, Integer> flagsDebt5000 = flagsService.findFlagsDebt5000(fids);
Map<Integer, Integer> flag90ByPastDueArrear = flagsService.findFlag90ByPastDueArrear(fids, yearAgo);
Map<Integer, Integer> flag90ByRuPaymt = flagsService.findFlag90ByRuPaymt(fids, yearAgo);
String json;
try {
json = mapper.writeValueAsString(subjects.stream().map(subject -> {
Integer debt5000 = null;
Integer flagDays90 = null;
LocalDateTime calculatedAt = null;
if (subject.getFid() != null) {
debt5000 = flagsDebt5000.getOrDefault(subject.getFid(), 0);
int pastDue90 = flag90ByPastDueArrear.getOrDefault(subject.getFid(), 0);
int paymt90 = flag90ByRuPaymt.getOrDefault(subject.getFid(), 0);
flagDays90 = Math.max(pastDue90, paymt90);
calculatedAt = LocalDateTime.now();
}
Integer finalDebt500 = debt5000;
Integer finalFlagDays9 = flagDays90;
LocalDateTime finalCalculatedAt = calculatedAt;
return new HashMap<String, Object>() {{
put("subject_id", subject.getIdentifier());
put("fid", subject.getFid());
put("phone", subject.getPhone());
put("package_id", subjectPayload.getPackageId());
put("flag_debt5000", finalDebt500);
put("flag_90_12", finalFlagDays9);
put("calculated_at", finalCalculatedAt);
}};
}).toList());
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
phoneFidMapMapper.registerJson(json);
}
public void setPollingQueue(BlockingQueue<SubjectPayload> queue) {
this.in = queue;
}
public CompletableFuture<Void> doneFuture() {
return done;
}
}

View file

@ -1,9 +1,11 @@
package ru.nbch.credit_tracker.service.task.impl;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -12,12 +14,9 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.app.FlagDetail;
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
import ru.nbch.credit_tracker.model.SubjectProfile;
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
@ -28,7 +27,6 @@ import ru.nbch.credit_tracker.service.indic.FlagsService2;
public class FlagsEnricherV2 implements Consumer<SubjectPayload> {
private final FlagsService2 flagsService;
private final PhoneFidMapMapper phoneFidMapMapper;
private final ExecutorService ioPool;
private final ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
@ -38,7 +36,6 @@ public class FlagsEnricherV2 implements Consumer<SubjectPayload> {
public FlagsEnricherV2(FlagsService2 flagsService,
PhoneFidMapMapper phoneFidMapMapper) {
this.flagsService = flagsService;
this.phoneFidMapMapper = phoneFidMapMapper;
this.ioPool = new ThreadPoolExecutor(10,
10,
0L, TimeUnit.MINUTES,
@ -66,9 +63,7 @@ public class FlagsEnricherV2 implements Consumer<SubjectPayload> {
Map<Integer, Integer> flag90ByPastDueArrear = flagsService.findFlag90ByPastDueArrear(fids, yearAgo);
Map<Integer, Integer> flag90ByRuPaymt = flagsService.findFlag90ByRuPaymt(fids, yearAgo);
String json;
try {
json = mapper.writeValueAsString(subjects.stream().map(subject -> {
List<FlagDetail> flagDetails = subjects.stream().map(subject -> {
Integer debt5000 = null;
Integer flagDays90 = null;
LocalDateTime calculatedAt = null;
@ -84,28 +79,25 @@ public class FlagsEnricherV2 implements Consumer<SubjectPayload> {
Integer finalDebt500 = debt5000;
Integer finalFlagDays9 = flagDays90;
LocalDateTime finalCalculatedAt = calculatedAt;
return new HashMap<String, Object>() {{
put("subject_id", subject.getIdentifier());
put("fid", subject.getFid());
put("phone", subject.getPhone());
put("package_id", subjectPayload.getPackageId());
put("flag_debt5000", finalDebt500);
put("flag_90_12", finalFlagDays9);
put("calculated_at", finalCalculatedAt);
}};
}).toList());
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
phoneFidMapMapper.registerJson(json);
return FlagDetail.builder()
.mapId(subject.getMapId())
.subjectId(subject.getIdentifier())
.packageId(subjectPayload.getPackageId())
.fid(subject.getFid())
.phone(subject.getPhone())
.flagDebt5000(finalDebt500)
.flag90days(finalFlagDays9)
.calculatedAt(finalCalculatedAt)
.build();
}).toList();
flagsService.registerCalculationFlags(flagDetails);
}
@Override
public void accept(SubjectPayload subjectPayload) {
ThreadPoolExecutor casted = (ThreadPoolExecutor) ioPool;
log.info("submitting payload. active tasks number: {}; queue size: {}", casted.getActiveCount(), casted.getQueue().size());
this.ioPool.submit(() -> {
process(subjectPayload);
});
this.ioPool.submit(() -> process(subjectPayload));
}
}

View file

@ -1,9 +1,11 @@
package ru.nbch.credit_tracker.service.task.impl;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.app.PhoneFidMap;
import ru.nbch.credit_tracker.entities.indic.Name;
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
import ru.nbch.credit_tracker.model.NameData;
@ -36,9 +38,9 @@ public class SaveSubjectHandler implements Handler<SubjectPayload, SubjectPayloa
Long packageId = taskPayload.getPackageId();
log.debug("SaveSubjectStage handle by packageId: {}, size of bucket for save: {}", taskPayload.getPackageId(), subjects.size());
LocalDateTime now = LocalDateTime.now();
Map<String, Name> nameByPhone = phoneService2.findNameByNumber(subjects);
//todo сделать один проход для установки FID для вставки в PHONE_FID_MAP и одновременного заполнения инфо из Name для дальнейшей обработки
subjects.forEach(subject -> {
List<PhoneFidMap> subjectForSave = subjects.stream().map(subject -> {
Name name = nameByPhone.get(CTUtil.normalizePhoneNumber(subject.getPhone()));
if (name != null) {
NameData nameData = NameData.builder()
@ -52,8 +54,20 @@ public class SaveSubjectHandler implements Handler<SubjectPayload, SubjectPayloa
subject.setFid(name.getFid());
subject.setNameData(nameData);
}
});
//todo стоит ли делать имутабл для subject?
return PhoneFidMap.builder()
.subjectId(subject.getIdentifier())
.packageId(packageId)
.phone(subject.getPhone())
.fid(subject.getFid())
.calculatedAt(now)
.build();
}).toList();
List<Long> ids = phoneService2.registerSubjects(subjectForSave);
for (int i = 0; i < subjects.size(); i++) {
subjects.get(i).setMapId(ids.get(i));
}
return new SubjectPayload(taskPayload.getPackageId(), subjects);
}
}

View file

@ -3,7 +3,7 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ru.nbch.credit_tracker.mapper.indic.FlagsMapper">
<mapper namespace="ru.nbch.credit_tracker.mapper.indic.IndicFlagsMapper">
<resultMap id="RuPastDuarearResultMap" type="ru.nbch.credit_tracker.service.indic.FlagsService$RuPastDuarearData">
<result property="fid" column="fid" />

View file

@ -0,0 +1,21 @@
<?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.FlagDetailMapper">
<insert id="registerCalcFlags" parameterType="string">
INSERT INTO signals_flags
(map_id, subject_id, fid, phone, flag_debt5000, flag_90_12, calculated_at)
SELECT map_id, subject_id, fid, phone, flag_debt5000, flag_90_12, calculated_at
FROM json_to_recordset(#{json}::json) AS t(
map_id bigint,
subject_id varchar(255),
fid int,
phone text,
flag_debt5000 smallint,
flag_90_12 smallint,
calculated_at timestamp)
</insert>
</mapper>

View file

@ -33,10 +33,31 @@
</foreach>
</insert>
<insert id="registerJson" parameterType="string">
INSERT INTO signals_phone_fid_map
(subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at)
SELECT subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at
<!-- <insert id="registerJson" parameterType="string">-->
<!-- INSERT INTO signals_phone_fid_map-->
<!-- (subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at)-->
<!-- SELECT subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at-->
<!-- FROM json_to_recordset(#{json}::json) AS t(-->
<!-- subject_id varchar(255),-->
<!-- fid int,-->
<!-- phone text,-->
<!-- package_id bigint,-->
<!-- flag_debt5000 smallint,-->
<!-- flag_90_12 smallint,-->
<!-- calculated_at timestamp)-->
<!-- </insert>-->
<select id="registerJson" parameterType="string" resultType="long">
WITH src AS (
SELECT
row_number() OVER () AS rn,
subject_id,
fid,
phone,
package_id,
flag_debt5000,
flag_90_12,
calculated_at
FROM json_to_recordset(#{json}::json) AS t(
subject_id varchar(255),
fid int,
@ -44,8 +65,23 @@
package_id bigint,
flag_debt5000 smallint,
flag_90_12 smallint,
calculated_at timestamp)
</insert>
calculated_at timestamp
)
)
INSERT INTO signals_phone_fid_map
(subject_id, fid, phone, package_id, flag_debt5000, flag_90_12, calculated_at)
SELECT
subject_id,
fid,
phone,
package_id,
flag_debt5000,
flag_90_12,
calculated_at
FROM src
ORDER BY rn
RETURNING id;
</select>
<insert id="registerWithId" parameterType="java.util.List" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO signals_phone_fid_map (subject_id, phone, package_id)

View file

@ -6,7 +6,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import ru.nbch.credit_tracker.mapper.indic.FlagsMapper;
import ru.nbch.credit_tracker.mapper.indic.IndicFlagsMapper;
import ru.nbch.credit_tracker.service.indic.FlagsService;
import java.math.BigDecimal;
@ -26,7 +26,7 @@ public class FlagsServiceTest {
private static final LocalDate INITIAL_DATE = LocalDate.parse("2025-09-25");
@Mock
FlagsMapper flagsMapper;
IndicFlagsMapper flagsMapper;
@Test
public void testfindFlags() {