Added flags fetching by jdbc template
This commit is contained in:
parent
e70f07b04b
commit
4f55c0df42
2 changed files with 262 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
@ -47,5 +48,10 @@ public class IndicDataSourceConfig extends DatabaseConfig {
|
||||||
sqlSessionFactoryBean.setTypeHandlersPackage("ru.nbch.credit_tracker.config.datasource.handlers");
|
sqlSessionFactoryBean.setTypeHandlersPackage("ru.nbch.credit_tracker.config.datasource.handlers");
|
||||||
return sqlSessionFactoryBean.getObject();
|
return sqlSessionFactoryBean.getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean(name = "jdbcTemplateIndic")
|
||||||
|
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(@Qualifier("indicDataSource") DataSource dataSource) {
|
||||||
|
return new NamedParameterJdbcTemplate(dataSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,256 @@
|
||||||
|
package ru.nbch.credit_tracker.service.indic;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
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 java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class FlagsService2 {
|
||||||
|
|
||||||
|
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 FlagsService2(@Qualifier("jdbcTemplateIndic") NamedParameterJdbcTemplate jdbcTemplate) {
|
||||||
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, FlagsService.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, FlagsService.FlagsData> result = new HashMap<>();
|
||||||
|
fids.forEach(fid -> {
|
||||||
|
Integer flagDebt5000 = flags5000.get(fid);
|
||||||
|
if (flagDebt5000 == null) {
|
||||||
|
flagDebt5000 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer flag90days = flags90DaysByPastDueArrear.get(fid);
|
||||||
|
if (flag90days == null || flag90days == 0) {
|
||||||
|
flag90days = flags90DaysByRuPaymt.get(fid);
|
||||||
|
if (flag90days == null) {
|
||||||
|
flag90days = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.put(fid, new FlagsService.FlagsData(flagDebt5000, flag90days));
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выбирает данные из RU_PASTDUEARREAR и ищет по ним флаги просрочек
|
||||||
|
* По FID из RU_PASTDUEARREAR выбираются все уникальные ACC_SERIAL_NUM с максимальной датой REPORTED_DT.
|
||||||
|
* Если по хотя бы одной такой записи AMT_PAST_DUE > 5000, то flag500 устанавливается в 1.
|
||||||
|
* Если ни по одному счёту условие не выполняется или счетов вообще не найдено, флаг = 0.
|
||||||
|
* <p>
|
||||||
|
* flag90Days = 1, если выполняется хотя бы одно из условий:
|
||||||
|
* В INDIC.RU_PASTDUEARREAR у данного FID есть запись с DAYS_PAST_DUE ≥ 90 и REPORTED_DT >= текущая дата – 12 месяцев.
|
||||||
|
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
||||||
|
*
|
||||||
|
* @param fids - отсортирован по возрастанию фидов
|
||||||
|
* @param flag5000Map - рещультирующая мапа флагов просрочек debt5000
|
||||||
|
* @param flag90Days - рещультирующая мапа флагов просрочек 90_days
|
||||||
|
*/
|
||||||
|
private void findFlagsRuPastDueArrear(List<Integer> fids, Map<Integer, Integer> flag5000Map, Map<Integer, Integer> flag90Days) {
|
||||||
|
log.debug("Start calculating flag 5000 and 90 days by RU_PASTDUEARREAR 2");
|
||||||
|
MapSqlParameterSource params = new MapSqlParameterSource();
|
||||||
|
params.addValue("fids", fids);
|
||||||
|
|
||||||
|
jdbcTemplate.query(SELECT_RU_PASDUEARREAR_DATA, params, (ResultSet rs) -> {
|
||||||
|
Integer currentFid = null;
|
||||||
|
BigInteger prevAccSerialNum = null;
|
||||||
|
boolean processed5000ForCurrentId = false;
|
||||||
|
boolean processed90DaysForCurrentId = false;
|
||||||
|
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
||||||
|
|
||||||
|
while (rs.next()) {
|
||||||
|
Integer fid = rs.getInt("FID");
|
||||||
|
|
||||||
|
// Переход к новому fid. Сброс состояния
|
||||||
|
if (!fid.equals(currentFid)) {
|
||||||
|
currentFid = fid;
|
||||||
|
prevAccSerialNum = null;
|
||||||
|
processed5000ForCurrentId = false;
|
||||||
|
processed90DaysForCurrentId = false;
|
||||||
|
|
||||||
|
// Инициализируем значения по умолчанию
|
||||||
|
flag5000Map.putIfAbsent(fid, 0);
|
||||||
|
flag90Days.putIfAbsent(fid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если для текущего FID уже обработали оба флага, пропускаем остальные записи
|
||||||
|
if (processed5000ForCurrentId && processed90DaysForCurrentId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработка флага 5000
|
||||||
|
if (!processed5000ForCurrentId && flag5000Map.get(fid) == 0) {
|
||||||
|
BigInteger currentAccSerialNum = getBigInteger(rs, "ACC_SERIAL_NUM");
|
||||||
|
BigDecimal amtPastDue = getBigDecimal(rs, "AMT_PAST_DUE");
|
||||||
|
|
||||||
|
if (prevAccSerialNum == null || !prevAccSerialNum.equals(currentAccSerialNum)) {
|
||||||
|
if (amtPastDue != null && amtPastDue.compareTo(BigDecimal.valueOf(5000)) >= 0) {
|
||||||
|
flag5000Map.put(fid, 1);
|
||||||
|
processed5000ForCurrentId = true;
|
||||||
|
}
|
||||||
|
prevAccSerialNum = currentAccSerialNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработка флага 90 дней
|
||||||
|
if (!processed90DaysForCurrentId) {
|
||||||
|
Integer currentFlag90 = flag90Days.get(fid);
|
||||||
|
|
||||||
|
if (currentFlag90 != null && currentFlag90 == 1) {
|
||||||
|
processed90DaysForCurrentId = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentFlag90 == null || currentFlag90 == 0) {
|
||||||
|
BigInteger days = getBigInteger(rs, "DAYS_PAST_DUE");
|
||||||
|
LocalDate reportedDate = rs.getObject("REPORTED_DT", LocalDate.class);
|
||||||
|
|
||||||
|
if (days != null) {
|
||||||
|
boolean has90daysFlag = days.compareTo(BigInteger.valueOf(90)) >= 0
|
||||||
|
&& reportedDate != null && !reportedDate.isBefore(yearAgo);
|
||||||
|
|
||||||
|
if (has90daysFlag) {
|
||||||
|
flag90Days.put(fid, 1);
|
||||||
|
processed90DaysForCurrentId = true;
|
||||||
|
} else {
|
||||||
|
flag90Days.put(fid, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flag90Days.put(fid, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
log.debug("Complete calculating flag 5000 and 90 days by RU_PASTDUEARREAR 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выбирает данные из RU_PAYMT и ищет по ним флаги просрочек 90Days
|
||||||
|
* <p>
|
||||||
|
* flag90Days = 1, если выполняется хотя бы одно из условий:
|
||||||
|
* В INDIC.RU_PAYMT у данного FID есть запись с DAYS_PAST_DUE ≥ 90 и REPORTED_DT >= текущая дата – 12 месяцев.
|
||||||
|
* Если ни по одной записи условия не выполняются или записей вообще не найдено, флаг = 0.
|
||||||
|
*
|
||||||
|
* @param fids - отсортирован по возрастанию фидов
|
||||||
|
* @param flag90Days - рещультирующая мапа флагов просрочек 90_days
|
||||||
|
*/
|
||||||
|
private void findFlagsRuPaymt(List<Integer> fids, Map<Integer, Integer> flag90Days) {
|
||||||
|
log.debug("Start calculating flag 90 days by RU_PAPAYMT 2");
|
||||||
|
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
||||||
|
MapSqlParameterSource params = new MapSqlParameterSource();
|
||||||
|
params.addValue("fids", fids);
|
||||||
|
params.addValue("reportedDate", yearAgo);
|
||||||
|
jdbcTemplate.query(SELECT_RU_PAYMT_DATA, params, rs -> {
|
||||||
|
Integer currentFid = null;
|
||||||
|
boolean processed90DaysForCurrentId = false;
|
||||||
|
|
||||||
|
while (rs.next()) {
|
||||||
|
Integer fid = rs.getInt("FID");
|
||||||
|
|
||||||
|
// Переход к новому fid. Сброс состояния
|
||||||
|
if (!fid.equals(currentFid)) {
|
||||||
|
currentFid = fid;
|
||||||
|
processed90DaysForCurrentId = false;
|
||||||
|
|
||||||
|
// Инициализируем значения по умолчанию
|
||||||
|
flag90Days.putIfAbsent(fid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработка флага 90 дней
|
||||||
|
if (!processed90DaysForCurrentId) {
|
||||||
|
Integer currentFlag90 = flag90Days.get(fid);
|
||||||
|
|
||||||
|
if (currentFlag90 != null && currentFlag90 == 1) {
|
||||||
|
processed90DaysForCurrentId = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentFlag90 == null || currentFlag90 == 0) {
|
||||||
|
BigInteger days = getBigInteger(rs, "DAYS_PAST_DUE");
|
||||||
|
LocalDate date = rs.getObject("REPORTED_DT", LocalDate.class);
|
||||||
|
|
||||||
|
if (days != null) {
|
||||||
|
boolean has90daysFlag = days.compareTo(BigInteger.valueOf(90)) >= 0
|
||||||
|
&& date != null && !date.isBefore(yearAgo);
|
||||||
|
|
||||||
|
if (has90daysFlag) {
|
||||||
|
flag90Days.put(fid, 1);
|
||||||
|
processed90DaysForCurrentId = true;
|
||||||
|
} else {
|
||||||
|
flag90Days.put(fid, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flag90Days.put(fid, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
log.debug("Complete calculating flag 90 days by RU_PAPAYMT 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private BigInteger getBigInteger(ResultSet rs, String columnName) {
|
||||||
|
try {
|
||||||
|
String value = rs.getString(columnName);
|
||||||
|
return value != null ? new BigInteger(value) : null;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal getBigDecimal(ResultSet rs, String columnName) {
|
||||||
|
try {
|
||||||
|
return rs.getBigDecimal(columnName);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue