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>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.integration</groupId>
|
||||||
|
<artifactId>spring-integration-sftp</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
|
@ -51,6 +55,13 @@
|
||||||
<artifactId>test-clearing</artifactId>
|
<artifactId>test-clearing</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- CSV -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.opencsv</groupId>
|
||||||
|
<artifactId>opencsv</artifactId>
|
||||||
|
<version>5.5.2</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<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 HazelcastClientParams hazelcast;
|
||||||
private KafkaConsumerSettings kafkaConsumer;
|
private KafkaConsumerSettings kafkaConsumer;
|
||||||
private KafkaProducerSettings kafkaProducer;
|
private KafkaProducerSettings kafkaProducer;
|
||||||
|
private ReportsStore reportsStore;
|
||||||
|
private boolean csvMode = false;
|
||||||
|
|
||||||
public HazelcastClientParams getHazelcast() {
|
public HazelcastClientParams getHazelcast() {
|
||||||
return hazelcast;
|
return hazelcast;
|
||||||
|
|
@ -38,4 +40,20 @@ public class RegistryServiceSettings {
|
||||||
public void setKafkaProducer(KafkaProducerSettings kafkaProducer) {
|
public void setKafkaProducer(KafkaProducerSettings kafkaProducer) {
|
||||||
this.kafkaProducer = 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.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.clearing.classes.statics.data.register.DepoBalanceRegister;
|
import ru.clearing.classes.statics.data.register.DepoBalanceRegister;
|
||||||
import ru.clearing.classes.statics.data.registry.Registry;
|
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.BaseRequest;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
||||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
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.clearing.registry.util.PreClearMap;
|
||||||
import ru.spcex.platform.enumeration.AccountType;
|
import ru.spcex.platform.enumeration.AccountType;
|
||||||
import ru.spcex.platform.enumeration.RegistryTradingParams;
|
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.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
|
||||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static ru.spcex.platform.enumeration.Task.createRegistry_GRRT;
|
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 Imdg<RegistryHistory> registryHistoryMap;
|
||||||
private final PreClearMap<DepoBalanceRegister> preClearMap;
|
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
|
@Autowired
|
||||||
public DepoBalanceRegisterService(Consumer<String, Object> kafkaQueue,
|
public DepoBalanceRegisterService(Consumer<String, Object> kafkaQueue,
|
||||||
Producer<String, Object> kafkaProducer,
|
Producer<String, Object> kafkaProducer,
|
||||||
ImdgProvider imdgProvider) {
|
ImdgProvider imdgProvider,
|
||||||
|
RegistryServiceSettings settings,
|
||||||
|
@Qualifier("reportOutDir") File outFolder,
|
||||||
|
SFTPReportsConfig.ReportsGateway reportsSftpGateway) {
|
||||||
super(kafkaQueue, kafkaProducer);
|
super(kafkaQueue, kafkaProducer);
|
||||||
this.depoBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoBalanceRegister, DepoBalanceRegister.class);
|
this.depoBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoBalanceRegister, DepoBalanceRegister.class);
|
||||||
this.registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
this.registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||||
preClearMap = PreClearMap.instanceForInstantField(depoBalanceRegisterMap, "created");
|
preClearMap = PreClearMap.instanceForInstantField(depoBalanceRegisterMap, "created");
|
||||||
|
reportBuilder = new DepoBalanceRegisterReportBuilder(imdgProvider);
|
||||||
|
this.outFolder = outFolder;
|
||||||
|
this.settings = settings;
|
||||||
|
this.reportsSftpGateway = reportsSftpGateway;
|
||||||
|
this.deleteAfterSend = settings.getReportsStore().isDeleteAfterSend();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -58,6 +81,7 @@ public class DepoBalanceRegisterService extends QueueConsumer implements Initial
|
||||||
}
|
}
|
||||||
|
|
||||||
public void depoBalanceRegisterNew(BaseRequest<LauncherCommandRequest> userRequest) {
|
public void depoBalanceRegisterNew(BaseRequest<LauncherCommandRequest> userRequest) {
|
||||||
|
boolean csvMode = settings.isCsvMode();
|
||||||
log.debug("LauncherCommandRequest received from {}", createRegistry_GRRT.topic());
|
log.debug("LauncherCommandRequest received from {}", createRegistry_GRRT.topic());
|
||||||
ImdgPredicate predicate = getPredicateForRegistries(userRequest.getRequestPayload().getCompanyId());
|
ImdgPredicate predicate = getPredicateForRegistries(userRequest.getRequestPayload().getCompanyId());
|
||||||
Collection<RegistryHistory> registryHistories = registryHistoryMap.getCollectionObjectsByPredicate(predicate);
|
Collection<RegistryHistory> registryHistories = registryHistoryMap.getCollectionObjectsByPredicate(predicate);
|
||||||
|
|
@ -67,10 +91,16 @@ public class DepoBalanceRegisterService extends QueueConsumer implements Initial
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.debug("Select {} Registry history by query {}", registryHistories.size(), predicate);
|
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) {
|
for (RegistryHistory registryHistory : registryHistories) {
|
||||||
if (BigDecimal.ZERO.compareTo(registryHistory.getObject().getDiffBalance()) != 0) continue;
|
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");
|
log.debug("Successfully processed");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.clearing.classes.statics.data.company.Company;
|
import ru.clearing.classes.statics.data.company.Company;
|
||||||
import ru.clearing.classes.statics.data.register.MoneyBalanceRegister;
|
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.BaseRequest;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
||||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
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.clearing.registry.util.PreClearMap;
|
||||||
import ru.spcex.platform.enumeration.AccountType;
|
import ru.spcex.platform.enumeration.AccountType;
|
||||||
import ru.spcex.platform.enumeration.RegistryTradingParams;
|
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.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
|
||||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static ru.spcex.platform.enumeration.Task.createRegistry_GBRR;
|
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 Imdg<Company> companyMap;
|
||||||
private final PreClearMap<MoneyBalanceRegister> preClearMap;
|
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
|
@Autowired
|
||||||
public MoneyBalanceRegisterService(Consumer<String, Object> kafkaQueue,
|
public MoneyBalanceRegisterService(Consumer<String, Object> kafkaQueue,
|
||||||
Producer<String, Object> kafkaProducer,
|
Producer<String, Object> kafkaProducer,
|
||||||
ImdgProvider imdgProvider) {
|
ImdgProvider imdgProvider,
|
||||||
|
RegistryServiceSettings settings,
|
||||||
|
@Qualifier("reportOutDir") File outFolder,
|
||||||
|
SFTPReportsConfig.ReportsGateway reportsSftpGateway) {
|
||||||
super(kafkaQueue, kafkaProducer);
|
super(kafkaQueue, kafkaProducer);
|
||||||
this.moneyBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyBalanceRegister, MoneyBalanceRegister.class);
|
this.moneyBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyBalanceRegister, MoneyBalanceRegister.class);
|
||||||
this.registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
this.registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||||
this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
||||||
preClearMap = PreClearMap.instanceForInstantField(moneyBalanceRegisterMap, "created");
|
preClearMap = PreClearMap.instanceForInstantField(moneyBalanceRegisterMap, "created");
|
||||||
|
reportBuilder = new MoneyBalanceRegisterReportBuilder(imdgProvider);
|
||||||
|
this.outFolder = outFolder;
|
||||||
|
this.settings = settings;
|
||||||
|
this.reportsSftpGateway = reportsSftpGateway;
|
||||||
|
this.deleteAfterSend = settings.getReportsStore().isDeleteAfterSend();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -62,6 +86,7 @@ public class MoneyBalanceRegisterService extends QueueConsumer implements Initia
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moneyBalanceRegisterNew(BaseRequest<LauncherCommandRequest> userRequest) {
|
public void moneyBalanceRegisterNew(BaseRequest<LauncherCommandRequest> userRequest) {
|
||||||
|
boolean csvMode = settings.isCsvMode();
|
||||||
log.debug("LauncherCommandRequest received from {}", createRegistry_GBRR.topic());
|
log.debug("LauncherCommandRequest received from {}", createRegistry_GBRR.topic());
|
||||||
ImdgPredicate predicate = getSqlForRegistryHistory(userRequest.getRequestPayload().getCompanyId());
|
ImdgPredicate predicate = getSqlForRegistryHistory(userRequest.getRequestPayload().getCompanyId());
|
||||||
Collection<RegistryHistory> registryHistories = registryHistoryMap.getCollectionObjectsByPredicate(predicate);
|
Collection<RegistryHistory> registryHistories = registryHistoryMap.getCollectionObjectsByPredicate(predicate);
|
||||||
|
|
@ -70,10 +95,16 @@ public class MoneyBalanceRegisterService extends QueueConsumer implements Initia
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.debug("Select {} Registry history by query {}", registryHistories.size(), predicate);
|
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) {
|
for (RegistryHistory registryHistory : registryHistories) {
|
||||||
if (BigDecimal.ZERO.compareTo(registryHistory.getObject().getDiffBalance()) != 0) continue;
|
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");
|
log.debug("successfully processed");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,13 @@ registry-service.kafka-producer.acks=all
|
||||||
registry-service.kafka-producer.retries=0
|
registry-service.kafka-producer.retries=0
|
||||||
registry-service.kafka-producer.batch-size=16384
|
registry-service.kafka-producer.batch-size=16384
|
||||||
registry-service.kafka-producer.linger-ms=1
|
registry-service.kafka-producer.linger-ms=1
|
||||||
registry-service.kafka-producer.buffer-memory=33554432
|
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.ImdgId;
|
||||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static ru.spcex.clearing.registry.utils.TestUtils.setFuture;
|
import static ru.spcex.clearing.registry.utils.TestUtils.setFuture;
|
||||||
import static ru.spcex.clearing.test.config.KafkaTestConfig.producerCaptors;
|
import static ru.spcex.clearing.test.config.KafkaTestConfig.producerCaptors;
|
||||||
|
|
@ -58,4 +60,9 @@ public class KafkaConfigTest {
|
||||||
return mockProducer;
|
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;
|
package ru.spcex.clearing.registry.service;
|
||||||
|
|
||||||
|
import com.opencsv.exceptions.CsvValidationException;
|
||||||
import org.apache.kafka.clients.consumer.MockConsumer;
|
import org.apache.kafka.clients.consumer.MockConsumer;
|
||||||
import org.apache.kafka.clients.producer.Producer;
|
import org.apache.kafka.clients.producer.Producer;
|
||||||
import org.junit.jupiter.api.MethodOrderer;
|
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.Test;
|
||||||
import org.junit.jupiter.api.TestMethodOrder;
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
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.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
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.clearing.classes.statics.data.registry.RegistryHistory;
|
||||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
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.ValidationConfig;
|
||||||
|
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||||
import ru.spcex.clearing.test.TestUtils;
|
import ru.spcex.clearing.test.TestUtils;
|
||||||
import ru.spcex.clearing.test.config.ImdgTestConfig;
|
import ru.spcex.clearing.test.config.ImdgTestConfig;
|
||||||
import ru.spcex.clearing.test.config.KafkaTestConfig;
|
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.Imdg;
|
||||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
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.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
@ -38,9 +45,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
DepoBalanceRegisterService.class,
|
DepoBalanceRegisterService.class,
|
||||||
ImdgTestConfig.class,
|
ImdgTestConfig.class,
|
||||||
KafkaTestConfig.class,
|
KafkaTestConfig.class,
|
||||||
|
TestConfig.class,
|
||||||
|
SFTPTestConfig.class,
|
||||||
})
|
})
|
||||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||||
class DepoBalanceRegisterServiceTest {
|
class DepoBalanceRegisterServiceTest implements InitializingBean {
|
||||||
private static int requestCount = 0;
|
private static int requestCount = 0;
|
||||||
|
|
||||||
private static final Long companyId = 1L;
|
private static final Long companyId = 1L;
|
||||||
|
|
@ -63,15 +72,25 @@ class DepoBalanceRegisterServiceTest {
|
||||||
@Qualifier("mockProducer")
|
@Qualifier("mockProducer")
|
||||||
private Producer<String, Object> producer;
|
private Producer<String, Object> producer;
|
||||||
|
|
||||||
@PostConstruct
|
@Autowired
|
||||||
private void init() {
|
private RegistryServiceSettings settings;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("reportOutDir")
|
||||||
|
private File outFolder;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId();
|
ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId();
|
||||||
|
|
||||||
//initializing of imdg
|
//initializing of imdg
|
||||||
registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||||
depoBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoBalanceRegister, DepoBalanceRegister.class);
|
depoBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoBalanceRegister, DepoBalanceRegister.class);
|
||||||
// initialing objects for imdg repos
|
// initialing objects for imdg repos
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryHistory init() {
|
||||||
Registry registry = new Registry();
|
Registry registry = new Registry();
|
||||||
registry.setRegistryDesignation(RegistryDesignation.A.getKey());
|
registry.setRegistryDesignation(RegistryDesignation.A.getKey());
|
||||||
registry.setRegistryInstrumentType(RegistryInstrumentType.S.getKey());
|
registry.setRegistryInstrumentType(RegistryInstrumentType.S.getKey());
|
||||||
|
|
@ -87,11 +106,15 @@ class DepoBalanceRegisterServiceTest {
|
||||||
registryHistory.setObject(registry);
|
registryHistory.setObject(registry);
|
||||||
registryHistory.setEventTime(Instant.now());
|
registryHistory.setEventTime(Instant.now());
|
||||||
registryHistoryMap.insert(registryHistory);
|
registryHistoryMap.insert(registryHistory);
|
||||||
|
return registryHistory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(1)
|
@Order(1)
|
||||||
void executionRegisterNewForEventTime() {
|
void executionRegisterNewForEventTime() {
|
||||||
|
RegistryHistory source = init();
|
||||||
|
boolean oldCsvMode = settings.isCsvMode();
|
||||||
|
settings.setCsvMode(false);
|
||||||
//making launcherCommand
|
//making launcherCommand
|
||||||
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
||||||
|
|
||||||
|
|
@ -112,5 +135,37 @@ class DepoBalanceRegisterServiceTest {
|
||||||
assertEquals(account, depoBalanceRegister.getDepoCode());
|
assertEquals(account, depoBalanceRegister.getDepoCode());
|
||||||
assertEquals(balance, depoBalanceRegister.getQuantity());
|
assertEquals(balance, depoBalanceRegister.getQuantity());
|
||||||
assertEquals(SECURITY_SYMBOL, depoBalanceRegister.getSecuritySymbol());
|
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;
|
package ru.spcex.clearing.registry.service;
|
||||||
|
|
||||||
|
import com.opencsv.exceptions.CsvValidationException;
|
||||||
import org.apache.kafka.clients.consumer.MockConsumer;
|
import org.apache.kafka.clients.consumer.MockConsumer;
|
||||||
import org.apache.kafka.clients.producer.Producer;
|
import org.apache.kafka.clients.producer.Producer;
|
||||||
import org.junit.jupiter.api.MethodOrderer;
|
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.Test;
|
||||||
import org.junit.jupiter.api.TestMethodOrder;
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
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.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
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.clearing.classes.statics.data.registry.RegistryHistory;
|
||||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
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.ValidationConfig;
|
||||||
|
import ru.spcex.clearing.registry.config.settings.RegistryServiceSettings;
|
||||||
import ru.spcex.clearing.test.TestUtils;
|
import ru.spcex.clearing.test.TestUtils;
|
||||||
import ru.spcex.clearing.test.config.ImdgTestConfig;
|
import ru.spcex.clearing.test.config.ImdgTestConfig;
|
||||||
import ru.spcex.clearing.test.config.KafkaTestConfig;
|
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.Imdg;
|
||||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
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.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
@ -39,9 +46,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
MoneyBalanceRegisterService.class,
|
MoneyBalanceRegisterService.class,
|
||||||
ImdgTestConfig.class,
|
ImdgTestConfig.class,
|
||||||
KafkaTestConfig.class,
|
KafkaTestConfig.class,
|
||||||
|
TestConfig.class,
|
||||||
|
SFTPTestConfig.class,
|
||||||
})
|
})
|
||||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.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_DESIGNATION = RegistryDesignation.A.getKey();
|
||||||
private static final String REGISTRY_INSTRUMENT_TYPE = RegistryInstrumentType.M.getKey();
|
private static final String REGISTRY_INSTRUMENT_TYPE = RegistryInstrumentType.M.getKey();
|
||||||
private static final String REGISTRY_FULL_NAME = "MY FULLNAME";
|
private static final String REGISTRY_FULL_NAME = "MY FULLNAME";
|
||||||
|
|
@ -72,18 +81,28 @@ class MoneyBalanceRegisterServiceTest {
|
||||||
@Qualifier("mockProducer")
|
@Qualifier("mockProducer")
|
||||||
private Producer<String, Object> producer;
|
private Producer<String, Object> producer;
|
||||||
|
|
||||||
@PostConstruct
|
@Autowired
|
||||||
private void init() {
|
private RegistryServiceSettings settings;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("reportOutDir")
|
||||||
|
private File outFolder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId();
|
ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId();
|
||||||
|
|
||||||
moneyBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyBalanceRegister, MoneyBalanceRegister.class);
|
moneyBalanceRegisterMap = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyBalanceRegister, MoneyBalanceRegister.class);
|
||||||
companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
||||||
registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
registryHistoryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_RegistryHistory, RegistryHistory.class);
|
||||||
|
|
||||||
|
Company company = new Company();
|
||||||
|
company.setId(2L);
|
||||||
|
company.setShortName(COMPANY_SHORTNAME);
|
||||||
|
companyMap.insert(company);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private RegistryHistory init() {
|
||||||
@Order(1)
|
|
||||||
void executionRegisterNewForClearingDate() {
|
|
||||||
Registry registry = new Registry();
|
Registry registry = new Registry();
|
||||||
registry.setTradingClearingRegistry("not null value");
|
registry.setTradingClearingRegistry("not null value");
|
||||||
registry.setDiffBalance(BigDecimal.ZERO);
|
registry.setDiffBalance(BigDecimal.ZERO);
|
||||||
|
|
@ -105,10 +124,15 @@ class MoneyBalanceRegisterServiceTest {
|
||||||
registryHistory.setEventTime(Instant.now());
|
registryHistory.setEventTime(Instant.now());
|
||||||
registryHistoryMap.insert(registryHistory);
|
registryHistoryMap.insert(registryHistory);
|
||||||
|
|
||||||
Company company = new Company();
|
return registryHistory;
|
||||||
company.setId(2L);
|
}
|
||||||
company.setShortName(COMPANY_SHORTNAME);
|
|
||||||
companyMap.insert(company);
|
@Test
|
||||||
|
@Order(1)
|
||||||
|
void executionRegisterNewForClearingDate() {
|
||||||
|
RegistryHistory source = init();
|
||||||
|
boolean oldCsvMode = settings.isCsvMode();
|
||||||
|
settings.setCsvMode(false);
|
||||||
|
|
||||||
//making launcherCommand
|
//making launcherCommand
|
||||||
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
LauncherCommandRequest launcherCommandRequest = new LauncherCommandRequest();
|
||||||
|
|
@ -130,5 +154,38 @@ class MoneyBalanceRegisterServiceTest {
|
||||||
assertEquals(REGISTRY_BALANCE, moneyBalanceRegister.getRemainderSum());
|
assertEquals(REGISTRY_BALANCE, moneyBalanceRegister.getRemainderSum());
|
||||||
assertEquals(REGISTRY_ACCOUNT, moneyBalanceRegister.getAccount());
|
assertEquals(REGISTRY_ACCOUNT, moneyBalanceRegister.getAccount());
|
||||||
assertEquals(COMPANY_SHORTNAME, moneyBalanceRegister.getSetHouseName());
|
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