http://jira.mfd.msk:8088/browse/CLS-608 Money/DepoBalanceRegisterReport
This commit is contained in:
parent
0f65c05f08
commit
fd2ba48189
23 changed files with 1121 additions and 23 deletions
|
|
@ -37,6 +37,10 @@
|
|||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-sftp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
|
@ -51,6 +55,13 @@
|
|||
<artifactId>test-clearing</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- CSV -->
|
||||
<dependency>
|
||||
<groupId>com.opencsv</groupId>
|
||||
<artifactId>opencsv</artifactId>
|
||||
<version>5.5.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package ru.spcex.clearing.registry.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Configuration
|
||||
public class RegistryServiceConfig {
|
||||
@Bean("reportOutDir")
|
||||
public File outDir(RegistryServiceSettings settings) {
|
||||
File outFolder = new File(settings.getReportsStore().getLocalTempDir());
|
||||
if (!outFolder.exists()) {
|
||||
boolean mkDirOk = outFolder.mkdirs();
|
||||
if (!mkDirOk) throw new IllegalStateException("Can't create output directory for reports, registry-service was terminated");
|
||||
} else if (!outFolder.isDirectory()) {
|
||||
throw new IllegalStateException("Output reports path from settings is not directory!");
|
||||
}
|
||||
return outFolder;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package ru.spcex.clearing.registry.config;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.annotation.Gateway;
|
||||
import org.springframework.integration.annotation.MessagingGateway;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.dsl.IntegrationFlow;
|
||||
import org.springframework.integration.dsl.IntegrationFlows;
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.sftp.gateway.SftpOutboundGateway;
|
||||
import org.springframework.integration.sftp.outbound.SftpMessageHandler;
|
||||
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
|
||||
import org.springframework.integration.sftp.session.SftpFileInfo;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.Command.LS;
|
||||
|
||||
@Configuration
|
||||
public class SFTPReportsConfig {
|
||||
private final RegistryServiceSettings settings;
|
||||
|
||||
public SFTPReportsConfig(RegistryServiceSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Bean("reportsSftpSessionFactory")
|
||||
public SessionFactory<ChannelSftp.LsEntry> sftpSessionFactory() {
|
||||
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
|
||||
factory.setHost(settings.getReportsStore().getServerIp());
|
||||
factory.setPort(settings.getReportsStore().getServerPort());
|
||||
factory.setUser(settings.getReportsStore().getUser());
|
||||
factory.setPassword(settings.getReportsStore().getPassword());
|
||||
factory.setAllowUnknownKeys(true);
|
||||
return new CachingSessionFactory<>(factory);
|
||||
}
|
||||
|
||||
@Bean("reportsSftpHandler")
|
||||
@ServiceActivator(inputChannel = "reportsToSftpChannel")
|
||||
public MessageHandler handler(@Qualifier("reportsSftpSessionFactory") SessionFactory<ChannelSftp.LsEntry> sessionFactory) {
|
||||
SftpMessageHandler handler = new SftpMessageHandler(sessionFactory);
|
||||
handler.setRemoteDirectoryExpression(new LiteralExpression(settings.getReportsStore().getOutDir()));
|
||||
handler.setAutoCreateDirectory(true);
|
||||
handler.setFileNameGenerator(message -> {
|
||||
if (message.getPayload() instanceof File) {
|
||||
return ((File) message.getPayload()).getName();
|
||||
} else {
|
||||
throw new IllegalArgumentException("File must expected as payload.");
|
||||
}
|
||||
});
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean("reportsListSftpChannel")
|
||||
public MessageChannel listSftpChannel(@Qualifier("reportsSftpHandlerList") MessageHandler handler) {
|
||||
DirectChannel dc = new DirectChannel();
|
||||
dc.subscribe(handler);
|
||||
return dc;
|
||||
}
|
||||
|
||||
@Bean("reportsToSftpChannel")
|
||||
public MessageChannel toSftpChannel(@Qualifier("reportsSftpHandler") MessageHandler handler) {
|
||||
DirectChannel dc = new DirectChannel();
|
||||
dc.subscribe(handler);
|
||||
return dc;
|
||||
}
|
||||
|
||||
@Bean("reportsSftpHandlerList")
|
||||
@ServiceActivator(inputChannel = "reportsListSftpChannel")
|
||||
public MessageHandler handlerList(@Qualifier("reportsSftpSessionFactory") SessionFactory<ChannelSftp.LsEntry> sessionFactory) {
|
||||
String expression = "'/%s'".formatted(settings.getReportsStore().getOutDir());
|
||||
return new SftpOutboundGateway(sessionFactory, LS.getCommand(), expression);
|
||||
}
|
||||
|
||||
@Bean("reportsSftpOutboundListFlow")
|
||||
public IntegrationFlow sftpOutboundListFlow(@Qualifier("reportsSftpSessionFactory") SessionFactory<ChannelSftp.LsEntry> sessionFactory) {
|
||||
return IntegrationFlows.from("reportsListSftpChannel")
|
||||
.handle(new SftpOutboundGateway(sessionFactory, "ls", "payload"))
|
||||
.get();
|
||||
}
|
||||
|
||||
@MessagingGateway(name = "reportsSftpGateway")
|
||||
public interface ReportsGateway {
|
||||
@Gateway(requestChannel = "reportsToSftpChannel")
|
||||
void sendToSftp(File file);
|
||||
|
||||
@Gateway(requestChannel = "reportsListSftpChannel")
|
||||
List<SftpFileInfo> listFiles(String dir);
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ public class RegistryServiceSettings {
|
|||
private HazelcastClientParams hazelcast;
|
||||
private KafkaConsumerSettings kafkaConsumer;
|
||||
private KafkaProducerSettings kafkaProducer;
|
||||
private ReportsStore reportsStore;
|
||||
private boolean csvMode = false;
|
||||
|
||||
public HazelcastClientParams getHazelcast() {
|
||||
return hazelcast;
|
||||
|
|
@ -38,4 +40,20 @@ public class RegistryServiceSettings {
|
|||
public void setKafkaProducer(KafkaProducerSettings kafkaProducer) {
|
||||
this.kafkaProducer = kafkaProducer;
|
||||
}
|
||||
|
||||
public ReportsStore getReportsStore() {
|
||||
return reportsStore;
|
||||
}
|
||||
|
||||
public void setReportsStore(ReportsStore reportsStore) {
|
||||
this.reportsStore = reportsStore;
|
||||
}
|
||||
|
||||
public boolean isCsvMode() {
|
||||
return csvMode;
|
||||
}
|
||||
|
||||
public void setCsvMode(boolean csvMode) {
|
||||
this.csvMode = csvMode;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package ru.spcex.clearing.registry.config.settings;
|
||||
|
||||
public class ReportsStore {
|
||||
private String outDir;
|
||||
private String localTempDir;
|
||||
private String user;
|
||||
private String password;
|
||||
private String serverIp;
|
||||
private int serverPort;
|
||||
|
||||
public boolean isDeleteAfterSend() {
|
||||
return deleteAfterSend;
|
||||
}
|
||||
|
||||
public void setDeleteAfterSend(boolean deleteAfterSend) {
|
||||
this.deleteAfterSend = deleteAfterSend;
|
||||
}
|
||||
|
||||
private boolean deleteAfterSend;
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getServerIp() {
|
||||
return serverIp;
|
||||
}
|
||||
|
||||
public void setServerIp(String serverIp) {
|
||||
this.serverIp = serverIp;
|
||||
}
|
||||
|
||||
public int getServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
public void setServerPort(int serverPort) {
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public String getOutDir() {
|
||||
return outDir;
|
||||
}
|
||||
|
||||
public void setOutDir(String outDir) {
|
||||
this.outDir = outDir;
|
||||
}
|
||||
|
||||
public String getLocalTempDir() {
|
||||
return localTempDir;
|
||||
}
|
||||
|
||||
public void setLocalTempDir(String localTempDir) {
|
||||
this.localTempDir = localTempDir;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package ru.spcex.clearing.registry.reports;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.spcex.clearing.registry.config.SFTPReportsConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ReportUtils {
|
||||
private final static Logger log = LoggerFactory.getLogger(ReportUtils.class);
|
||||
|
||||
public static void sendFilesToSftp(Collection<File> files,
|
||||
SFTPReportsConfig.ReportsGateway reportsGateway,
|
||||
boolean deleteAfterSend) {
|
||||
for (File file : files) {
|
||||
reportsGateway.sendToSftp(file);
|
||||
if (deleteAfterSend) {
|
||||
boolean delete = file.delete();
|
||||
if (!delete) {
|
||||
log.warn("Can't delete temp file {}", file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package ru.spcex.clearing.registry.reports.bean;
|
||||
|
||||
public interface CSVReport {
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package ru.spcex.clearing.registry.reports.bean;
|
||||
|
||||
import com.opencsv.bean.CsvBindByName;
|
||||
import com.opencsv.bean.CsvBindByPosition;
|
||||
import com.opencsv.bean.CsvDate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
public class DepoBalanceRegisterReport implements CSVReport {
|
||||
@CsvBindByName(column = "Наименование Расчетного депозитария")
|
||||
@CsvBindByPosition(position = 0)
|
||||
private String houseName;
|
||||
|
||||
@CsvBindByName(column = "Номер отчета")
|
||||
@CsvBindByPosition(position = 1)
|
||||
private String number;
|
||||
|
||||
@CsvBindByName(column = "Дата")
|
||||
@CsvBindByPosition(position = 2)
|
||||
@CsvDate(value = "dd.MM.yyyy")
|
||||
private LocalDate date;
|
||||
|
||||
@CsvBindByName(column = "Время")
|
||||
@CsvBindByPosition(position = 3)
|
||||
@CsvDate(value = "HH:mm:ss")
|
||||
private LocalTime time;
|
||||
|
||||
@CsvBindByName(column = "Краткое наименование УК")
|
||||
@CsvBindByPosition(position = 4)
|
||||
private String company;
|
||||
|
||||
@CsvBindByName(column = "Номер торгового раздела счета депо/ код раздела «к размещению/выкупу»")
|
||||
@CsvBindByPosition(position = 5)
|
||||
private String account;
|
||||
|
||||
@CsvBindByName(column = "Код ЦБ")
|
||||
@CsvBindByPosition(position = 6)
|
||||
private String security;
|
||||
|
||||
@CsvBindByName(column = "Количество ЦБ")
|
||||
@CsvBindByPosition(position = 7)
|
||||
private BigDecimal sum;
|
||||
|
||||
public String getHouseName() {
|
||||
return houseName;
|
||||
}
|
||||
|
||||
public void setHouseName(String houseName) {
|
||||
this.houseName = houseName;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public LocalTime getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(LocalTime time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(String company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(String account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public String getSecurity() {
|
||||
return security;
|
||||
}
|
||||
|
||||
public void setSecurity(String security) {
|
||||
this.security = security;
|
||||
}
|
||||
|
||||
public BigDecimal getSum() {
|
||||
return sum;
|
||||
}
|
||||
|
||||
public void setSum(BigDecimal sum) {
|
||||
this.sum = sum;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package ru.spcex.clearing.registry.reports.bean;
|
||||
|
||||
import com.opencsv.bean.CsvBindByName;
|
||||
import com.opencsv.bean.CsvBindByPosition;
|
||||
import com.opencsv.bean.CsvDate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
public class MoneyBalanceRegisterReport implements CSVReport {
|
||||
@CsvBindByName(column = "Наименование Расчетного депозитария")
|
||||
@CsvBindByPosition(position = 0)
|
||||
private String houseName;
|
||||
|
||||
@CsvBindByName(column = "Номер отчета")
|
||||
@CsvBindByPosition(position = 1)
|
||||
private String number;
|
||||
|
||||
@CsvBindByName(column = "Дата")
|
||||
@CsvBindByPosition(position = 2)
|
||||
@CsvDate(value = "dd.MM.yyyy")
|
||||
private LocalDate date;
|
||||
|
||||
@CsvBindByName(column = "Время")
|
||||
@CsvBindByPosition(position = 3)
|
||||
@CsvDate(value = "HH:mm:ss")
|
||||
private LocalTime time;
|
||||
|
||||
@CsvBindByName(column = "Код валюты")
|
||||
@CsvBindByPosition(position = 4)
|
||||
private String currency;
|
||||
|
||||
@CsvBindByName(column = "Краткое наименование УК")
|
||||
@CsvBindByPosition(position = 5)
|
||||
private String company;
|
||||
|
||||
@CsvBindByName(column = "Номер торгового /клирингового счета/ счета внутреннего учета СПВБ")
|
||||
@CsvBindByPosition(position = 6)
|
||||
private String account;
|
||||
|
||||
@CsvBindByName(column = "Остаток денежных средств")
|
||||
@CsvBindByPosition(position = 7)
|
||||
private BigDecimal sum;
|
||||
|
||||
|
||||
public String getHouseName() {
|
||||
return houseName;
|
||||
}
|
||||
|
||||
public void setHouseName(String houseName) {
|
||||
this.houseName = houseName;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public LocalTime getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(LocalTime time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public void setCurrency(String currency) {
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public String getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(String company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(String account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public BigDecimal getSum() {
|
||||
return sum;
|
||||
}
|
||||
|
||||
public void setSum(BigDecimal sum) {
|
||||
this.sum = sum;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
package ru.spcex.clearing.registry.reports.builders;
|
||||
|
||||
import com.opencsv.CSVWriter;
|
||||
import com.opencsv.ICSVWriter;
|
||||
import com.opencsv.bean.*;
|
||||
import com.opencsv.exceptions.CsvBadConverterException;
|
||||
import com.opencsv.exceptions.CsvChainedException;
|
||||
import com.opencsv.exceptions.CsvFieldAssignmentException;
|
||||
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.clearing.classes.objects.BusinessObject;
|
||||
import ru.spcex.clearing.registry.reports.bean.CSVReport;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Класс для построения отчетов в формате CSV
|
||||
*/
|
||||
public abstract class CSVReportBuilder<R extends CSVReport, I extends BusinessObject> {
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
protected static DateTimeFormatter dateTimeFormatter_YYMMDDHHmmssSSS = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
|
||||
|
||||
/**
|
||||
* Имя отчета (для имени файла)
|
||||
*/
|
||||
protected abstract String reportName();
|
||||
|
||||
/**
|
||||
* Преобразовать объект в строку отчета
|
||||
*/
|
||||
protected abstract R toRow(I input);
|
||||
|
||||
/**
|
||||
* Название отчета, используется для формирования имени отчета (без указания формата)
|
||||
*/
|
||||
protected String getReportFilename() {
|
||||
return "%s_%s".formatted(reportName(), dateTimeFormatter_YYMMDDHHmmssSSS.format(LocalDateTime.now()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Формирование отчета на основе объектов
|
||||
*/
|
||||
public File buildReport(Collection<I> inputObj, File outFolder) {
|
||||
assert outFolder != null && outFolder.isDirectory() && inputObj != null;
|
||||
List<R> rows = new ArrayList<>(inputObj.size());
|
||||
for (I input : inputObj) rows.add(toRow(input));
|
||||
|
||||
File reportFile = new File(outFolder, normalizeFilenameForOS(getReportFilename() + ".csv"));
|
||||
|
||||
try (Writer writer = new FileWriter(reportFile);
|
||||
ICSVWriter icsvWriter = new CustomCSVWriter(writer)) {
|
||||
CustomStrategy<R> customStrategy = new CustomStrategy<>();
|
||||
customStrategy.setType(getReportClass());
|
||||
StatefulBeanToCsv<R> sbc = new StatefulBeanToCsvBuilder<R>(icsvWriter)
|
||||
.withMappingStrategy(customStrategy)
|
||||
.withLineEnd("\n")
|
||||
.withSeparator(',')
|
||||
.withQuotechar('\"')
|
||||
.build();
|
||||
if (!rows.isEmpty()) sbc.write(rows);
|
||||
else {
|
||||
// Для записи заголовков в пустой файл
|
||||
Constructor<? extends R> constructor = Objects.requireNonNull(getReportClass()).getDeclaredConstructor();
|
||||
R obj = constructor.newInstance();
|
||||
String[] headers = customStrategy.generateHeader(obj);
|
||||
writer.write("\"" + String.join("\",\"", headers) + "\"");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Can't create report", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return reportFile;
|
||||
}
|
||||
|
||||
protected abstract Class<R> getReportClass();
|
||||
|
||||
protected String normalizeFilenameForOS(String filename) {
|
||||
if (System.getProperty("os.name").toLowerCase().contains("windows"))
|
||||
return filename.replace(":", "_");
|
||||
return filename;
|
||||
}
|
||||
|
||||
static class CustomCSVWriter extends CSVWriter {
|
||||
public CustomCSVWriter(Writer writer) {
|
||||
super(writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeNext(String[] nextLine, boolean applyQuotesToAll, Appendable appendable) throws IOException {
|
||||
if (nextLine != null) {
|
||||
for (int i = 0; i < nextLine.length; i++) {
|
||||
if (StringUtils.isEmpty(nextLine[i])) {
|
||||
nextLine[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.writeNext(nextLine, applyQuotesToAll, appendable);
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomStrategy<T> extends ColumnPositionMappingStrategy<T> {
|
||||
public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
|
||||
super.generateHeader(bean);
|
||||
String[] headers = new String[this.getFieldMap().values().size()];
|
||||
for (BeanField<T, Integer> field : this.getFieldMap().values()) {
|
||||
CsvBindByPosition positionAnnotation = field.getField().getAnnotation(CsvBindByPosition.class);
|
||||
CsvBindByName nameAnnotation = field.getField().getAnnotation(CsvBindByName.class);
|
||||
headers[positionAnnotation.position()] = nameAnnotation.column();
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] transmuteBean(T bean) throws CsvFieldAssignmentException, CsvChainedException {
|
||||
return super.transmuteBean(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CsvConverter determineConverter(Field field, Class<?> elementType, String locale, String writeLocale, Class<? extends AbstractCsvConverter> customConverter) throws CsvBadConverterException {
|
||||
CsvConverter csvConverter = super.determineConverter(field, elementType, locale, writeLocale, customConverter);
|
||||
if (csvConverter instanceof ConverterNumber && field.getType() == BigDecimal.class) {
|
||||
CsvNumber csvNumberAnnotation = field.getAnnotation(CsvNumber.class);
|
||||
String formatValue = csvNumberAnnotation.value();
|
||||
String writeFormat = csvNumberAnnotation.writeFormat();
|
||||
csvConverter = new ConverterNumber(BigDecimal.class,
|
||||
Locale.getDefault().toString(),
|
||||
Locale.getDefault().toString(),
|
||||
Locale.getDefault(),
|
||||
formatValue,
|
||||
writeFormat);
|
||||
}
|
||||
return csvConverter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package ru.spcex.clearing.registry.reports.builders;
|
||||
|
||||
import ru.clearing.classes.statics.data.company.Company;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.registry.reports.bean.DepoBalanceRegisterReport;
|
||||
import ru.spcex.platform.enumeration.AccountType;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class DepoBalanceRegisterReportBuilder extends CSVReportBuilder<DepoBalanceRegisterReport, Registry> {
|
||||
private final static DateTimeFormatter yyyyMMddFormat = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private final Imdg<Company> companyImdg;
|
||||
|
||||
public DepoBalanceRegisterReportBuilder(ImdgProvider imdgProvider) {
|
||||
companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String reportName() {
|
||||
return "depo_balance_register";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<DepoBalanceRegisterReport> getReportClass() {
|
||||
return DepoBalanceRegisterReport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DepoBalanceRegisterReport toRow(Registry input) {
|
||||
LocalDate now = LocalDate.now();
|
||||
LocalTime nowTime = LocalTime.now();
|
||||
DepoBalanceRegisterReport entity = new DepoBalanceRegisterReport();
|
||||
|
||||
Company company = companyImdg.getSingleObjectByID(2L);
|
||||
if (company != null) entity.setHouseName(company.getShortName());
|
||||
|
||||
entity.setNumber(yyyyMMddFormat.format(now));
|
||||
entity.setDate(now);
|
||||
entity.setTime(nowTime);
|
||||
|
||||
company = companyImdg.getSingleObjectByID(input.getCompanyId());
|
||||
if (company != null) entity.setCompany(company.getShortName());
|
||||
|
||||
AccountType accountType = IEnumKey.getEnumByKey(AccountType.class, input.getAccountType());
|
||||
if (accountType == AccountType.Clrn || accountType == AccountType.Info) entity.setAccount(input.getAccount());
|
||||
|
||||
entity.setSecurity(input.getSecuritySymbol());
|
||||
entity.setSum(input.getBalance());
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package ru.spcex.clearing.registry.reports.builders;
|
||||
|
||||
import ru.clearing.classes.statics.data.company.Company;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.registry.reports.bean.MoneyBalanceRegisterReport;
|
||||
import ru.spcex.platform.enumeration.AccountType;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class MoneyBalanceRegisterReportBuilder extends CSVReportBuilder<MoneyBalanceRegisterReport, Registry> {
|
||||
private final static DateTimeFormatter yyyyMMddFormat = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private final Imdg<Company> companyImdg;
|
||||
|
||||
public MoneyBalanceRegisterReportBuilder(ImdgProvider imdgProvider) {
|
||||
companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String reportName() {
|
||||
return "money_balance_register";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<MoneyBalanceRegisterReport> getReportClass() {
|
||||
return MoneyBalanceRegisterReport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MoneyBalanceRegisterReport toRow(Registry input) {
|
||||
LocalDate now = LocalDate.now();
|
||||
LocalTime nowTime = LocalTime.now();
|
||||
MoneyBalanceRegisterReport entity = new MoneyBalanceRegisterReport();
|
||||
|
||||
Company company = companyImdg.getSingleObjectByID(2L);
|
||||
if (company != null) entity.setHouseName(company.getShortName());
|
||||
|
||||
entity.setNumber(yyyyMMddFormat.format(now));
|
||||
entity.setDate(now);
|
||||
entity.setTime(nowTime);
|
||||
entity.setCurrency("RUR");
|
||||
|
||||
company = companyImdg.getSingleObjectByID(input.getCompanyId());
|
||||
if (company != null) entity.setCompany(company.getShortName());
|
||||
|
||||
AccountType accountType = IEnumKey.getEnumByKey(AccountType.class, input.getAccountType());
|
||||
if (accountType == AccountType.Clrn || accountType == AccountType.Info) entity.setAccount(input.getAccount());
|
||||
|
||||
entity.setSum(input.getBalance());
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.register.DepoBalanceRegister;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
|
|
@ -14,6 +15,10 @@ import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
|||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||
import ru.spcex.clearing.registry.config.SFTPReportsConfig;
|
||||
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||
import ru.spcex.clearing.registry.reports.ReportUtils;
|
||||
import ru.spcex.clearing.registry.reports.builders.DepoBalanceRegisterReportBuilder;
|
||||
import ru.spcex.clearing.registry.util.PreClearMap;
|
||||
import ru.spcex.platform.enumeration.AccountType;
|
||||
import ru.spcex.platform.enumeration.RegistryTradingParams;
|
||||
|
|
@ -24,10 +29,13 @@ import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
|
|||
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
|
||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static ru.spcex.platform.enumeration.Task.createRegistry_GRRT;
|
||||
|
||||
|
|
@ -39,14 +47,29 @@ public class DepoBalanceRegisterService extends QueueConsumer implements Initial
|
|||
private final Imdg<RegistryHistory> registryHistoryMap;
|
||||
private final PreClearMap<DepoBalanceRegister> preClearMap;
|
||||
|
||||
private final DepoBalanceRegisterReportBuilder reportBuilder;
|
||||
private final File outFolder;
|
||||
private final RegistryServiceSettings settings;
|
||||
|
||||
private final SFTPReportsConfig.ReportsGateway reportsSftpGateway;
|
||||
private final boolean deleteAfterSend;
|
||||
|
||||
@Autowired
|
||||
public DepoBalanceRegisterService(Consumer<String, Object> kafkaQueue,
|
||||
Producer<String, Object> kafkaProducer,
|
||||
ImdgProvider imdgProvider) {
|
||||
ImdgProvider imdgProvider,
|
||||
RegistryServiceSettings settings,
|
||||
@Qualifier("reportOutDir") File outFolder,
|
||||
SFTPReportsConfig.ReportsGateway reportsSftpGateway) {
|
||||
super(kafkaQueue, kafkaProducer);
|
||||
this.depoBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoBalanceRegister, DepoBalanceRegister.class);
|
||||
this.registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||
preClearMap = PreClearMap.instanceForInstantField(depoBalanceRegisterMap, "created");
|
||||
reportBuilder = new DepoBalanceRegisterReportBuilder(imdgProvider);
|
||||
this.outFolder = outFolder;
|
||||
this.settings = settings;
|
||||
this.reportsSftpGateway = reportsSftpGateway;
|
||||
this.deleteAfterSend = settings.getReportsStore().isDeleteAfterSend();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -58,6 +81,7 @@ public class DepoBalanceRegisterService extends QueueConsumer implements Initial
|
|||
}
|
||||
|
||||
public void depoBalanceRegisterNew(BaseRequest<LauncherCommandRequest> userRequest) {
|
||||
boolean csvMode = settings.isCsvMode();
|
||||
log.debug("LauncherCommandRequest received from {}", createRegistry_GRRT.topic());
|
||||
ImdgPredicate predicate = getPredicateForRegistries(userRequest.getRequestPayload().getCompanyId());
|
||||
Collection<RegistryHistory> registryHistories = registryHistoryMap.getCollectionObjectsByPredicate(predicate);
|
||||
|
|
@ -67,10 +91,16 @@ public class DepoBalanceRegisterService extends QueueConsumer implements Initial
|
|||
return;
|
||||
}
|
||||
log.debug("Select {} Registry history by query {}", registryHistories.size(), predicate);
|
||||
preClearMap.preClearMap();
|
||||
if (!csvMode) preClearMap.preClearMap();
|
||||
List<Registry> registryForReport = new ArrayList<>();
|
||||
for (RegistryHistory registryHistory : registryHistories) {
|
||||
if (BigDecimal.ZERO.compareTo(registryHistory.getObject().getDiffBalance()) != 0) continue;
|
||||
insertDepoBalanceRegister(registryHistory);
|
||||
if (!csvMode) insertDepoBalanceRegister(registryHistory);
|
||||
else registryForReport.add(registryHistory.getObject());
|
||||
}
|
||||
if (csvMode) {
|
||||
File reportFile = reportBuilder.buildReport(registryForReport, outFolder);
|
||||
ReportUtils.sendFilesToSftp(List.of(reportFile), reportsSftpGateway, deleteAfterSend);
|
||||
}
|
||||
log.debug("Successfully processed");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.company.Company;
|
||||
import ru.clearing.classes.statics.data.register.MoneyBalanceRegister;
|
||||
|
|
@ -15,6 +16,10 @@ import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
|||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||
import ru.spcex.clearing.registry.config.SFTPReportsConfig;
|
||||
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||
import ru.spcex.clearing.registry.reports.ReportUtils;
|
||||
import ru.spcex.clearing.registry.reports.builders.MoneyBalanceRegisterReportBuilder;
|
||||
import ru.spcex.clearing.registry.util.PreClearMap;
|
||||
import ru.spcex.platform.enumeration.AccountType;
|
||||
import ru.spcex.platform.enumeration.RegistryTradingParams;
|
||||
|
|
@ -25,10 +30,13 @@ import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
|
|||
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
|
||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static ru.spcex.platform.enumeration.Task.createRegistry_GBRR;
|
||||
|
|
@ -42,15 +50,31 @@ public class MoneyBalanceRegisterService extends QueueConsumer implements Initia
|
|||
private final Imdg<Company> companyMap;
|
||||
private final PreClearMap<MoneyBalanceRegister> preClearMap;
|
||||
|
||||
private final MoneyBalanceRegisterReportBuilder reportBuilder;
|
||||
private final File outFolder;
|
||||
RegistryServiceSettings settings;
|
||||
|
||||
private final SFTPReportsConfig.ReportsGateway reportsSftpGateway;
|
||||
private final boolean deleteAfterSend;
|
||||
|
||||
|
||||
@Autowired
|
||||
public MoneyBalanceRegisterService(Consumer<String, Object> kafkaQueue,
|
||||
Producer<String, Object> kafkaProducer,
|
||||
ImdgProvider imdgProvider) {
|
||||
ImdgProvider imdgProvider,
|
||||
RegistryServiceSettings settings,
|
||||
@Qualifier("reportOutDir") File outFolder,
|
||||
SFTPReportsConfig.ReportsGateway reportsSftpGateway) {
|
||||
super(kafkaQueue, kafkaProducer);
|
||||
this.moneyBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyBalanceRegister, MoneyBalanceRegister.class);
|
||||
this.registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||
this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
||||
preClearMap = PreClearMap.instanceForInstantField(moneyBalanceRegisterMap, "created");
|
||||
reportBuilder = new MoneyBalanceRegisterReportBuilder(imdgProvider);
|
||||
this.outFolder = outFolder;
|
||||
this.settings = settings;
|
||||
this.reportsSftpGateway = reportsSftpGateway;
|
||||
this.deleteAfterSend = settings.getReportsStore().isDeleteAfterSend();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -62,6 +86,7 @@ public class MoneyBalanceRegisterService extends QueueConsumer implements Initia
|
|||
}
|
||||
|
||||
public void moneyBalanceRegisterNew(BaseRequest<LauncherCommandRequest> userRequest) {
|
||||
boolean csvMode = settings.isCsvMode();
|
||||
log.debug("LauncherCommandRequest received from {}", createRegistry_GBRR.topic());
|
||||
ImdgPredicate predicate = getSqlForRegistryHistory(userRequest.getRequestPayload().getCompanyId());
|
||||
Collection<RegistryHistory> registryHistories = registryHistoryMap.getCollectionObjectsByPredicate(predicate);
|
||||
|
|
@ -70,10 +95,16 @@ public class MoneyBalanceRegisterService extends QueueConsumer implements Initia
|
|||
return;
|
||||
}
|
||||
log.debug("Select {} Registry history by query {}", registryHistories.size(), predicate);
|
||||
preClearMap.preClearMap();
|
||||
if (!csvMode) preClearMap.preClearMap();
|
||||
List<Registry> registryForReport = new ArrayList<>();
|
||||
for (RegistryHistory registryHistory : registryHistories) {
|
||||
if (BigDecimal.ZERO.compareTo(registryHistory.getObject().getDiffBalance()) != 0) continue;
|
||||
insertMoneyBalanceRegister(registryHistory);
|
||||
if (!csvMode) insertMoneyBalanceRegister(registryHistory);
|
||||
else registryForReport.add(registryHistory.getObject());
|
||||
}
|
||||
if (csvMode) {
|
||||
File reportFile = reportBuilder.buildReport(registryForReport, outFolder);
|
||||
ReportUtils.sendFilesToSftp(List.of(reportFile), reportsSftpGateway, deleteAfterSend);
|
||||
}
|
||||
log.debug("successfully processed");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,3 +18,12 @@ registry-service.kafka-producer.retries=0
|
|||
registry-service.kafka-producer.batch-size=16384
|
||||
registry-service.kafka-producer.linger-ms=1
|
||||
registry-service.kafka-producer.buffer-memory=33554432
|
||||
|
||||
registry-service.csv-mode=true
|
||||
registry-service.reports-store.local-temp-dir=./reports_out_temp
|
||||
registry-service.reports-store.out-dir=reports
|
||||
registry-service.reports-store.user=tester
|
||||
registry-service.reports-store.password=password
|
||||
registry-service.reports-store.server-ip=10.230.238.53
|
||||
registry-service.reports-store.server-port=2222
|
||||
registry-service.reports-store.delete-after-send=true
|
||||
|
|
@ -21,6 +21,8 @@ import ru.spcex.platform.imdg.api.Imdg;
|
|||
import ru.spcex.platform.imdg.api.ImdgId;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static ru.spcex.clearing.registry.utils.TestUtils.setFuture;
|
||||
import static ru.spcex.clearing.test.config.KafkaTestConfig.producerCaptors;
|
||||
|
|
@ -58,4 +60,9 @@ public class KafkaConfigTest {
|
|||
return mockProducer;
|
||||
}
|
||||
|
||||
@Bean("outDir")
|
||||
public File outDir() {
|
||||
return new File("out");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package ru.spcex.clearing.registry.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.sftp.session.SftpFileInfo;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class SFTPTestConfig {
|
||||
@Bean
|
||||
public SFTPReportsConfig.ReportsGateway reportsGateway(){
|
||||
return new ReportsGateway();
|
||||
}
|
||||
|
||||
public static class ReportsGateway implements SFTPReportsConfig.ReportsGateway {
|
||||
|
||||
@Override
|
||||
public void sendToSftp(File file) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SftpFileInfo> listFiles(String dir) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package ru.spcex.clearing.registry.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||
import ru.spcex.clearing.registry.config.settings.ReportsStore;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Configuration
|
||||
public class TestConfig {
|
||||
@Bean
|
||||
public RegistryServiceSettings testSettings() {
|
||||
RegistryServiceSettings registryServiceSettings = new RegistryServiceSettings();
|
||||
ReportsStore store = new ReportsStore();
|
||||
store.setLocalTempDir("out");
|
||||
registryServiceSettings.setReportsStore(store);
|
||||
registryServiceSettings.setCsvMode(true);
|
||||
return registryServiceSettings;
|
||||
}
|
||||
|
||||
@Bean("reportOutDir")
|
||||
public File reportOutDir() {
|
||||
File outDir = new File("out");
|
||||
outDir.mkdirs();
|
||||
return outDir;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package ru.spcex.clearing.registry.service;
|
||||
|
||||
import com.opencsv.exceptions.CsvValidationException;
|
||||
import org.apache.kafka.clients.consumer.MockConsumer;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
|
|
@ -7,6 +8,7 @@ import org.junit.jupiter.api.Order;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
|
@ -16,7 +18,10 @@ import ru.clearing.classes.statics.data.registry.Registry;
|
|||
import ru.clearing.classes.statics.data.registry.RegistryHistory;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
||||
import ru.spcex.clearing.registry.config.SFTPTestConfig;
|
||||
import ru.spcex.clearing.registry.config.TestConfig;
|
||||
import ru.spcex.clearing.registry.config.ValidationConfig;
|
||||
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||
import ru.spcex.clearing.test.TestUtils;
|
||||
import ru.spcex.clearing.test.config.ImdgTestConfig;
|
||||
import ru.spcex.clearing.test.config.KafkaTestConfig;
|
||||
|
|
@ -24,9 +29,11 @@ import ru.spcex.platform.enumeration.*;
|
|||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
|
@ -38,9 +45,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
DepoBalanceRegisterService.class,
|
||||
ImdgTestConfig.class,
|
||||
KafkaTestConfig.class,
|
||||
TestConfig.class,
|
||||
SFTPTestConfig.class,
|
||||
})
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
class DepoBalanceRegisterServiceTest {
|
||||
class DepoBalanceRegisterServiceTest implements InitializingBean {
|
||||
private static int requestCount = 0;
|
||||
|
||||
private static final Long companyId = 1L;
|
||||
|
|
@ -63,15 +72,25 @@ class DepoBalanceRegisterServiceTest {
|
|||
@Qualifier("mockProducer")
|
||||
private Producer<String, Object> producer;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
@Autowired
|
||||
private RegistryServiceSettings settings;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("reportOutDir")
|
||||
private File outFolder;
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId();
|
||||
|
||||
//initializing of imdg
|
||||
registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||
depoBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoBalanceRegister, DepoBalanceRegister.class);
|
||||
// initialing objects for imdg repos
|
||||
}
|
||||
|
||||
private RegistryHistory init() {
|
||||
Registry registry = new Registry();
|
||||
registry.setRegistryDesignation(RegistryDesignation.A.getKey());
|
||||
registry.setRegistryInstrumentType(RegistryInstrumentType.S.getKey());
|
||||
|
|
@ -87,11 +106,15 @@ class DepoBalanceRegisterServiceTest {
|
|||
registryHistory.setObject(registry);
|
||||
registryHistory.setEventTime(Instant.now());
|
||||
registryHistoryMap.insert(registryHistory);
|
||||
return registryHistory;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void executionRegisterNewForEventTime() {
|
||||
|
||||
RegistryHistory source = init();
|
||||
boolean oldCsvMode = settings.isCsvMode();
|
||||
settings.setCsvMode(false);
|
||||
//making launcherCommand
|
||||
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
||||
|
||||
|
|
@ -112,5 +135,37 @@ class DepoBalanceRegisterServiceTest {
|
|||
assertEquals(account, depoBalanceRegister.getDepoCode());
|
||||
assertEquals(balance, depoBalanceRegister.getQuantity());
|
||||
assertEquals(SECURITY_SYMBOL, depoBalanceRegister.getSecuritySymbol());
|
||||
settings.setCsvMode(oldCsvMode);
|
||||
registryHistoryMap.delete(source);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
void executionRegisterNewForEventTime_Csv() throws CsvValidationException, IOException {
|
||||
RegistryHistory source = init();
|
||||
ReportTestUtils.resetDir(outFolder);
|
||||
boolean oldCsvMode = settings.isCsvMode();
|
||||
settings.setCsvMode(true);
|
||||
//making launcherCommand
|
||||
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
||||
|
||||
String jsonString = TestUtils.getJsonStringForSystem(launcherCommandRequest, 0L);
|
||||
|
||||
TestUtils.addRecordToKafka((MockConsumer) depoBalanceRegisterService.getConsumer(),
|
||||
Task.createRegistry_GRRT.topic(),
|
||||
requestCount++,
|
||||
0,
|
||||
jsonString);
|
||||
|
||||
TestUtils.waitingSendAndCheckRecord(0L, producer);
|
||||
|
||||
File outFile = outFolder.listFiles()[0];
|
||||
File expectedFile = new File(getClass().getClassLoader().getResource("expected_reports/depo_balance_register_expected.csv").getFile());
|
||||
ReportTestUtils.compareCSVFiles(expectedFile, outFile, Arrays.asList("Дата", "Время", "Номер отчета"));
|
||||
|
||||
settings.setCsvMode(oldCsvMode);
|
||||
ReportTestUtils.deleteDir(outFolder);
|
||||
registryHistoryMap.delete(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package ru.spcex.clearing.registry.service;
|
||||
|
||||
import com.opencsv.exceptions.CsvValidationException;
|
||||
import org.apache.kafka.clients.consumer.MockConsumer;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
|
|
@ -7,6 +8,7 @@ import org.junit.jupiter.api.Order;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
|
@ -17,7 +19,10 @@ import ru.clearing.classes.statics.data.registry.Registry;
|
|||
import ru.clearing.classes.statics.data.registry.RegistryHistory;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
||||
import ru.spcex.clearing.registry.config.SFTPTestConfig;
|
||||
import ru.spcex.clearing.registry.config.TestConfig;
|
||||
import ru.spcex.clearing.registry.config.ValidationConfig;
|
||||
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||
import ru.spcex.clearing.test.TestUtils;
|
||||
import ru.spcex.clearing.test.config.ImdgTestConfig;
|
||||
import ru.spcex.clearing.test.config.KafkaTestConfig;
|
||||
|
|
@ -25,10 +30,12 @@ import ru.spcex.platform.enumeration.*;
|
|||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
|
@ -39,9 +46,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
MoneyBalanceRegisterService.class,
|
||||
ImdgTestConfig.class,
|
||||
KafkaTestConfig.class,
|
||||
TestConfig.class,
|
||||
SFTPTestConfig.class,
|
||||
})
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
class MoneyBalanceRegisterServiceTest {
|
||||
class MoneyBalanceRegisterServiceTest implements InitializingBean {
|
||||
private static final String REGISTRY_DESIGNATION = RegistryDesignation.A.getKey();
|
||||
private static final String REGISTRY_INSTRUMENT_TYPE = RegistryInstrumentType.M.getKey();
|
||||
private static final String REGISTRY_FULL_NAME = "MY FULLNAME";
|
||||
|
|
@ -72,18 +81,28 @@ class MoneyBalanceRegisterServiceTest {
|
|||
@Qualifier("mockProducer")
|
||||
private Producer<String, Object> producer;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
@Autowired
|
||||
private RegistryServiceSettings settings;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("reportOutDir")
|
||||
private File outFolder;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId();
|
||||
|
||||
moneyBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyBalanceRegister, MoneyBalanceRegister.class);
|
||||
companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
||||
registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||
|
||||
Company company = new Company();
|
||||
company.setId(2L);
|
||||
company.setShortName(COMPANY_SHORTNAME);
|
||||
companyMap.insert(company);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void executionRegisterNewForClearingDate() {
|
||||
private RegistryHistory init() {
|
||||
Registry registry = new Registry();
|
||||
registry.setTradingClearingRegistry("not null value");
|
||||
registry.setDiffBalance(BigDecimal.ZERO);
|
||||
|
|
@ -105,10 +124,15 @@ class MoneyBalanceRegisterServiceTest {
|
|||
registryHistory.setEventTime(Instant.now());
|
||||
registryHistoryMap.insert(registryHistory);
|
||||
|
||||
Company company = new Company();
|
||||
company.setId(2L);
|
||||
company.setShortName(COMPANY_SHORTNAME);
|
||||
companyMap.insert(company);
|
||||
return registryHistory;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void executionRegisterNewForClearingDate() {
|
||||
RegistryHistory source = init();
|
||||
boolean oldCsvMode = settings.isCsvMode();
|
||||
settings.setCsvMode(false);
|
||||
|
||||
//making launcherCommand
|
||||
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
||||
|
|
@ -130,5 +154,38 @@ class MoneyBalanceRegisterServiceTest {
|
|||
assertEquals(REGISTRY_BALANCE, moneyBalanceRegister.getRemainderSum());
|
||||
assertEquals(REGISTRY_ACCOUNT, moneyBalanceRegister.getAccount());
|
||||
assertEquals(COMPANY_SHORTNAME, moneyBalanceRegister.getSetHouseName());
|
||||
|
||||
settings.setCsvMode(oldCsvMode);
|
||||
registryHistoryMap.delete(source);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
void executionRegisterNewForClearingDate_CSV() throws CsvValidationException, IOException {
|
||||
RegistryHistory source = init();
|
||||
boolean oldCsvMode = settings.isCsvMode();
|
||||
settings.setCsvMode(true);
|
||||
|
||||
//making launcherCommand
|
||||
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
||||
launcherCommandRequest.setCompanyId(REGISTRY_COMPANY_ID);
|
||||
String jsonString = TestUtils.getJsonStringForSystem(launcherCommandRequest, 0L);
|
||||
|
||||
TestUtils.addRecordToKafka((MockConsumer) moneyBalanceRegisterService.getConsumer(),
|
||||
Task.createRegistry_GBRR.topic(),
|
||||
requestCount++,
|
||||
0,
|
||||
jsonString);
|
||||
|
||||
TestUtils.waitingSendAndCheckRecord(0L, producer);
|
||||
|
||||
File outFile = outFolder.listFiles()[0];
|
||||
File expectedFile = new File(getClass().getClassLoader().getResource("expected_reports/money_balance_register_expected.csv").getFile());
|
||||
ReportTestUtils.compareCSVFiles(expectedFile, outFile, Arrays.asList("Дата", "Время", "Номер отчета"));
|
||||
|
||||
settings.setCsvMode(oldCsvMode);
|
||||
ReportTestUtils.deleteDir(outFolder);
|
||||
registryHistoryMap.delete(source);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package ru.spcex.clearing.registry.service;
|
||||
|
||||
import com.opencsv.CSVParser;
|
||||
import com.opencsv.CSVParserBuilder;
|
||||
import com.opencsv.CSVReader;
|
||||
import com.opencsv.CSVReaderBuilder;
|
||||
import com.opencsv.exceptions.CsvValidationException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ReportTestUtils {
|
||||
|
||||
public static void compareCSVFiles(File expectedFile, File actualFile, List<String> columnsForSkip) throws IOException, CsvValidationException {
|
||||
if (columnsForSkip == null) columnsForSkip = Collections.emptyList();
|
||||
CSVParser csvParser = new CSVParserBuilder().withSeparator(',').withQuoteChar('\"').build();
|
||||
CSVReader expectedCSVReader = new CSVReaderBuilder(new FileReader(expectedFile)).withCSVParser(csvParser).build();
|
||||
CSVReader actualCSVReader = new CSVReaderBuilder(new FileReader(actualFile)).withCSVParser(csvParser).build();
|
||||
|
||||
Map<String, Integer> expectedValueForColumn = new HashMap<>();
|
||||
Map<String, Integer> actualValueForColumn = new HashMap<>();
|
||||
|
||||
String[] expectedHeaders = expectedCSVReader.readNext();
|
||||
String[] actualHeaders = actualCSVReader.readNext();
|
||||
assertEquals(expectedHeaders.length, actualHeaders.length);
|
||||
|
||||
for (int headerIdx = 0; headerIdx < expectedHeaders.length; headerIdx++) {
|
||||
String expectedHeader = expectedHeaders[headerIdx];
|
||||
String actualHeader = actualHeaders[headerIdx];
|
||||
if (!columnsForSkip.contains(expectedHeader)) expectedValueForColumn.put(expectedHeader, headerIdx);
|
||||
if (!columnsForSkip.contains(actualHeader)) actualValueForColumn.put(actualHeader, headerIdx);
|
||||
}
|
||||
|
||||
List<String[]> expectedLines = new ArrayList<>();
|
||||
do {
|
||||
String[] expectedLine = expectedCSVReader.readNext();
|
||||
if (expectedLine == null) break;
|
||||
expectedLines.add(expectedLine);
|
||||
} while (true);
|
||||
|
||||
List<String[]> actualLines = new ArrayList<>();
|
||||
do {
|
||||
String[] actualLine = actualCSVReader.readNext();
|
||||
if (actualLine == null) break;
|
||||
actualLines.add(actualLine);
|
||||
} while (true);
|
||||
if (expectedLines.size() != actualLines.size()) {
|
||||
Assertions.fail("expected and actual lines not equal");
|
||||
}
|
||||
|
||||
for (String[] actualLine : actualLines) {
|
||||
boolean findEqual = false;
|
||||
for (String[] expectedLine : expectedLines) {
|
||||
boolean lineEqual = true;
|
||||
for (String expectedHeader : expectedValueForColumn.keySet()) {
|
||||
int expectedIdx = expectedValueForColumn.get(expectedHeader);
|
||||
int actualIdx = actualValueForColumn.get(expectedHeader);
|
||||
String expected = expectedLine[expectedIdx];
|
||||
String actual = actualLine[actualIdx];
|
||||
lineEqual = expected.equals(actual);
|
||||
if (!lineEqual) break;
|
||||
}
|
||||
if (lineEqual) {
|
||||
findEqual = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (findEqual) continue;
|
||||
Assertions.fail("For actual line '%s' not found expected line".formatted(String.join(", ", actualLine)));
|
||||
}
|
||||
|
||||
List<String> errors = new ArrayList<>();
|
||||
for (int idx = 0; idx < expectedHeaders.length; idx++) {
|
||||
if (!Objects.equals(expectedHeaders[idx], actualHeaders[idx])) {
|
||||
errors.add("expected header (%s) for idx = %d not equal actual header (%s)".formatted(
|
||||
expectedHeaders[idx],
|
||||
idx,
|
||||
actualHeaders[idx])
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!errors.isEmpty()) {
|
||||
Assertions.fail("Files equal, but header sequence broken, cause: %s".formatted(String.join(",", errors)));
|
||||
}
|
||||
|
||||
expectedCSVReader.close();
|
||||
actualCSVReader.close();
|
||||
}
|
||||
|
||||
public static void resetDir(File folder) throws IOException {
|
||||
FileUtils.deleteDirectory(folder);
|
||||
folder = new File("out");
|
||||
folder.mkdirs();
|
||||
}
|
||||
|
||||
public static void deleteDir(File folder) throws IOException {
|
||||
FileUtils.deleteDirectory(folder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"Наименование Расчетного депозитария","Номер отчета","Дата","Время","Краткое наименование УК","Номер торгового раздела счета депо/ код раздела «к размещению/выкупу»","Код ЦБ","Количество ЦБ"
|
||||
,"20231228","28.12.2023","18:54:21",,,"SECURITY_SYMBOL","1"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
"Наименование Расчетного депозитария","Номер отчета","Дата","Время","Код валюты","Краткое наименование УК","Номер торгового /клирингового счета/ счета внутреннего учета СПВБ","Остаток денежных средств"
|
||||
"ANY VALUE","20231229","29.12.2023","10:34:29","RUR",,"CLRN VALUE","123411"
|
||||
|
Loading…
Add table
Reference in a new issue