Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
ialbert 2023-01-31 15:25:08 +03:00
commit 7647a0ff5b
25 changed files with 868 additions and 385 deletions

View file

@ -24,6 +24,8 @@ import ru.spcex.clearing.backendapi.security.KeycloakUtils;
import ru.spcex.clearing.backendapi.service.IOperator;
import ru.spcex.clearing.backendapi.service.IStateLoader;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.platform.enumeration.Task;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
@ -67,7 +69,7 @@ public class LauncherController extends AbstractQueueController {
@RequestMapping(value = "/{task-code}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CudResponse add(@ApiParam(value = "Код задания из taskDictionary", required = true, example = "ABLK")
@PathVariable("task-code") String dictionaryName) throws ExecutionException, InterruptedException {
@PathVariable("task-code") String dictionaryName) throws ExecutionException, InterruptedException {
AbstractDictionary taskEnum = taskDictionary.getSingleObjectByFieldValues(Map.of("code", dictionaryName));
if (taskEnum == null) {
throw new NotFound404Exception("task dictionary element with code '" + dictionaryName + "'");
@ -81,11 +83,37 @@ public class LauncherController extends AbstractQueueController {
}
launcherCommand.setTask(dictionaryName);
launcherCommand.setUserId(user.getId());
// пока здесь, это требуется для сохранения истории
saveLauncher(dictionaryName, user.getId());
//топики ограничиваются наличием в taskDictionary
//подписываются на разные топики в разных модулях, см. ru.spcex.platform.enumeration.Task#topic
return processRequest("launcher-" + dictionaryName, launcherCommand);
return processRequest(Consts.LAUNCHER_NEW, launcherCommand);
}
@ApiOperation(value = "create specific launcher.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(value = "/specific/{task-code}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CudResponse addSpecific(@ApiParam(value = "Код задания из taskDictionary", required = true, example = "ABLK")
@PathVariable("task-code") String dictionaryName,
@RequestBody LauncherNew launcherNew) throws ExecutionException, InterruptedException {
AbstractDictionary taskEnum = taskDictionary.getSingleObjectByFieldValues(Map.of("code", dictionaryName));
if (taskEnum == null) {
throw new NotFound404Exception("task dictionary element with code '" + dictionaryName + "'");
}
if (!Task.startOfClearing.getKey().equals(taskEnum.getCode())) {
throw new IllegalStateException(String.format("Task %s not support request with body", taskEnum.getCode()));
}
LauncherNew launcherCommand = new LauncherNew();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = KeycloakUtils.getUserNameFromAuthentication(authentication);
User user = userImdg.getSingleObjectByFieldValues(Map.of("identifier", username));
if (user == null) {
throw new IllegalStateException("cannot obtain userId from logged in user " + username);
}
launcherCommand.setTask(dictionaryName);
launcherCommand.setUserId(user.getId());
launcherCommand.setCompanyId(launcherNew.getCompanyId());
launcherCommand.setSecurityId(launcherNew.getSecurityId());
return processRequest(Consts.LAUNCHER_NEW, launcherCommand);
}
private void saveLauncher(String taskCode, Long userId) {

View file

@ -19,6 +19,12 @@ public class LauncherNew implements IAction<Object> {
@ApiModelProperty(value = "Идентификатор единоличного исполнительного органа", example = "ABCD")
@JsonProperty
private String task;
@ApiModelProperty(value = "Идентификатор инициатора", example = "1000")
@JsonProperty
private Long companyId;
@ApiModelProperty(value = "Идентификатор инструмента", example = "1000")
@JsonProperty
private Long securityId;
@JsonIgnore
private Long userId;
@ -32,6 +38,8 @@ public class LauncherNew implements IAction<Object> {
} else {
LauncherCommandRequest taskRunnerCommandRequest = new LauncherCommandRequest();
taskRunnerCommandRequest.setTaskName(task);
taskRunnerCommandRequest.setCompanyId(companyId);
taskRunnerCommandRequest.setSecurityId(securityId);
taskRunnerCommandRequest.setUserId(userId);
return taskRunnerCommandRequest;
}
@ -65,4 +73,20 @@ public class LauncherNew implements IAction<Object> {
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public Long getSecurityId() {
return securityId;
}
public void setSecurityId(Long securityId) {
this.securityId = securityId;
}
}

View file

@ -1576,7 +1576,7 @@
<generationId type="1" name="Идентификатор взаимодействия" shortname="ID взаимодействия" searchable="true" sortable="true"/>
<inSDf12Id type="1" name="Идентификатор соответствующей записи из таблицы-источника" shortname="Входящая запись" searchable="true" sortable="true"/>
</sDf18>
<s_trade name="Сделки из Торговой системы" class="" table="s_trade">
<s_trade name="Сделки из Торговой системы" class="ru.clearing.classes.statics.data.misc.STrade" table="s_trade">
<id type="1" name="Идентификатор записи" shortname="ID" searchable="true" sortable="true"/>
<trade_num type="1" name="Номер сделки" shortname="Номер сделки" searchable="true" sortable="true"/>
<sec_code type="2" length="255" name="Код ценной бумаги" shortname="Код ценной бумаги" searchable="true" sortable="true"/>

View file

@ -14,7 +14,6 @@
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<external_libraries.kafka.version>3.0.1</external_libraries.kafka.version>
</properties>
<dependencies>
<dependency>
@ -57,23 +56,6 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<version>2.8.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.8.8</version>
</dependency>
</dependencies>
<build>
<resources>

View file

@ -1,17 +1,24 @@
package ru.spcex.clearing.balance.config;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.clients.producer.MockProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.platform.messaging.serialization.JsonSerializer;
@Configuration
public class KafkaTestConfig {
// @Bean
// public MockConsumer<String, Object> createTestConsumer() {
// return new MockConsumer<>(OffsetResetStrategy.EARLIEST);
// }
//
// @Bean
// public Producer<String, Object> createTestProducer() {
// return new MockProducer<>(true, new StringSerializer(), new JsonSerializer());
// }
@Bean
public MockConsumer<String, Object> createTestConsumer() {
return new MockConsumer<>(OffsetResetStrategy.EARLIEST);
}
@Bean
public Producer<String, Object> createTestProducer() {
return new MockProducer<>(true, new StringSerializer(), new JsonSerializer());
}
}

View file

@ -1,41 +0,0 @@
package ru.spcex.clearing.balance.config;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import java.util.concurrent.CountDownLatch;
@Component
public class KafkaTestConsumer {
public static final String TOPIC_GALB = "launcher-GALB";
private static final Logger LOGGER = LoggerFactory.getLogger(KafkaTestConsumer.class);
private final String TOPIC_NAME = "com.madadipouya.kafka.user";
private CountDownLatch latch = new CountDownLatch(1);
private String payload;
@KafkaListener(topics = TOPIC_GALB)
public void receive(ConsumerRecord<?, ?> consumerRecord) {
LOGGER.info("received payload='{}'", consumerRecord.toString());
payload = consumerRecord.toString();
latch.countDown();
}
public CountDownLatch getLatch() {
return latch;
}
public void resetLatch() {
latch = new CountDownLatch(1);
}
public String getPayload() {
return payload;
}
}

View file

@ -1,104 +0,0 @@
package ru.spcex.clearing.balance.service;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.kafka.listener.KafkaMessageListenerContainer;
import org.springframework.kafka.listener.MessageListener;
import org.springframework.kafka.test.EmbeddedKafkaBroker;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.kafka.test.utils.ContainerTestUtils;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.spcex.clearing.balance.config.KafkaTestConsumer;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static ru.spcex.clearing.balance.config.KafkaTestConsumer.TOPIC_GALB;
@EmbeddedKafka//(partitions = 1, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"})
@SpringBootTest(properties = "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}")
@ExtendWith(SpringExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class EmbeddedKafkaTest {
static {
Path path = Paths.get("src", "main", "resources");
String currentPath = path.toAbsolutePath().toString();
System.setProperty("spring.config.location", currentPath + File.separator);
}
@Autowired
public KafkaTemplate<String, String> template;
BlockingQueue<ConsumerRecord<String, String>> records;
KafkaMessageListenerContainer<String, String> container;
@Autowired
private EmbeddedKafkaBroker embeddedKafkaBroker;
@Autowired
private KafkaTestConsumer consumer;
@BeforeEach
void setup() {
consumer.resetLatch();
}
@BeforeAll
void setUp() {
Map<String, Object> configs = new HashMap<>(KafkaTestUtils.consumerProps("consumer", "false", embeddedKafkaBroker));
DefaultKafkaConsumerFactory<String, String> consumerFactory = new DefaultKafkaConsumerFactory<>(configs, new StringDeserializer(), new StringDeserializer());
ContainerProperties containerProperties = new ContainerProperties(TOPIC_GALB);
container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);
records = new LinkedBlockingQueue<>();
container.setupMessageListener((MessageListener<String, String>) records::add);
container.start();
ContainerTestUtils.waitForAssignment(container, embeddedKafkaBroker.getPartitionsPerTopic());
}
@AfterAll
void tearDown() {
container.stop();
}
@Test
public void kafkaSetup_withTopic_ensureSendMessageIsReceived() throws Exception {
// Arrange
Map<String, Object> configs = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker));
Producer<String, String> producer = new DefaultKafkaProducerFactory<>(configs, new StringSerializer(), new StringSerializer()).createProducer();
String data = "Sending with default template";
//Act
producer.send(new ProducerRecord<>(TOPIC_GALB, "my-aggregate-id", data));
// producer.flush();
// template.send(TOPIC, data);
// Assert
ConsumerRecord<String, String> singleRecord = records.poll(10, TimeUnit.SECONDS);
boolean messageConsumed = consumer.getLatch()
.await(30, TimeUnit.SECONDS);
assertTrue(messageConsumed);
assertThat(consumer.getPayload(), containsString(data));
// assertThat(singleRecord).isNotNull();
// assertThat(singleRecord.key()).isEqualTo("my-aggregate-id");
// assertThat(singleRecord.value()).isEqualTo("{\"event\":\"Test Event\"}");
}
}

View file

@ -1,69 +0,0 @@
package ru.spcex.clearing.balance.service;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.test.EmbeddedKafkaBroker;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.spcex.clearing.balance.config.KafkaTestConsumer;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static ru.spcex.clearing.balance.config.KafkaTestConsumer.TOPIC_GALB;
@EmbeddedKafka//(partitions = 1, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"})
@SpringBootTest(properties = "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}")
@ExtendWith(SpringExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class Sdf08ServiceKafkaTest {
static {
Path path = Paths.get("src", "main", "resources");
String currentPath = path.toAbsolutePath().toString();
System.setProperty("spring.config.location", currentPath + File.separator);
}
@Autowired
public KafkaTemplate<String, String> template;
@Autowired
private EmbeddedKafkaBroker embeddedKafkaBroker;
@Autowired
private KafkaTestConsumer consumer;
@Test
public void newSDf08() throws Exception {
// Arrange
Map<String, Object> configs = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker));
Producer<String, String> producer = new DefaultKafkaProducerFactory<>(configs, new StringSerializer(), new StringSerializer()).createProducer();
String data = "Sending with default template";
//Act
producer.send(new ProducerRecord<>(TOPIC_GALB, "my-aggregate-id", data));
// producer.flush();
// template.send(TOPIC, data);
// Assert
boolean messageConsumed = consumer.getLatch()
.await(10, TimeUnit.SECONDS);
assertTrue(messageConsumed);
assertThat(consumer.getPayload(), containsString(data));
}
}

View file

@ -4,22 +4,22 @@ import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.objects.BusinessObject;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
public class LiabilitiesClaimsAssets extends BusinessObject {
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private Long companyId;
private Instant clearingDate;
private LocalDate clearingDate;
private Long accountId;
private String accountType;
private String account;
private BigDecimal liabilitiesQuantity;
private BigDecimal claimsQuantity;
private String currency;
private Instant settlementDate;
private Instant tradingDate;
private Instant refundDate;
private LocalDate settlementDate;
private LocalDate tradingDate;
private LocalDate refundDate;
private BigDecimal price;
private Long securityId;
private String tradingCode;
@ -42,11 +42,11 @@ public class LiabilitiesClaimsAssets extends BusinessObject {
this.companyId = value;
}
public Instant getClearingDate() {
public LocalDate getClearingDate() {
return clearingDate;
}
public void setClearingDate(Instant value) {
public void setClearingDate(LocalDate value) {
this.clearingDate = value;
}
@ -98,27 +98,27 @@ public class LiabilitiesClaimsAssets extends BusinessObject {
this.currency = value;
}
public Instant getSettlementDate() {
public LocalDate getSettlementDate() {
return settlementDate;
}
public void setSettlementDate(Instant value) {
public void setSettlementDate(LocalDate value) {
this.settlementDate = value;
}
public Instant getTradingDate() {
public LocalDate getTradingDate() {
return tradingDate;
}
public void setTradingDate(Instant value) {
public void setTradingDate(LocalDate value) {
this.tradingDate = value;
}
public Instant getRefundDate() {
public LocalDate getRefundDate() {
return refundDate;
}
public void setRefundDate(Instant value) {
public void setRefundDate(LocalDate value) {
this.refundDate = value;
}

View file

@ -0,0 +1,189 @@
package ru.clearing.classes.statics.data.misc;
import ru.clearing.classes.ConstSerializable;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
/**
* Сделки из Торговой системы
* <p>
* DB table: S_TRADE
**/
public class STrade extends SpcexObjectBase {
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private Long tradeNum;
private String secCode;
private Instant tradeDateTime;
private LocalDate settleDate;
private BigDecimal price;
private BigDecimal value;
private BigDecimal qty;
private BigDecimal accruedint;
private String firmId;
private String clientCode;
private BigDecimal exchangeCommission;
private String classCode;
private String operation;
private String issueAccount;
private String moneyAccount;
private String tradeType;
private Long daysToMatDate;
private String collateral;
private String settleCode;
public Long getTradeNum() {
return tradeNum;
}
public void setTradeNum(Long value) {
this.tradeNum = value;
}
public String getSecCode() {
return secCode;
}
public void setSecCode(String value) {
this.secCode = value;
}
public Instant getTradeDateTime() {
return tradeDateTime;
}
public void setTradeDateTime(Instant value) {
this.tradeDateTime = value;
}
public LocalDate getSettleDate() {
return settleDate;
}
public void setSettleDate(LocalDate value) {
this.settleDate = value;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal value) {
this.price = value;
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public BigDecimal getQty() {
return qty;
}
public void setQty(BigDecimal value) {
this.qty = value;
}
public BigDecimal getAccruedint() {
return accruedint;
}
public void setAccruedint(BigDecimal value) {
this.accruedint = value;
}
public String getFirmId() {
return firmId;
}
public void setFirmId(String value) {
this.firmId = value;
}
public String getClientCode() {
return clientCode;
}
public void setClientCode(String value) {
this.clientCode = value;
}
public BigDecimal getExchangeCommission() {
return exchangeCommission;
}
public void setExchangeCommission(BigDecimal value) {
this.exchangeCommission = value;
}
public String getClassCode() {
return classCode;
}
public void setClassCode(String value) {
this.classCode = value;
}
public String getOperation() {
return operation;
}
public void setOperation(String value) {
this.operation = value;
}
public String getIssueAccount() {
return issueAccount;
}
public void setIssueAccount(String value) {
this.issueAccount = value;
}
public String getMoneyAccount() {
return moneyAccount;
}
public void setMoneyAccount(String value) {
this.moneyAccount = value;
}
public String getTradeType() {
return tradeType;
}
public void setTradeType(String value) {
this.tradeType = value;
}
public Long getDaysToMatDate() {
return daysToMatDate;
}
public void setDaysToMatDate(Long value) {
this.daysToMatDate = value;
}
public String getCollateral() {
return collateral;
}
public void setCollateral(String value) {
this.collateral = value;
}
public String getSettleCode() {
return settleCode;
}
public void setSettleCode(String value) {
this.settleCode = value;
}
}

View file

@ -3,8 +3,11 @@ package ru.spcex.clearing.error;
import ru.spcex.platform.utils.enumeration.IEnumId;
public enum ClearingError implements IEnumId {
GeneralError(5400L),
RecordNotFound(5406L),
CompanyCreditCheck(5412L),
CompanyDebitCheck(5413L),
CompanyNotFound(5410L),
;
private final Long id;

View file

@ -0,0 +1,34 @@
package ru.spcex.clearing.error;
import ru.spcex.platform.utils.enumeration.EnumMessage;
public class ClearingException extends Exception {
final EnumMessage enumMsg;
public ClearingException(EnumMessage msg) {
this.enumMsg = msg;
}
public ClearingException(ClearingError code) {
this.enumMsg = new EnumMessage(code);
}
public ClearingException(ClearingError code, String message) {
super(code == null ? message : code.getId() + " " + message);
this.enumMsg = new EnumMessage(code);
}
public ClearingException(ClearingError code, String message, Throwable cause) {
super(code == null ? message : code.getId() + " " + message, cause);
this.enumMsg = new EnumMessage(code);
}
public ClearingException(String message, Throwable cause) {
super(message, cause);
this.enumMsg = new EnumMessage(ClearingError.GeneralError);
}
public EnumMessage getEnumMsg() {
return enumMsg;
}
}

View file

@ -0,0 +1,340 @@
package ru.spcex.clearing.service;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.execution.ExecutionDeposit;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.STrade;
import ru.clearing.classes.statics.data.security.Security;
import ru.spcex.clearing.error.ClearingError;
import ru.spcex.clearing.error.ClearingException;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.CoveredDealRegisterNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityNewRequest;
import ru.spcex.platform.enumeration.Allowed;
import ru.spcex.platform.enumeration.Market;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.log.ExceptionUtils;
import ru.spcex.platform.utils.time.TimeUtil;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
/**
* 1.35. executionDeposit - Сделки
* I - Изменение executionDeposit при получении новых сделок из ТС (s_trade)
*/
@Component
@EnableScheduling
public class ExecutionDepositComponent {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ImdgProvider imdgProvider;
private Imdg<STrade> sTradeImdg;
private Imdg<Security> securityImdg;
private Imdg<ExecutionDeposit> executionDepositImdg;
private Imdg<Company> companyImdg;
private Imdg<Account> accountImdg;
private Imdg<Listing> listingImdg;
private ImdgId idGenerator;
Producer<String, Object> kafka;
Long tradeNum;
Instant tradingDay;
@Autowired
public ExecutionDepositComponent(ImdgProvider imdgProvider, Producer<String, Object> kafka) {
this.imdgProvider = imdgProvider;
this.sTradeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_STrade, STrade.class);
this.securityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Security, Security.class);
this.executionDepositImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionDeposit, ExecutionDeposit.class);
this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
this.idGenerator = imdgProvider.getImdgIdGenerator();
this.kafka = kafka;
resetTradingDay();
}
/**
* Сбрасывать каждый день в 01:00:01 "0 1 0 1 * ?"
*/
@Scheduled(cron = "${clearing-service.scheduler.check-s-trade}")
public void resetTradingDay() {
Instant today = TimeUtil.localDateToInstant(LocalDate.now());
if (tradingDay == null || !tradingDay.equals(today)) {
tradeNum = -1L;
tradingDay = today;
}
log.info("Reset trading day for search STrade: tradeNum={}, tradeDat={}", tradeNum, tradingDay);
}
public void processNewTS() {
Long tradeNum = -1L; // todo уточнить как он обновляется
ImdgPredicateBuilder pb = sTradeImdg.predicateBuilder();
ImdgPredicate sql = pb.and(pb.greater("tradeNum", tradeNum), pb.greatEqual("tradeDateTime", tradingDay));
Collection<STrade> sTrades = sTradeImdg.getCollectionObjectsByPredicate(sql);
log.info("Found {} new s_trade with trade_num>{}", sTrades.size(), tradeNum);
if (sTrades.isEmpty()) {
log.info("No new sTrades.");
return;
}
// Выявление новых сделок необходимо выполнить следующие контрольные проверки:
// Проверить все инструменты.
{
Set<String> secCodesOfSTrade = sTrades.stream().map(STrade::getSecCode).filter(Objects::nonNull).collect(Collectors.toSet());
log.debug("Verify {} instruments for {} STrade's.", secCodesOfSTrade.size(), sTrades.size());
ImdgPredicate allIn = securityImdg.predicateBuilder().in("securitySymbol", secCodesOfSTrade.toArray(new String[0]));
Collection<Security> foundSecurities = securityImdg.getCollectionObjectsByPredicate(allIn);
Set<String> secCodesOfSecurity = foundSecurities.stream().map(Security::getSecuritySymbol).filter(Objects::nonNull).collect(Collectors.toSet());
if (secCodesOfSecurity.containsAll(secCodesOfSTrade)) {
log.debug("All {} Security found by {} secCodes from STrade",
secCodesOfSecurity.size(), secCodesOfSTrade.size());
} else {
HashSet<String> notFoundSymbol = new HashSet<>(secCodesOfSTrade);
notFoundSymbol.removeAll(secCodesOfSecurity);
log.info("Found only {} Security by {} secCodes from STrade. Not found: {}",
secCodesOfSecurity.size(), secCodesOfSTrade.size(), notFoundSymbol);
createNewSecurities(notFoundSymbol);
log.info("Stop till they all will be created");
auditMessage("В security нет записей с securitySymbol", notFoundSymbol);
return;
}
}
Long generationId = idGenerator.nextId();
log.info("generationId = {}", generationId);
for (STrade trade : sTrades) {
log.trace("Check s_trade[{}].tradeNum={}", trade.getId(), trade.getTradeNum());
Collection<ExecutionDeposit> existsEDeposit = executionDepositImdg.getCollectionObjectsByFieldValues(Map.of(
"exchangeExecutionId", trade.getTradeNum(),
"exchangeExecutionTime", trade.getTradeDateTime()
));
if (existsEDeposit.isEmpty()) {
log.trace("S_TRADE[{}] new", trade.getId());
ExecutionDeposit newED = null;
try {
newED = createExecutionDeposit(trade, Allowed.ALLOWED/*todo уточнить момент заполнения*/, generationId);
verification(newED);
executionDepositImdg.insert(newED);
sendNotification(newED);
} catch (ClearingException ce) {
auditMessage(ce);
} catch (Exception e) {
if (newED != null) {
newED.setCoverageStatus(Allowed.DENIED.getKey());
}
log.error("When create new ExecutionDeposit by STrade[{}]", trade.getId());
}
} else {
long[] idToLong = existsEDeposit.stream().mapToLong(ed -> ed.getId()).toArray();
log.warn("S_TRADE[{}] already has executionDeposit: {}", trade.getId(), Arrays.toString(idToLong));
}
}
Long newMaxTradeNum = sTrades.stream().mapToLong(STrade::getTradeNum).max().orElseGet(() -> tradeNum);
log.debug("Next tradeNum is {}", newMaxTradeNum);
}
protected void verification(ExecutionDeposit forED) throws ClearingException {
/*todo Рассчитанные в КС контрольные суммы (общее количество сделок и суммарный объем заключенных сделок в денежном выражении)
должны совпадать со значениями, рассчитанными Торговой системой:
count(execution[tradingDay]) = count (trade_arqua)
*/
// использовать ли VerificationResultComponent для сверки или здесь код добавить.
}
protected void auditMessage(ClearingException ce) {
log.error("AUDIT error code {}: {}", ce.getEnumMsg(), ce.getMessage());
}
protected void auditMessage(String message, Object... ids) {
String txt = message;
if (ids != null && ids.length > 0) {
txt += " object:" + Arrays.toString(ids);
}
log.error("audit \"clearing-service\", errorText: {}", txt);
}
/**
* в очередь kafka для модуля securities-service сообщение о добавлении инструмента с параметром securitySymbol=s_trade.sec_code
*
* @param newSymbolRequest
*/
protected void createNewSecurities(Collection<String> newSymbolRequest) {
final String destination = Consts.DESTINATION_MONEY_MARKET_SECURITY_NEW;
List<String> symbolRequests = new ArrayList<>(newSymbolRequest); // чтобы в случае ошибки отобразить номер в логе
List<Future<RecordMetadata>> sendAll = new ArrayList<>(symbolRequests.size());
for (String newSymbol : symbolRequests) {
if (newSymbol == null || newSymbol.isEmpty()) {
log.warn("Empty SecuritySumbol");
} else {
MoneyMarketSecurityNewRequest requestPayload = new MoneyMarketSecurityNewRequest();
requestPayload.setSecuritySymbol(newSymbol);
BaseRequest<Object> request = new BaseRequest<>();
request.setId(idGenerator.nextId());
request.setActionType(ActionType.NEW);
request.setRequestPayload(requestPayload);
// saveRequestToStorage(destination, request); //сохраняет данные о запросе в хранилище
log.trace("Send to {} new symbol \"{}\" ", destination, newSymbol);
Future<RecordMetadata> send = kafka.send(new ProducerRecord<>(destination, request));
sendAll.add(send);
}
}
int i = 0;
for (Future<RecordMetadata> future : sendAll) {
try {
future.get(); // get exception
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
String about = i < symbolRequests.size() ? symbolRequests.get(i) : "(out of range i=" + i + ")";
log.warn("Thread interrupted! On send symbol \"{}\"", about);
throw new RuntimeException(e);
} catch (ExecutionException e) {
String about = i < symbolRequests.size() ? symbolRequests.get(i) : "(out of range i=" + i + ")";
log.error("Error send message for symbol \"{}\" to {}: {}", destination,
about, ExceptionUtils.getStackTrace(e.getCause() == null ? e : e.getCause()));
}
i++;
}
}
protected void sendNotification(ExecutionDeposit forED) {
final String destination = Consts.REGISTRY_COVERED_DEAL_REGISTER_NEW;
CoveredDealRegisterNewRequest requestPayload = new CoveredDealRegisterNewRequest();
requestPayload.setExecutionId(forED.getId());
// requestPayload.setCompanyFullName(forED.getCompanyFullName());
requestPayload.setTradingDate(forED.getTradingDate());
requestPayload.setExchangeExecutionId(forED.getExchangeExecutionId());
requestPayload.setExchangeExecutionTime(forED.getExchangeExecutionTime());
requestPayload.setSecuritySymbol(forED.getSecuritySymbol());
requestPayload.setSecurityFullName(forED.getSecurityFullName());
// requestPayload.setSellerFullName(forED.getSellerFullName());
// requestPayload.setSellerClearingCode(forED.getSellerClearingCode());
// String requestPayload.setSellerAccount(forED.getAccountId());
// String requestPayload.setBuyerFullName(forED.getBuyerFullName());
// requestPayload.setBuyerClearingCode(forED.getBuyerClearingCode());
// String requestPayload.setBuyerAccount(forED.getBuyerAccount());
// BigDecimal requestPayload.setAmount(forED.getAmount());
requestPayload.setId(idGenerator.nextId());
requestPayload.setCreatedAt(forED.getCreated());
requestPayload.setUpdatedAt(forED.getUpdated());
requestPayload.setClearingDate(forED.getClearingDate());
BaseRequest<Object> request = new BaseRequest<>();
request.setId(idGenerator.nextId());
request.setActionType(ActionType.NEW);
request.setRequestPayload(requestPayload);
log.trace("Send to {} new ExecutionDeposit[{}]", destination, forED.getId());
Future<RecordMetadata> send = kafka.send(new ProducerRecord<>(destination, request));
try {
send.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
protected ExecutionDeposit createExecutionDeposit(STrade sTrade,
Allowed coverageStatus, Long sessionId) throws ClearingException {
Account account = accountImdg.getSingleObjectByFieldValues(Map.of("account", sTrade.getMoneyAccount()));
Security security = securityImdg.getSingleObjectByFieldValues(Map.of("securitySymbol", sTrade.getSecCode()));
if (security == null) {
log.warn("security securitySymbol=\"{}\" not found", sTrade.getSecCode());
throw new ClearingException(new EnumMessage(ClearingError.RecordNotFound, sTrade.getSecCode()));
}
Listing listing = null;
if (security != null) {
listing = listingImdg.getSingleObjectByFieldValues(Map.of("securityId", security.getId()));
}
Company company = companyImdg.getSingleObjectByFieldValues(Map.of("tradingCode", sTrade.getFirmId()));
if (company == null) {
throw new ClearingException(new EnumMessage(ClearingError.CompanyNotFound, sTrade.getFirmId()));
}
return createExecutionDeposit(sTrade, account, listing, company, security, coverageStatus, sessionId);
}
private ExecutionDeposit createExecutionDeposit(STrade sTrade, Account account, Listing listing,
Company company, Security security,
Allowed coverageStatus, Long sessionId) {
ExecutionDeposit eDeposit = new ExecutionDeposit();
eDeposit.setId(idGenerator.nextId());
final Instant now = Instant.now();
final LocalDate nowDay = TimeUtil.toLocalDate(now);
eDeposit.setCreated(now);
eDeposit.setTradingDate(nowDay);
eDeposit.setClearingDate(nowDay);
eDeposit.setExchangeExecutionId(sTrade.getTradeNum());
eDeposit.setExchangeExecutionTime(sTrade.getTradeDateTime());
if (account != null) {
eDeposit.setAccountId(account.getId());
}
eDeposit.setMarket(Market.mkrs.getKey());
eDeposit.setPrice(sTrade.getPrice());
eDeposit.setLots(sTrade.getQty());
if (listing != null && listing.getLotSize() != null && eDeposit.getLots() != null) {
BigDecimal quantity = eDeposit.getLots().multiply(listing.getLotSize());
eDeposit.setQuantity(quantity);
}
eDeposit.setFirstLegAmount(sTrade.getValue());
eDeposit.setSecondLegAmount(sTrade.getValue());
//eDeposit.setInterestAmount(null);
eDeposit.setSide(sTrade.getOperation());//Символьный код по справочнику moneyFlowSide), соответствующий значению из s_trade.operation (sTrade.getOperation())
eDeposit.setSettlementCurrency("RUB"); // (справочник currencyCode)
eDeposit.setCompanyId(company.getId());
eDeposit.setDuration(sTrade.getDaysToMatDate());
eDeposit.setFirstLegSettlementDate(nowDay);
eDeposit.setSecondLegSettlementDate(sTrade.getSettleDate());
//eDeposit.setFirstLegSettlementCode(null);
//eDeposit.setSecondLegSettlementCode(null);
eDeposit.setSecurityFullName(security.getFullName());
eDeposit.setSecuritySymbol(security.getSecuritySymbol());
eDeposit.setSecurityId(security.getId());
//eDeposit.setCounterPartyId(null);
eDeposit.setCoverageStatus(coverageStatus == null ? null : coverageStatus.getKey()); // Заполняется по справочнику allowed в результате расчета требований и обязательств. TODO
eDeposit.setSessionId(sessionId);
return eDeposit;
}
}

View file

@ -0,0 +1,33 @@
package ru.spcex.clearing.service;
import org.apache.kafka.clients.consumer.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.platform.enumeration.Task;
@Service
public class LauncherCommandReceiver extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ClearingService clearingService;
@Autowired
public LauncherCommandReceiver(Consumer<String, Object> kafkaQueue,
ClearingService clearingService) {
super(kafkaQueue);
this.clearingService = clearingService;
}
@Override
public void afterPropertiesSet() {
callback(LauncherCommandRequest.class)
.setConsumer(action -> clearingService.executeVerification())
.forDestination(Task.createOrderConfirm.topic(), callbacks::put); // CORC
init();
}
}

View file

@ -19,4 +19,5 @@ clearing-service.kafka-producer.batch-size=16384
clearing-service.kafka-producer.linger-ms=1
clearing-service.kafka-producer.buffer-memory=33554432
clearing-service.scheduler.check-payment-instruction=*/5 * * * * *
clearing-service.scheduler.check-payment-instruction=*/5 * * * * *
clearing-service.scheduler.check-s-trade=0 1 0 1 * ?

View file

@ -45,16 +45,16 @@ public class LiabilitiesClaimsAssetsMapStore extends TemplateMapStore<Liabilitie
object.setCompanyId(resultSet.getObject("COMPANY_ID", Long.class));
object.setCreated(getInstantFromTimestamp(resultSet, "CREATED_AT"));
object.setUpdated(getInstantFromTimestamp(resultSet, "UPDATED_AT"));
object.setClearingDate(getInstantFromTimestamp(resultSet, "CLEARING_DATE"));
object.setClearingDate(getLocalDateFromSqlDate(resultSet, "CLEARING_DATE"));
object.setAccountId(resultSet.getObject("ACCOUNT_ID", Long.class));
object.setAccountType(resultSet.getObject("ACCOUNT_TYPE", String.class));
object.setAccount(resultSet.getObject("ACCOUNT", String.class));
object.setLiabilitiesQuantity(resultSet.getObject("LIABILITIES_QUANTITY", BigDecimal.class));
object.setClaimsQuantity(resultSet.getObject("CLAIMS_QUANTITY", BigDecimal.class));
object.setCurrency(resultSet.getObject("CURRENCY", String.class));
object.setSettlementDate(getInstantFromTimestamp(resultSet, "SETTLEMENT_DATE"));
object.setTradingDate(getInstantFromTimestamp(resultSet, "TRADING_DATE"));
object.setRefundDate(getInstantFromTimestamp(resultSet, "REFUND_DATE"));
object.setSettlementDate(getLocalDateFromSqlDate(resultSet, "SETTLEMENT_DATE"));
object.setTradingDate(getLocalDateFromSqlDate(resultSet, "TRADING_DATE"));
object.setRefundDate(getLocalDateFromSqlDate(resultSet, "REFUND_DATE"));
object.setPrice(resultSet.getObject("PRICE", BigDecimal.class));
object.setSecurityId(resultSet.getObject("SECURITY_ID", Long.class));
object.setTradingCode(resultSet.getObject("TRADING_CODE", String.class));
@ -78,16 +78,16 @@ public class LiabilitiesClaimsAssetsMapStore extends TemplateMapStore<Liabilitie
object.getCompanyId(),
TimeUtil.toDateFromInstant(object.getCreated()),
TimeUtil.toDateFromInstant(object.getUpdated()),
TimeUtil.toDateFromInstant(object.getClearingDate()),
TimeUtil.toDateFromLocalDate(object.getClearingDate()),
object.getAccountId(),
object.getAccountType(),
object.getAccount(),
object.getLiabilitiesQuantity(),
object.getClaimsQuantity(),
object.getCurrency(),
TimeUtil.toDateFromInstant(object.getSettlementDate()),
TimeUtil.toDateFromInstant(object.getTradingDate()),
TimeUtil.toDateFromInstant(object.getRefundDate()),
TimeUtil.toDateFromLocalDate(object.getSettlementDate()),
TimeUtil.toDateFromLocalDate(object.getTradingDate()),
TimeUtil.toDateFromLocalDate(object.getRefundDate()),
object.getPrice(),
object.getSecurityId(),
object.getTradingCode(),

View file

@ -0,0 +1,94 @@
package ru.spcex.clearing.imdg.object;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import ru.clearing.classes.statics.data.misc.STrade;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.imdg.base.TemplateMapStore;
import ru.spcex.platform.utils.time.TimeUtil;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
@Component
public class STradeMapStore extends TemplateMapStore<STrade> {
public STradeMapStore(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
public String getMapName() {
return IMDGDistributedNames.Map_STrade;
}
@Override
public String getTableName() {
return "S_TRADE";
}
@Override
public String[] getFields() {
return new String[]{
"ID", "TRADE_NUM", "SEC_CODE", "TRADE_DATE_TIME", "SETTLE_DATE", "PRICE", "VALUE", "QTY", "ACCRUEDINT",
"FIRM_ID", "CLIENT_CODE", "EXCHANGE_COMMISSION", "CLASS_CODE", "OPERATION", "ISSUE_ACCOUNT",
"MONEY_ACCOUNT", "TRADE_TYPE", "DAYS_TO_MAT_DATE", "COLLATERAL", "SETTLE_CODE"
};
}
@Override
public STrade objectReader(ResultSet resultSet) throws SQLException {
STrade object = new STrade();
object.setId(resultSet.getObject("ID", Long.class));
object.setTradeNum(resultSet.getObject("TRADE_NUM", Long.class));
object.setSecCode(resultSet.getObject("SEC_CODE", String.class));
object.setTradeDateTime(getInstantFromTimestamp(resultSet, "TRADE_DATE_TIME"));
object.setSettleDate(resultSet.getObject("SETTLE_DATE", LocalDate.class));
object.setPrice(resultSet.getObject("PRICE", BigDecimal.class));
object.setValue(resultSet.getObject("VALUE", BigDecimal.class));
object.setQty(resultSet.getObject("QTY", BigDecimal.class));
object.setAccruedint(resultSet.getObject("ACCRUEDINT", BigDecimal.class));
object.setFirmId(resultSet.getObject("FIRM_ID", String.class));
object.setClientCode(resultSet.getObject("CLIENT_CODE", String.class));
object.setExchangeCommission(resultSet.getObject("EXCHANGE_COMMISSION", BigDecimal.class));
object.setClassCode(resultSet.getObject("CLASS_CODE", String.class));
object.setOperation(resultSet.getObject("OPERATION", String.class));
object.setIssueAccount(resultSet.getObject("ISSUE_ACCOUNT", String.class));
object.setMoneyAccount(resultSet.getObject("MONEY_ACCOUNT", String.class));
object.setTradeType(resultSet.getObject("TRADE_TYPE", String.class));
object.setDaysToMatDate(resultSet.getObject("DAYS_TO_MAT_DATE", Long.class));
object.setCollateral(resultSet.getObject("COLLATERAL", String.class));
object.setSettleCode(resultSet.getObject("SETTLE_CODE", String.class));
return object;
}
@Override
public Object[] objectToField(STrade object) {
Object[] args = new Object[]{
object.getId(),
object.getTradeNum(),
object.getSecCode(),
TimeUtil.toDateFromInstant(object.getTradeDateTime()),
object.getSettleDate(),
object.getPrice(),
object.getValue(),
object.getQty(),
object.getAccruedint(),
object.getFirmId(),
object.getClientCode(),
object.getExchangeCommission(),
object.getClassCode(),
object.getOperation(),
object.getIssueAccount(),
object.getMoneyAccount(),
object.getTradeType(),
object.getDaysToMatDate(),
object.getCollateral(),
object.getSettleCode()
};
return args;
}
}

View file

@ -12,11 +12,15 @@ import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
import ru.clearing.classes.statics.data.journal.InDocumentJournal;
import ru.clearing.classes.statics.data.journal.ManagementJournal;
import ru.clearing.classes.statics.data.journal.OutDocumentJournal;
import ru.clearing.classes.statics.data.liabilities.LiabilitiesClaimsAssets;
import ru.clearing.classes.statics.data.liabilities.LiabilitiesClaimsMoney;
import ru.clearing.classes.statics.data.messages.ErrorText;
import ru.clearing.classes.statics.data.misc.*;
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.clearing.classes.statics.data.profile.ProfileDocument;
import ru.clearing.classes.statics.data.register.OrderRegister;
import ru.clearing.classes.statics.data.register.ReportRegister;
import ru.clearing.classes.statics.data.scheduler.*;
import ru.clearing.classes.statics.data.sdf.*;
import ru.clearing.classes.statics.data.security.Security;
@ -66,6 +70,10 @@ public class RunnableMapNamesForTesting {
usingIgnoringFieldsComparator("profile.clearingCode", "profile.fullName", "profile.registrationCode", "profile.shortName", "profile.tradingCode")));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ErrorText, ErrorText.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_Launcher, Launcher.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_LiabilitiesClaimsAssets, LiabilitiesClaimsAssets.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_LiabilitiesClaimsMoney, LiabilitiesClaimsMoney.class,
new SettingOperation("setClaimsAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("04.92")}),
new SettingOperation("setLiabilitiesAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("06.26")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_Listing, Listing.class,
new SettingOperation("setLotSize", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("21.11")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ManagementJournal, ManagementJournal.class));
@ -78,11 +86,6 @@ public class RunnableMapNamesForTesting {
new SettingOperation("setAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("23.22")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_UserConnect, UserConnect.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_User, User.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_VerificationResult, VerificationResult.class,
new SettingOperation("setDiffSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("13.22")}),
new SettingOperation("setInSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("14.22")}),
new SettingOperation("setOutExtSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("15.22")}),
new SettingOperation("setOutIntSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("19.22")})));
//dictionary
dictionaryObjectForCheckMapStores.add(new DictionaryObjectForCheckMapStore<>(IMDGDistributedNames.Map_AccountStatusDictionary, AccountStatusDictionary.class));
@ -128,12 +131,26 @@ public class RunnableMapNamesForTesting {
//object
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_AccountRouting, AccountRouting.class));
// businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_AdmittedDealRegister, AdmittedDealRegister.class,
// new SettingOperation("setAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("19.12")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_BankAccount, BankAccount.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ClearMemberRegister, ClearMemberRegister.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_CompanyRoleSet, CompanyRoleSet.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_Contact, Contact.class));
// businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ContractRegister, ContractRegister.class));
// businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_CoveredDealRegister, CoveredDealRegister.class,
// new SettingOperation("setAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("11.11")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_Currency, Currency.class));
// businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_DealRegister, DealRegister.class,
//// new SettingOperation("setAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("11.11")})));
// businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ExecutionDeposit, ExecutionDeposit.class,
// new SettingOperation("setFirstLegAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("03.22")}),
// new SettingOperation("setSecondLegAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("03.33")}),
// new SettingOperation("setInterestAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("04.22")}),
// new SettingOperation("setLots", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("05.22")}),
// new SettingOperation("setQuantity", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("09.22")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_InDocumentJournal, InDocumentJournal.class,
new SettingOperation("setAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("22.12")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_InformationAccount, InformationAccount.class));
@ -141,11 +158,13 @@ public class RunnableMapNamesForTesting {
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class,
new SettingOperation("setNominalValue", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("25.25")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_Notification, Notification.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_OrderRegister, OrderRegister.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_OutDocumentJournal, OutDocumentJournal.class,
new SettingOperation("setAmount", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("28.28")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_PlannerAllToday, PlannerAllToday.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_ReportRegister, ReportRegister.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_SDf01, SDf01.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_SDf02, SDf02.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_SDf03, SDf03.class));
@ -161,7 +180,16 @@ public class RunnableMapNamesForTesting {
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_SDf17, SDf17.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_SDf18, SDf18.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_Session, Session.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_STrade, STrade.class,
new SettingOperation("setQty", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("23.92")}),
new SettingOperation("setValue", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("24.92")}),
new SettingOperation("setExchange_commission", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("26.26")})));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_UserRoleSession, UserRoleSession.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_UserSettings, UserSettings.class));
businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_VerificationResult, VerificationResult.class,
new SettingOperation("setDiffSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("13.22")}),
new SettingOperation("setInSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("14.22")}),
new SettingOperation("setOutExtSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("15.22")}),
new SettingOperation("setOutIntSum", new Class[]{BigDecimal.class}, new Object[]{new BigDecimal("19.22")})));
}
}

View file

@ -1,4 +1,4 @@
-- DB version: 2.4.4.0
-- DB version: 2.4.0.7
/* Dictionaries */
-- chargeDirection - Направление начисления комиссии
@ -1532,7 +1532,7 @@ COMMENT ON COLUMN ACCOUNT_BALANCE.COMPANY_ID IS 'Наименование уча
COMMENT ON COLUMN ACCOUNT_BALANCE.ACCOUNT_ID IS 'Наименование счета (linked to account)';
COMMENT ON COLUMN ACCOUNT_BALANCE.ACCOUNT_TYPE IS 'Тип счета (linked to account)';
COMMENT ON COLUMN ACCOUNT_BALANCE.ACCOUNT_TYPE IS 'Тип счета (linked to accountType)';
COMMENT ON COLUMN ACCOUNT_BALANCE.ACCOUNT IS 'Наименование счета';
@ -1586,7 +1586,7 @@ COMMENT ON COLUMN ACCOUNT_BALANCE_HISTORY.COMPANY_ID IS 'Наименовани
COMMENT ON COLUMN ACCOUNT_BALANCE_HISTORY.ACCOUNT_ID IS 'Наименование счета (linked to account)';
COMMENT ON COLUMN ACCOUNT_BALANCE_HISTORY.ACCOUNT_TYPE IS 'Тип счета (linked to account)';
COMMENT ON COLUMN ACCOUNT_BALANCE_HISTORY.ACCOUNT_TYPE IS 'Тип счета (linked to accountType)';
COMMENT ON COLUMN ACCOUNT_BALANCE_HISTORY.ACCOUNT IS 'Наименование счета';
@ -3414,110 +3414,5 @@ COMMENT ON COLUMN MONEY_MARKET_SESSION_HISTORY.USER_ID IS 'Наименован
/* views */
-- Data types

View file

@ -12,6 +12,7 @@ import ru.spcex.clearing.reports.reports.ReportId;
import ru.spcex.clearing.reports.services.builders.XMLReportBuilder;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.IEnumKey;
import ru.spcex.platform.utils.log.ExceptionUtils;
import java.io.File;
import java.io.IOException;
@ -74,12 +75,20 @@ public class ReportsServiceCommand implements InitializingBean {
public void generateReportAll(@Nullable String reportGroup, LocalDate startDate, LocalDate endDate) throws IOException {
for (ReportWithPeriodCollector<?> reportDataCollector : allPeriodReports) {
if (reportGroup == null || QUEUE_RUN_REPORT_COMMAND.equals(reportGroup)) {
makeSingleReport(reportDataCollector, startDate, endDate);
try {
makeSingleReport(reportDataCollector, startDate, endDate);
} catch (Exception e) {
log.error("Error generate report of type {}: {}", reportDataCollector, ExceptionUtils.getStackTrace(e));
}
}
}
for (SimpleReportCollector<?> reportDataCollector : allSimpleReports) {
if (reportGroup == null || QUEUE_RUN_DAILY_REPORT_COMMAND.equals(reportGroup)) {
makeSingleReport(reportDataCollector);
try {
makeSingleReport(reportDataCollector);
} catch (Exception e) {
log.error("Error generate report of type {}: {}", reportDataCollector, ExceptionUtils.getStackTrace(e));
}
}
}
}

View file

@ -68,6 +68,10 @@ public class ReportBR_0420314_P2_Collector extends ReportWithPeriodCollector<Rep
final Long companyId = entry.getKey();
List<PaymentInstruction> paymentInstructionsByCompany = entry.getValue();
Company company = companyImdg.getSingleObjectByID(companyId);
if (company == null) {
log.warn("Company not found, id={}", companyId);
continue;
}
ProfileDocument profileDocumentCntr = profileDocumentImdg.getSingleObjectByFieldValues(Map.of(
"companyId", companyId,
"documentType", DocumentTypes.cntr.getKey()

View file

@ -73,7 +73,7 @@ public class ReportBR_0420318_Collector extends ReportWithPeriodCollector<Report
for (LiabilitiesClaimsAssets liability : liabilitiesByCompany) {
final String currencyCode = liability.getCurrency();
Instant liabilitiesClaimsAssets_settlementDate = null;
LocalDate liabilitiesClaimsAssets_settlementDate = null;
if (checkCategoryB) {
liabilitiesClaimsAssets_settlementDate = liability.getRefundDate();
}

View file

@ -2,10 +2,12 @@ package ru.spcex.clearing.scheduler.service;
import org.apache.kafka.clients.consumer.Consumer;
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.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.scheduler.Launcher;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
@ -20,14 +22,17 @@ import java.time.Instant;
import static ru.spcex.platform.utils.enumeration.IEnumKey.getEnumByKey;
@Service
public class LauncherService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<Launcher> launcherMap;
private final Producer<String, Object> kafkaProducer;
@Autowired
public LauncherService(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider) {
super(kafkaQueue, kafkaProducer);
this.kafkaProducer = kafkaProducer;
this.launcherMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Launcher, Launcher.class);
}
@ -53,6 +58,7 @@ public class LauncherService extends QueueConsumer implements InitializingBean {
launcher.setUpdated(created);
launcherMap.insert(launcher);
log.debug("successfully processed, new id {}", launcher.getId());
kafkaProducer.send(new ProducerRecord<>("launcher-" + launcher.getTask(), req));
}
}

View file

@ -121,6 +121,7 @@ public final class IMDGDistributedNames {
public static final String Map_ContractRegister = "Map_ContractRegister";
public static final String Map_OrderRegister = "Map_OrderRegister";
public static final String Map_VerificationResult = "Map_VerificationResult";
public static final String Map_STrade = "Map_STrade";
public static final String MAP_SEQUENCE_NAME = "MAP_SEQUENCE_NAME";

View file

@ -6,9 +6,12 @@ public class LauncherCommandRequest {
@JsonProperty
private Long userId;
@JsonProperty
private String taskName;
@JsonProperty
private Long companyId;
@JsonProperty
private Long securityId;
public Long getUserId() {
@ -26,4 +29,20 @@ public class LauncherCommandRequest {
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public Long getSecurityId() {
return securityId;
}
public void setSecurityId(Long securityId) {
this.securityId = securityId;
}
}