Compare commits

..

3 commits

15 changed files with 385 additions and 7 deletions

View file

@ -4,6 +4,7 @@ import jakarta.xml.bind.JAXBException;
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.entities.external_response.monitoring_report_file.SgnlReportMonitorigSetupError;
import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport;
import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringError; import ru.nbch.credit_tracker.entities.user_response.errors.MonitoringError;
import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse; import ru.nbch.credit_tracker.entities.user_response.success.MonitoringSetupResponse;
@ -24,6 +25,7 @@ public class XmlConfig {
return new XmlProcessorImplAnyClasses(Charset.forName(settings.getEncoding()), return new XmlProcessorImplAnyClasses(Charset.forName(settings.getEncoding()),
// unmarshalling classes // unmarshalling classes
SgnlOnlineReport.class, SgnlOnlineReport.class,
SgnlReportMonitorigSetupError.class,
// marshalling classes // marshalling classes
MonitoringError.class, MonitoringError.class,
MonitoringSetupResponse.class); MonitoringSetupResponse.class);
@ -36,6 +38,7 @@ public class XmlConfig {
staxReader.add(MonitoringRequestStaxReader::new); staxReader.add(MonitoringRequestStaxReader::new);
staxReader.add(OnlineDownloadReportPersonsStaxReader::new); staxReader.add(OnlineDownloadReportPersonsStaxReader::new);
staxReader.add(MonitoringSignalResponseStaxXmlReader::new); staxReader.add(MonitoringSignalResponseStaxXmlReader::new);
staxReader.add(MonitoringReportErrorsStaxtReader::new);
return new XmlProcessorStaxImpl(staxReader); return new XmlProcessorStaxImpl(staxReader);
} }
} }

View file

@ -18,4 +18,5 @@ public class PhoneFidMap {
private Integer flagDebt5000; private Integer flagDebt5000;
private Integer flag90days; private Integer flag90days;
private LocalDateTime calculatedAt; private LocalDateTime calculatedAt;
private String errorText;
} }

View file

@ -0,0 +1,72 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_error;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"id",
"version",
"user",
"reportCreated"
})
@XmlRootElement(name = "Errors")
public class MonitoringReportErrors {
@XmlElement(name = "Id")
protected String id;
@XmlElement(name = "Version")
protected String version;
@XmlElement(name = "User")
protected String user;
@XmlElement(name = "ReportCreated")
protected String reportCreated;
@XmlElement(name = "p")
protected List<P> persons;
public List<P> getPersons() {
if (persons == null) {
persons = new ArrayList<>();
}
return this.persons;
}
private P currentPerson;
public void createCurrentPerson() {
currentPerson = new P();
}
public P getCurrentPerson() {
return currentPerson;
}
public void finalizePerson() {
getPersons().add(currentPerson);
}
@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
})
public static class P {
@XmlAttribute(name = "uid")
protected Integer uid;
@XmlValue
protected String value;
}
}

View file

@ -0,0 +1,21 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"filename"
})
public class ErrorsForNextReport {
@XmlElement(name = "filename", required = true)
protected String filename;
}

View file

@ -0,0 +1,24 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"memberCode",
"packCode"
})
public class InputParams {
@XmlElement(name = "memberCode", required = true)
protected String memberCode;
@XmlElement(name = "packCode", required = true)
protected String packCode;
}

View file

@ -0,0 +1,20 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"errorsForNextReport"
})
public class OperationReport {
@XmlElement(name = "ErrorsForNextReport")
protected ErrorsForNextReport errorsForNextReport;
}

View file

@ -0,0 +1,22 @@
package ru.nbch.credit_tracker.entities.external_response.monitoring_report_file;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"inputParams",
"operationReport"
})
@XmlRootElement(name = "SgnlReport")
public class SgnlReportMonitorigSetupError {
@XmlElement(name = "InputParams", required = true)
protected InputParams inputParams;
@XmlElement(name = "OperationReport", required = true)
protected OperationReport operationReport;
}

View file

