diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/scheduler/LauncherController.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/scheduler/LauncherController.java index a6e7bb993..f0dcfa17f 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/scheduler/LauncherController.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/scheduler/LauncherController.java @@ -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) { diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/schedule/LauncherNew.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/schedule/LauncherNew.java index ce810d0e8..31ceac638 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/schedule/LauncherNew.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/schedule/LauncherNew.java @@ -19,6 +19,12 @@ public class LauncherNew implements IAction { @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 { } 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 { 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; + } } diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.xml b/clearing-parent/backend-api/src/main/resources/meta/meta.xml index f8f91c229..058667e6d 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.xml @@ -1576,7 +1576,7 @@ - + diff --git a/clearing-parent/balance-service/pom.xml b/clearing-parent/balance-service/pom.xml index 5b4cd23de..d49af4c57 100644 --- a/clearing-parent/balance-service/pom.xml +++ b/clearing-parent/balance-service/pom.xml @@ -14,7 +14,6 @@ 17 17 - 3.0.1 @@ -57,23 +56,6 @@ assertj-core test - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.kafka - spring-kafka-test - 2.8.8 - test - - - org.springframework.kafka - spring-kafka - 2.8.8 - diff --git a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/KafkaTestConfig.java b/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/KafkaTestConfig.java index 256267d20..b56fef2b1 100644 --- a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/KafkaTestConfig.java +++ b/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/KafkaTestConfig.java @@ -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 createTestConsumer() { -// return new MockConsumer<>(OffsetResetStrategy.EARLIEST); -// } -// -// @Bean -// public Producer createTestProducer() { -// return new MockProducer<>(true, new StringSerializer(), new JsonSerializer()); -// } + @Bean + public MockConsumer createTestConsumer() { + return new MockConsumer<>(OffsetResetStrategy.EARLIEST); + } + + @Bean + public Producer createTestProducer() { + return new MockProducer<>(true, new StringSerializer(), new JsonSerializer()); + } } diff --git a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/KafkaTestConsumer.java b/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/KafkaTestConsumer.java deleted file mode 100644 index 502e8a50a..000000000 --- a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/config/KafkaTestConsumer.java +++ /dev/null @@ -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; - } - -} diff --git a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/service/EmbeddedKafkaTest.java b/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/service/EmbeddedKafkaTest.java deleted file mode 100644 index 8c5b3dd79..000000000 --- a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/service/EmbeddedKafkaTest.java +++ /dev/null @@ -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 template; - BlockingQueue> records; - KafkaMessageListenerContainer container; - @Autowired - private EmbeddedKafkaBroker embeddedKafkaBroker; - @Autowired - private KafkaTestConsumer consumer; - - @BeforeEach - void setup() { - consumer.resetLatch(); - } - - @BeforeAll - void setUp() { - Map configs = new HashMap<>(KafkaTestUtils.consumerProps("consumer", "false", embeddedKafkaBroker)); - DefaultKafkaConsumerFactory 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) records::add); - container.start(); - ContainerTestUtils.waitForAssignment(container, embeddedKafkaBroker.getPartitionsPerTopic()); - } - - @AfterAll - void tearDown() { - container.stop(); - } - - @Test - public void kafkaSetup_withTopic_ensureSendMessageIsReceived() throws Exception { - // Arrange - Map configs = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker)); - Producer 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 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\"}"); - } -} \ No newline at end of file diff --git a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/service/Sdf08ServiceKafkaTest.java b/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/service/Sdf08ServiceKafkaTest.java deleted file mode 100644 index bc17da0da..000000000 --- a/clearing-parent/balance-service/src/test/java/ru/spcex/clearing/balance/service/Sdf08ServiceKafkaTest.java +++ /dev/null @@ -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 template; - - @Autowired - private EmbeddedKafkaBroker embeddedKafkaBroker; - @Autowired - private KafkaTestConsumer consumer; - - @Test - public void newSDf08() throws Exception { - // Arrange - Map configs = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker)); - Producer 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)); - } -} \ No newline at end of file diff --git a/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/liabilities/LiabilitiesClaimsAssets.java b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/liabilities/LiabilitiesClaimsAssets.java index 758bebfbb..a7643a8ba 100644 --- a/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/liabilities/LiabilitiesClaimsAssets.java +++ b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/liabilities/LiabilitiesClaimsAssets.java @@ -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; } diff --git a/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/misc/STrade.java b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/misc/STrade.java new file mode 100644 index 000000000..f49c7b224 --- /dev/null +++ b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/misc/STrade.java @@ -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; + +/** + * Сделки из Торговой системы + *

+ * 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; + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java index dfaacf56d..2e9d0341c 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingError.java @@ -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; diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingException.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingException.java new file mode 100644 index 000000000..e70bf1f67 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/error/ClearingException.java @@ -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; + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/ExecutionDepositComponent.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/ExecutionDepositComponent.java new file mode 100644 index 000000000..bbe554b3a --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/ExecutionDepositComponent.java @@ -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 sTradeImdg; + private Imdg securityImdg; + private Imdg executionDepositImdg; + private Imdg companyImdg; + private Imdg accountImdg; + private Imdg

listingImdg; + + private ImdgId idGenerator; + Producer kafka; + + Long tradeNum; + Instant tradingDay; + + + @Autowired + public ExecutionDepositComponent(ImdgProvider imdgProvider, Producer 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 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 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 foundSecurities = securityImdg.getCollectionObjectsByPredicate(allIn); + Set 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 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 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 newSymbolRequest) { + final String destination = Consts.DESTINATION_MONEY_MARKET_SECURITY_NEW; + List symbolRequests = new ArrayList<>(newSymbolRequest); // чтобы в случае ошибки отобразить номер в логе + List> 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 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 send = kafka.send(new ProducerRecord<>(destination, request)); + sendAll.add(send); + } + } + int i = 0; + for (Future 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 request = new BaseRequest<>(); + request.setId(idGenerator.nextId()); + request.setActionType(ActionType.NEW); + request.setRequestPayload(requestPayload); + log.trace("Send to {} new ExecutionDeposit[{}]", destination, forED.getId()); + Future 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; + } + +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/LauncherCommandReceiver.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/LauncherCommandReceiver.java new file mode 100644 index 000000000..06d5aa4ef --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/LauncherCommandReceiver.java @@ -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 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(); + } +} diff --git a/clearing-parent/clearing-service/src/main/resources/application.properties b/clearing-parent/clearing-service/src/main/resources/application.properties index af4ebcf34..e0908f94a 100644 --- a/clearing-parent/clearing-service/src/main/resources/application.properties +++ b/clearing-parent/clearing-service/src/main/resources/application.properties @@ -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 * * * * * \ No newline at end of file +clearing-service.scheduler.check-payment-instruction=*/5 * * * * * +clearing-service.scheduler.check-s-trade=0 1 0 1 * ? diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessobject/LiabilitiesClaimsAssetsMapStore.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessobject/LiabilitiesClaimsAssetsMapStore.java index c940295bb..c9b1fc27f 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessobject/LiabilitiesClaimsAssetsMapStore.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessobject/LiabilitiesClaimsAssetsMapStore.java @@ -45,16 +45,16 @@ public class LiabilitiesClaimsAssetsMapStore extends TemplateMapStore { + + 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; + } + +} diff --git a/clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/structure/RunnableMapNamesForTesting.java b/clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/structure/RunnableMapNamesForTesting.java index 0ce9ebe55..d53944c78 100644 --- a/clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/structure/RunnableMapNamesForTesting.java +++ b/clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/structure/RunnableMapNamesForTesting.java @@ -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")}))); } } diff --git a/clearing-parent/imdg/src/test/resources/ddl.sql b/clearing-parent/imdg/src/test/resources/ddl.sql index 3c8b20210..20af99fb4 100644 --- a/clearing-parent/imdg/src/test/resources/ddl.sql +++ b/clearing-parent/imdg/src/test/resources/ddl.sql @@ -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 \ No newline at end of file diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/ReportsServiceCommand.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/ReportsServiceCommand.java index 260a368d0..499228968 100644 --- a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/ReportsServiceCommand.java +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/ReportsServiceCommand.java @@ -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)); + } } } } diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420314_P2_Collector.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420314_P2_Collector.java index 027135ddc..46bacd498 100644 --- a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420314_P2_Collector.java +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420314_P2_Collector.java @@ -68,6 +68,10 @@ public class ReportBR_0420314_P2_Collector extends ReportWithPeriodCollector 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() diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420318_Collector.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420318_Collector.java index f1845f848..2dd08ed64 100644 --- a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420318_Collector.java +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/collector/ReportBR_0420318_Collector.java @@ -73,7 +73,7 @@ public class ReportBR_0420318_Collector extends ReportWithPeriodCollector launcherMap; + private final Producer kafkaProducer; @Autowired public LauncherService(Consumer kafkaQueue, Producer 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)); } } diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java index f4773bb43..149c793b2 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java @@ -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"; diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/LauncherCommandRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/LauncherCommandRequest.java index 4382eecb7..b05686017 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/LauncherCommandRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/LauncherCommandRequest.java @@ -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; + } }