Добавил .sh, сделал алгоритмы выгрузки и тесты.
This commit is contained in:
psemenkov 2023-05-12 11:34:54 +03:00
parent ee79336ce4
commit d5c929f2a4
11 changed files with 312 additions and 45 deletions

View file

@ -1,8 +1,17 @@
package ru.spcex.clearing.lim.exporter.services;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.lim.exporter.config.SFTPConfig;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.LimExportedRequest;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.io.File;
import java.io.IOException;
@ -11,17 +20,28 @@ import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.List;
import static ru.spcex.clearing.platform.messaging.domain.Consts.LIM_EXPORTED;
public abstract class AbstractExporterService {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
protected final Imdg<Registry> registryImdg;
private final List<String> validStatus = List.of("ACTV", "ROPN");
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private final DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
private final SFTPConfig.LimGateway gateway;
private final Producer<String, Object> producer;
protected AbstractExporterService(SFTPConfig.LimGateway gateway) {
protected AbstractExporterService(SFTPConfig.LimGateway gateway, Producer<String, Object> producer, ImdgProvider imdgProvider) {
this.gateway = gateway;
this.producer = producer;
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
}
public abstract Collection<String> getLimFileRows();
public abstract String getTargetFileName();
public void process() {
@ -34,15 +54,19 @@ public abstract class AbstractExporterService {
Files.write(limFilePath, getLimFileRows());
gateway.sendToSftp(limFile);
log.debug("Successfully exported {} file", fileName);
Files.deleteIfExists(limFilePath);
} catch (IOException e) {
log.error("Failed export {} file", fileName);
throw new RuntimeException(e);
}
log.debug("Successfully exported {} file", fileName);
LimExportedRequest limExportedRequest = new LimExportedRequest();
limExportedRequest.setLimFileName(fileName);
producer.send(new ProducerRecord<>(LIM_EXPORTED, limExportedRequest));
}
protected String prepareFileName(String target){
protected String prepareFileName(String target) {
StringBuilder result = new StringBuilder();
String dt = dtFormatter.format(LocalDateTime.now());
@ -53,4 +77,13 @@ public abstract class AbstractExporterService {
result.append(".lim");
return result.toString();
}
protected boolean checkNotBloked(Registry registry) {
if (registry.getTradingClearingRegistryId() == null) return false;
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getSingleObjectByID(registry.getTradingClearingRegistryId());
if (tradingClearingRegistry != null && StringUtils.hasText(tradingClearingRegistry.getStatus())) {
return validStatus.contains(tradingClearingRegistry.getStatus());
}
return false;
}
}

View file

@ -1,13 +1,11 @@
package ru.spcex.clearing.lim.exporter.services;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.lim.exporter.config.SFTPConfig;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.math.BigDecimal;
@ -21,14 +19,11 @@ import java.util.stream.Collectors;
@Service
public class MoneyExporterService extends AbstractExporterService {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<Registry> registryImdg;
private final List<String> validStatus = List.of("ACTV", "ROPN");
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
public MoneyExporterService(SFTPConfig.LimGateway gateway, ImdgProvider imdgProvider) {
super(gateway);
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
public MoneyExporterService(SFTPConfig.LimGateway gateway,
Producer<String, Object> producer,
ImdgProvider imdgProvider) {
super(gateway, producer, imdgProvider);
}
@Override
@ -56,13 +51,13 @@ public class MoneyExporterService extends AbstractExporterService {
Map<String, List<Registry>> byTcrD = registriesD.stream()
.collect(Collectors.groupingBy(Registry::getTradingClearingRegistry));
for(Map.Entry<String, List<Registry>> entryA : byTcrA.entrySet()){
for (Map.Entry<String, List<Registry>> entryA : byTcrA.entrySet()) {
List<Registry> registriesListA = entryA.getValue();
List<Registry> registriesListB = byTcrD.get(entryA.getKey());
for (Registry registry : registriesListA){
if(checkNotBloked(registry)){
//из ТЗ пока не понятно как соотнести Registry из registriesListA и registriesListB по валюте(RUB, USD) и вычислить остаток на денежном счете
// limFileRows.add(getRow(...));
for (Registry registryA : registriesListA) {
if (checkNotBloked(registryA)) {
Registry registryD = findRegistryBySecurityId(registryA.getSecurityId(), registriesListB);
limFileRows.add(getRow(registryA, registryD));
}
}
}
@ -70,13 +65,7 @@ public class MoneyExporterService extends AbstractExporterService {
return limFileRows;
}
private boolean checkNotBloked(Registry registry){
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getSingleObjectByID(registry.getTradingClearingRegistryId());
return validStatus.contains(tradingClearingRegistry.getStatus());
}
//поменяется при обновлении ТЗ
private String getRow(Registry registryA, Registry registryB){
public String getRow(Registry registryA, Registry registryD) {
StringBuilder row = new StringBuilder();
row.append("MONEY: FIRM_ID = ");
@ -85,14 +74,14 @@ public class MoneyExporterService extends AbstractExporterService {
row.append("; TAG = SPVB");
row.append("; CURR_CODE = ");
// MoneyMarketSecurity mms = moneyMarketSecurityMap.getSingleObjectByFieldValues(Map.of("securityId", ));
row.append(registryA.getSecuritySymbol());
row.append("; CLIENT_CODE = ");
row.append(registryA.getTradingClearingRegistry());
row.append("; OPEN_BALANCE = ");
BigDecimal balance = registryA.getBalance() != null ?
registryB.getBalance() != null ? registryA.getBalance().subtract(registryB.getBalance()) : registryA.getBalance() :
registryD != null && registryD.getBalance() != null ? registryA.getBalance().subtract(registryD.getBalance()) : registryA.getBalance() :
BigDecimal.ZERO;
row.append(balance);
@ -101,4 +90,13 @@ public class MoneyExporterService extends AbstractExporterService {
row.append("; LIMIT_KIND = 0;");
return row.toString();
}
private Registry findRegistryBySecurityId(Long securityId, List<Registry> registries) {
for (Registry registry : registries) {
if (securityId.equals(registry.getSecurityId())) {
return registry;
}
}
return null;
}
}

View file

@ -1,12 +1,11 @@
package ru.spcex.clearing.lim.exporter.services;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.lim.exporter.config.SFTPConfig;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.time.LocalDate;
@ -19,11 +18,10 @@ import java.util.Map;
public class SecurityExporterService extends AbstractExporterService {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<Registry> registryImdg;
public SecurityExporterService(SFTPConfig.LimGateway gateway, ImdgProvider imdgProvider) {
super(gateway);
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
public SecurityExporterService(SFTPConfig.LimGateway gateway,
Producer<String, Object> producer,
ImdgProvider imdgProvider) {
super(gateway, producer, imdgProvider);
}
@ -33,7 +31,7 @@ public class SecurityExporterService extends AbstractExporterService {
}
@Override
public Collection<String> getLimFileRows(){
public Collection<String> getLimFileRows() {
log.debug("Started loading and formation of DEPO file lines");
LocalDate currentDate = LocalDate.now();
List<String> limFileRows = new ArrayList<>();
@ -42,21 +40,23 @@ public class SecurityExporterService extends AbstractExporterService {
"registryInstrumentType", "S",
"registryCode", "T",
"clearingDate", currentDate));
for (Registry registry : registries){
limFileRows.add(getRow(registry));
for (Registry registry : registries) {
if (checkNotBloked(registry)) {
limFileRows.add(getRow(registry));
}
}
log.debug("Successfully completed the formation of rows: {} for export DEPO", limFileRows.size());
return limFileRows;
}
private String getRow(Registry registry){
public String getRow(Registry registry) {
StringBuilder row = new StringBuilder();
row.append("DEPO: FIRM_ID = ");
row.append(registry.getTradingCode());
row.append("; SECCODE = ");
row.append(getSecurityShortName(registry));
row.append(registry.getSecuritySymbol());
row.append("; CLIENT_CODE = ");
row.append(registry.getTradingClearingRegistry());
@ -73,9 +73,4 @@ public class SecurityExporterService extends AbstractExporterService {
return row.toString();
}
//скорее всего в новой редакции ТЗ не понадобится
private String getSecurityShortName(Registry registry){
return null;
}
}

View file

@ -0,0 +1,59 @@
package ru.spcex.clearing.lim.exporter;
import org.apache.kafka.clients.producer.MockProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.test.TestUtils;
import ru.spcex.clearing.test.config.ImdgTestConfig;
import ru.spcex.clearing.test.config.KafkaTestConfig;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.time.LocalDate;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static ru.spcex.clearing.test.config.ImdgTestConfig.currentID;
import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
ImdgTestConfig.class,
KafkaTestConfig.class})
public abstract class AbstractServiceTest {
protected static final long id = currentID.getAndIncrement();
protected Imdg<Registry> registryImdg;
protected Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
protected LocalDate currentDate = LocalDate.now();
protected String tcrA = "1324A234";
protected String tcrD = "124324A234";
protected Long securityIdFirst = 12L;
protected Long securityIdSecond = 23L;
@Captor
protected ArgumentCaptor<ProducerRecord> producerRecord;
@MockBean
protected MockProducer<String, Object> mockProducer;
@Autowired
@Qualifier("hazelcastServiceTest")
protected ImdgProvider imdgProvider;
protected void init() {
waitAvailableImdgProviderAndAddAdminWithDefaultId();
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
TestUtils.FutureRecordMetadata future = spy(new TestUtils.FutureRecordMetadata());
doReturn(future).when(mockProducer).send(producerRecord.capture());
}
}

View file

@ -0,0 +1,83 @@
package ru.spcex.clearing.lim.exporter.services;
import org.junit.jupiter.api.Test;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.lim.exporter.AbstractServiceTest;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.Collection;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static ru.spcex.clearing.test.TestUtils.clearAllInImdg;
class MoneyExporterServiceTest extends AbstractServiceTest {
@PostConstruct
public void init() {
super.init();
}
/**
* {@link MoneyExporterService#getLimFileRows()}<br>
* Тест проверяет создание строк документа lim.<br>
*/
@Test
void getLimFileRows() {
clearAllInImdg(tradingClearingRegistryImdg);
Registry registryA = getRegistryA(tcrA, securityIdFirst);
Registry registryD = getRegistryD(tcrA, securityIdFirst);
registryImdg.insert(registryA);
registryImdg.insert(registryD);
registryA = getRegistryA(tcrD, securityIdSecond);
registryD = getRegistryD(tcrD, securityIdSecond);
registryImdg.insert(registryA);
registryImdg.insert(registryD);
MoneyExporterService moneyExporterService = new MoneyExporterService(null, mockProducer, imdgProvider);
Collection<String> limFileRows = moneyExporterService.getLimFileRows();
assertEquals(0, limFileRows.size());
TradingClearingRegistry tradingClearingRegistry = new TradingClearingRegistry();
tradingClearingRegistry.setId(securityIdFirst);
tradingClearingRegistry.setStatus("ACTV");
tradingClearingRegistryImdg.insert(tradingClearingRegistry);
tradingClearingRegistry.setId(securityIdSecond);
tradingClearingRegistryImdg.insert(tradingClearingRegistry);
limFileRows = moneyExporterService.getLimFileRows();
assertEquals(2, limFileRows.size());
assertTrue(limFileRows.contains(moneyExporterService.getRow(registryA, registryD)));
}
private Registry getRegistryA(String tradingClearingRegistry, Long securityId) {
Registry registry = new Registry();
registry.setTradingCode("1A12323");
registry.setBalance(new BigDecimal("10.00"));
registry.setTradingClearingRegistry(tradingClearingRegistry);
registry.setRegistryDesignation("A");
registry.setRegistryInstrumentType("M");
registry.setRegistryCode("F");
registry.setClearingDate(currentDate);
registry.setSecuritySymbol("RUB");
registry.setSecurityId(securityId);
registry.setTradingClearingRegistryId(securityId);
return registry;
}
private Registry getRegistryD(String tradingClearingRegistry, Long securityId) {
Registry registry = new Registry();
registry.setTradingCode("1A12323");
registry.setBalance(new BigDecimal("5.00"));
registry.setTradingClearingRegistry(tradingClearingRegistry);
registry.setRegistryDesignation("D");
registry.setRegistryInstrumentType("M");
registry.setRegistryCode("T");
registry.setClearingDate(currentDate);
registry.setSecuritySymbol("RUB");
registry.setSecurityId(securityId);
registry.setTradingClearingRegistryId(securityId);
return registry;
}
}

View file

@ -0,0 +1,70 @@
package ru.spcex.clearing.lim.exporter.services;
import org.junit.jupiter.api.Test;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.lim.exporter.AbstractServiceTest;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.Collection;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static ru.spcex.clearing.test.TestUtils.clearAllInImdg;
class SecurityExporterServiceTest extends AbstractServiceTest {
@PostConstruct
public void init() {
super.init();
}
/**
* {@link SecurityExporterService#getLimFileRows()}<br>
* Тест проверяет создание строк документа lim.<br>
*/
@Test
void getLimFileRows() {
clearAllInImdg(tradingClearingRegistryImdg);
Registry registry1 = getRegistry(tcrA, securityIdFirst);
Registry registry2 = getRegistry(tcrA, securityIdFirst);
registryImdg.insert(registry1);
registryImdg.insert(registry2);
registry1 = getRegistry(tcrD, securityIdSecond);
registry2 = getRegistry(tcrD, securityIdSecond);
registryImdg.insert(registry1);
registryImdg.insert(registry2);
SecurityExporterService securityExporterService = new SecurityExporterService(null, mockProducer, imdgProvider);
Collection<String> limFileRows = securityExporterService.getLimFileRows();
assertEquals(0, limFileRows.size());
TradingClearingRegistry tradingClearingRegistry = new TradingClearingRegistry();
tradingClearingRegistry.setId(securityIdFirst);
tradingClearingRegistry.setStatus("ACTV");
tradingClearingRegistryImdg.insert(tradingClearingRegistry);
tradingClearingRegistry.setId(securityIdSecond);
tradingClearingRegistryImdg.insert(tradingClearingRegistry);
limFileRows = securityExporterService.getLimFileRows();
assertEquals(4, limFileRows.size());
assertTrue(limFileRows.contains(securityExporterService.getRow(registry1)));
assertTrue(limFileRows.contains(securityExporterService.getRow(registry2)));
}
private Registry getRegistry(String tradingClearingRegistry, Long securityId) {
Registry registry = new Registry();
registry.setTradingCode("1A12323");
registry.setBalance(new BigDecimal("10.00"));
registry.setTradingClearingRegistry(tradingClearingRegistry);
registry.setRegistryDesignation("A");
registry.setRegistryInstrumentType("S");
registry.setRegistryCode("T");
registry.setClearingDate(currentDate);
registry.setSecuritySymbol("RUB");
registry.setSecurityId(securityId);
registry.setTradingClearingRegistryId(securityId);
return registry;
}
}

View file

@ -104,6 +104,7 @@ public interface Consts {
String SDF11_PROCESS = "sdf11-process";
String EXPORT_PROCESS = "export-process";
String S_TRADES_IMPORTED = "s_trades-imported";
String LIM_EXPORTED = "lim_exported";
String ACCOUNT_TERMINATION = "account-termination";
String BALANCE_ACCOUNT_NEW = "balance-account-new";
String BALANCE_ACCOUNT_UPDATE = "balance-account-update";

View file

@ -0,0 +1,16 @@
package ru.spcex.clearing.platform.messaging.domain.cud.utilities;
import com.fasterxml.jackson.annotation.JsonProperty;
public class LimExportedRequest {
@JsonProperty
private String limFileName;
public String getLimFileName() {
return limFileName;
}
public void setLimFileName(String limFileName) {
this.limFileName = limFileName;
}
}

View file

@ -6,6 +6,7 @@ kill -9 $(ps -ef | grep java | grep balance-service.jar | awk '{print $2}')
kill -9 $(ps -ef | grep java | grep company-service.jar | awk '{print $2}')
kill -9 $(ps -ef | grep java | grep clearing-service.jar | awk '{print $2}')
kill -9 $(ps -ef | grep java | grep dbf-exporter.jar | awk '{print $2}')
kill -9 $(ps -ef | grep java | grep lim-exporter.jar | awk '{print $2}')
kill -9 $(ps -ef | grep java | grep dbf-importer.jar | awk '{print $2}')
kill -9 $(ps -ef | grep java | grep trade-importer.jar | awk '{print $2}')
kill -9 $(ps -ef | grep java | grep imdg.jar | awk '{print $2}')

View file

@ -7,6 +7,7 @@ cd /opt/mfd/clearing/bin
/opt/mfd/clearing/bin/company-service.sh
/opt/mfd/clearing/bin/clearing-service.sh
/opt/mfd/clearing/bin/dbf-exporter.sh
/opt/mfd/clearing/bin/lim-exporter.sh
/opt/mfd/clearing/bin/dbf-importer.sh
/opt/mfd/clearing/bin/trade-importer.sh
/opt/mfd/clearing/bin/securities-service.sh

View file

@ -0,0 +1,10 @@
#!/bin/bash
CLEARING_HOME=/opt/mfd/clearing/
cd $CLEARING_HOME/bin
CMD="java -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7090 -jar lim-exporter.jar --spring.config.location=$CLEARING_HOME/settings/lim-exporter/"
$CMD >/dev/null 2>&1 &