@ -1,6 +1,7 @@
package ru.nbch.credit_tracker.facade; package ru.nbch.credit_tracker.facade;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.FileUrlResource; import org.springframework.core.io.FileUrlResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@ -225,6 +226,7 @@ public class SignalFacade {
if (signalRestService.setupMonitoring(packageId)) { if (signalRestService.setupMonitoring(packageId)) {
log.info("Package was successfully registered in signal service. PackageId: {} PackageName: {}", packageId, packageName); log.info("Package was successfully registered in signal service. PackageId: {} PackageName: {}", packageId, packageName);
signalService.updatePackageStatus(packageId, Status.ON_MONITORING); signalService.updatePackageStatus(packageId, Status.ON_MONITORING);
findErrors(packageId);
} else { } else {
log.info("Package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName); log.info("Package registration was rejected by signal service. PackageId: {} PackageName: {}", packageId, packageName);
signalService.updatePackageStatus(packageId, Status.ERROR); signalService.updatePackageStatus(packageId, Status.ERROR);
@ -237,6 +239,27 @@ public class SignalFacade {
}); });
} }
private void findErrors(Integer packageId) {
UserPackage userPackage = signalService.findPackage(packageId);
if (userPackage != null) {
String packCode = userPackage.getUserId().substring(0, 6) + "_" + userPackage.getPackageName();
log.info("Проверка на ошибки при постановке на мониторинг. packCode={}, packageId={}", packCode, packageId);
String fileName = signalRestService.getErrorFileName(packageId, packCode);
if (StringUtils.isNotBlank(fileName)) {
String filePath = signalRestService.loadErrorFile(packageId, fileName);
if (StringUtils.isNotBlank(filePath)) {
try {
signalService.updateSubjectsErrors(filePath, packageId);
CTUtil.removeFile(filePath);
} catch (Exception e) {
log.error("Ошибка при записи сообщений об ошибках в сформированных субъектах для мониторинга. Файл ошибок не будет удален. filePath = {}, Package_id = {}",
fileName, packageId, e);
}
}
}
}
}
private boolean isZipFile(MultipartFile file) { private boolean isZipFile(MultipartFile file) {
return file.getContentType() != null && return file.getContentType() != null &&
(file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) || (file.getContentType().equals("application/zip") || file.getContentType().equals("application/x-zip-compressed")) ||

View file

@ -16,6 +16,8 @@ public interface PhoneFidMapMapper {
void updatePhoneFidMaps(@Param("subjects") List<PhoneFidMap> subjects); void updatePhoneFidMaps(@Param("subjects") List<PhoneFidMap> subjects);
void updatePhoneFidMapsErrors(@Param("subjects") List<PhoneFidMap> subjects);
PhoneFidMap findPhoneFidMapById(@Param("id") Integer packageId); PhoneFidMap findPhoneFidMapById(@Param("id") Integer packageId);
boolean hasNonNullFids(@Param("packageId") Integer packageId); boolean hasNonNullFids(@Param("packageId") Integer packageId);

View file

@ -12,6 +12,7 @@ import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.entities.external_request.signals.Auth; import ru.nbch.credit_tracker.entities.external_request.signals.Auth;
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.external_request.signals.Signals; import ru.nbch.credit_tracker.entities.external_request.signals.Signals;
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_error.MonitoringReportErrors;
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.enums.Status; import ru.nbch.credit_tracker.enums.Status;
import ru.nbch.credit_tracker.service.indic.FlagsService; import ru.nbch.credit_tracker.service.indic.FlagsService;
@ -174,7 +175,7 @@ public class SignalService {
subjectToUpdate.add(subject); subjectToUpdate.add(subject);
}); });
int updateBatchSize = batchSize / 8; // 8 параметров на одну запись для обновления. Максимальное количество параметров ~65000 int updateBatchSize = batchSize / 9; // 9 параметров на одну запись для обновления. Максимальное количество параметров ~65000
for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) { for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) {
int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size()); int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size());
phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex)); phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex));
@ -202,6 +203,7 @@ public class SignalService {
/** /**
* Формирует файл запроса в официальный сервис сигналов, выгружая паспортные данные пачками и сразу записывая их в файл * Формирует файл запроса в официальный сервис сигналов, выгружая паспортные данные пачками и сразу записывая их в файл
*
* @return Путь к файлу запроса к официальному сервису сигналов на постановку на мониторинг * @return Путь к файлу запроса к официальному сервису сигналов на постановку на мониторинг
*/ */
public String writeSignals(Integer packageId) { public String writeSignals(Integer packageId) {
@ -277,6 +279,33 @@ public class SignalService {
return persons; return persons;
} }
public void updateSubjectsErrors(String filePath, Integer packageId) {
log.info("Start updating subjects errors. PackageId: {}", packageId);
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(Path.of(filePath)), 8 * 1024 * 1024)) {
staxXmlProcessor.read(in, MonitoringReportErrors.class,
request -> {
if (!request.getPersons().isEmpty()) {
List<PhoneFidMap> subjects = request.getPersons().stream().map(p -> {
log.error("Ошибка при формировании субъекта. package_id = {}, id = {}. Описание: {}", packageId, p.getUid(), p.getValue());
return PhoneFidMap.builder()
.id(p.getUid())
.errorText(p.getValue())
.build();
}).toList();
phoneFidMapService.updatePhoneFidMapsErrors(subjects);
log.trace("Updated subject's batch. Total count: {}. PackageId: {}", request.getPersons().size(), packageId);
request.getPersons().clear();
}
},
request -> request.getPersons().isEmpty()
,
batchSize, "/Errors/p");
} catch (IOException e) {
throw new RuntimeException("Error while parsing MonitoringReportErrors", e);
}
log.info("Subject's errors were updated. PackageId: {}", packageId);
}
public List<UserPackage> findActivePackages(String userId) { public List<UserPackage> findActivePackages(String userId) {
return userPackageService.findUserPackages(userId, Status.ON_MONITORING, Status.PROCESSING); return userPackageService.findUserPackages(userId, Status.ON_MONITORING, Status.PROCESSING);
} }
@ -317,6 +346,10 @@ public class SignalService {
return phoneFidMapService.hasNonNullfids(packageId); return phoneFidMapService.hasNonNullfids(packageId);
} }
public UserPackage findPackage(Integer packageId) {
return userPackageService.findPackage(packageId);
}
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public static class UpdateResult { public static class UpdateResult {

View file

@ -28,6 +28,10 @@ public class PhoneFidMapService {
mapper.updatePhoneFidMaps(subjects); mapper.updatePhoneFidMaps(subjects);
} }
public void updatePhoneFidMapsErrors(List<PhoneFidMap> subjects) {
mapper.updatePhoneFidMapsErrors(subjects);
}
public PhoneFidMap findPhoneFidMapById(Integer id) { public PhoneFidMap findPhoneFidMapById(Integer id) {
return mapper.findPhoneFidMapById(id); return mapper.findPhoneFidMapById(id);
} }

View file

@ -12,6 +12,7 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.external_response.errors.SgnlReport; import ru.nbch.credit_tracker.entities.external_response.errors.SgnlReport;
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_file.SgnlReportMonitorigSetupError;
import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.external_response.online_report.SgnlOnlineReport;
import ru.nbch.credit_tracker.service.SignalService; import ru.nbch.credit_tracker.service.SignalService;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
@ -34,7 +35,9 @@ public class SignalRestService {
private static String UPDATE_URI = "update"; private static String UPDATE_URI = "update";
private static String DELETE_URI = "delete"; private static String DELETE_URI = "delete";
private static String GET_REPORTS_URI = "onlinereport"; private static String GET_REPORTS_URI = "onlinereport";
private static String DOWNLOAD_REPORT_URI = "onlinedownload"; private static String GET_REPORT_URI = "report";
private static String DOWNLOAD_REPORT_URI = "download";
private static String DOWNLOAD_ONLINE_REPORT_URI = "onlinedownload";
private final RestTemplate restTemplate; private final RestTemplate restTemplate;
private final IXmlProcessor xmlProcessor; private final IXmlProcessor xmlProcessor;
@ -98,6 +101,70 @@ public class SignalRestService {
return false; return false;
} }
/**
* @return имя файла с ошибками по поставленному на мониторинг отчету
*/
public String getErrorFileName(Integer packageId, String packCode) {
String url = GET_REPORT_URI + "?packCode=" + packCode;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
String.class
);
String answer = response.getBody();
SgnlReport error = staxProcessor.read(answer, SgnlReport.class);
if (error.getError().getDescription() != null) {
log.error("Ошибка при получении имени файла ошибки из сервиса НБКИ. packCode={}. Описание: {}", packCode, error.getError().getDescription());
return null;
}
try {
SgnlReportMonitorigSetupError report = xmlProcessor.read(answer, SgnlReportMonitorigSetupError.class);
if (report.getOperationReport().getErrorsForNextReport() != null) {
String fileName = report.getOperationReport().getErrorsForNextReport().getFilename();
log.error("Найдены ошибки по пакету. packCode={}, packageId={}, fileName = {}", packCode, packageId, fileName);
return fileName;
} else {
log.info("Пакет был поставлен на мониторинг без ошибок. packCode={}, packageId={}", packCode, packageId);
}
} catch (Exception e) {
log.error("Ошибка при получении имени файла ошибки из сервиса НБКИ. Код ошибки: {} packCode={}", response.getStatusCode().value(), packCode);
}
return null;
}
/**
* Загружает .gz отчет ошибок из официального сервиса сигналов, разархивирует в tmp_folder
*
* @return путь к разархивированному файлу. Пример: <loadDir>/tmp_folder/<package_id>/0001XX_MY_BATCH_223112.1.errors.xml.gz
*/
public String loadErrorFile(Integer packageId, String fileName) {
String url = DOWNLOAD_REPORT_URI + "?fNameRequest=" + fileName;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<byte[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
byte[].class
);
return unzipReport(response, packageId, fileName);
}
/** /**
* Удаляет пакет с мониторинга * Удаляет пакет с мониторинга
*/ */
@ -162,7 +229,7 @@ public class SignalRestService {
* @return путь к разархивированному файлу. Пример: <loadDir>/tmp_folder/<package_id>/0001XX_MY_BATCH_204.1.online.2025-07-08T20-00-46.xml.gz.xml * @return путь к разархивированному файлу. Пример: <loadDir>/tmp_folder/<package_id>/0001XX_MY_BATCH_204.1.online.2025-07-08T20-00-46.xml.gz.xml
*/ */
public String downloadReport(Integer packageId, String reportName) { public String downloadReport(Integer packageId, String reportName) {
String url = DOWNLOAD_REPORT_URI + "?fNameReport=" + reportName; String url = DOWNLOAD_ONLINE_REPORT_URI + "?fNameReport=" + reportName;
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken); headers.setBasicAuth(authToken);
@ -176,6 +243,10 @@ public class SignalRestService {
byte[].class byte[].class
); );
return unzipReport(response,packageId, reportName);
}
private String unzipReport(ResponseEntity<byte[]> response, Integer packageId, String reportName) {
boolean isGzipped = response.getHeaders().getContentType() != null boolean isGzipped = response.getHeaders().getContentType() != null
&& response.getHeaders().getContentType().toString().equals("application/x-gzip"); && response.getHeaders().getContentType().toString().equals("application/x-gzip");

View file

@ -0,0 +1,68 @@
package ru.nbch.credit_tracker.service.xml.stax;
import lombok.extern.slf4j.Slf4j;
import ru.nbch.credit_tracker.entities.external_response.monitoring_report_error.MonitoringReportErrors;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
@Slf4j
public class MonitoringReportErrorsStaxtReader extends BaseStaxReader<MonitoringReportErrors> {
@Override
public Class<MonitoringReportErrors> type() {
return MonitoringReportErrors.class;
}
@Override
protected MonitoringReportErrors createObject() {
return new MonitoringReportErrors();
}
@Override
protected boolean innerProcess(XMLStreamReader reader, MonitoringReportErrors obj) throws XMLStreamException {
String text = buffer.toString();
String currPath = getPath();
switch (currPath) {
case "/Errors/Id" ->
obj.setId(text);
case "/Errors/Version" ->
obj.setVersion(text);
case "/Errors/User" ->
obj.setUser(text);
case "/Errors/ReportCreated" ->
obj.setReportCreated(text);
case "/Errors/p" -> {
obj.getCurrentPerson().setValue(text);
obj.finalizePerson();
}
}
return false;
}
@Override
protected void innerProcessStartElement(XMLStreamReader reader, MonitoringReportErrors obj) throws XMLStreamException {
String currPath = getPath();
switch (currPath) {
case "/Errors/p" ->
obj.createCurrentPerson();
}
for (int i = 0; i < reader.getAttributeCount(); i++) {
String text = reader.getAttributeValue(i);
switch (reader.getAttributeLocalName(i)) {
case "uid" -> {
try {
int uid = Integer.parseInt(text);
obj.getCurrentPerson().setUid(uid);
} catch (NumberFormatException e) {
log.error("Couldn't parse uid: {}", text);
throw new RuntimeException(e);
}
}
}
}
}
}

View file

@ -20,6 +20,7 @@ CREATE TABLE signals_phone_fid_map (
flag_debt5000 SMALLINT, -- 1, если есть активная просрочка > 5000 руб., иначе 0 flag_debt5000 SMALLINT, -- 1, если есть активная просрочка > 5000 руб., иначе 0
flag_90_12 SMALLINT, -- 1, если по субъекту когда-либо была просрочка 90+ дней за последний год, иначе 0 flag_90_12 SMALLINT, -- 1, если по субъекту когда-либо была просрочка 90+ дней за последний год, иначе 0
calculated_at TIMESTAMP, -- дата последнего расчёта флагов calculated_at TIMESTAMP, -- дата последнего расчёта флагов
error_text TEXT,
CONSTRAINT fk_signals_user_packages CONSTRAINT fk_signals_user_packages
FOREIGN KEY (package_id) FOREIGN KEY (package_id)
REFERENCES signals_user_packages(id) REFERENCES signals_user_packages(id)

View file

@ -14,6 +14,7 @@
<result property="flagDebt5000" column="flag_debt5000"/> <result property="flagDebt5000" column="flag_debt5000"/>
<result property="flag90days" column="flag_90_12"/> <result property="flag90days" column="flag_90_12"/>
<result property="calculatedAt" column="calculated_at"/> <result property="calculatedAt" column="calculated_at"/>
<result property="errorText" column="error_text"/>
</resultMap> </resultMap>
<insert id="registerSubjects" parameterType="java.util.List"> <insert id="registerSubjects" parameterType="java.util.List">
@ -35,7 +36,17 @@
fid = #{subject.fid}, fid = #{subject.fid},
flag_debt5000 = #{subject.flagDebt5000}, flag_debt5000 = #{subject.flagDebt5000},
flag_90_12 = #{subject.flag90days}, flag_90_12 = #{subject.flag90days},
calculated_at = #{subject.calculatedAt} calculated_at = #{subject.calculatedAt},
error_text = #{subject.errorText}
WHERE id = #{subject.id}
</foreach>
</update>
<update id="updatePhoneFidMapsErrors" parameterType="java.util.List">
<foreach collection="subjects" item="subject" separator=";">
UPDATE signals_phone_fid_map
SET
error_text = #{subject.errorText}
WHERE id = #{subject.id} WHERE id = #{subject.id}
</foreach> </foreach>
</update> </update>
@ -48,7 +59,8 @@
fid, fid,
flag_90_12, flag_90_12,
flag_debt5000, flag_debt5000,
calculated_at calculated_at,
error_text
FROM signals_phone_fid_map FROM signals_phone_fid_map
WHERE package_id = #{packageId} WHERE package_id = #{packageId}
ORDER BY id ORDER BY id
@ -63,7 +75,8 @@
fid, fid,
flag_90_12, flag_90_12,
flag_debt5000, flag_debt5000,
calculated_at calculated_at,
error_text
FROM signals_phone_fid_map FROM signals_phone_fid_map
WHERE id = #{id} WHERE id = #{id}
LIMIT 1 LIMIT 1