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

This commit is contained in:
psemenkov 2022-11-02 12:51:58 +03:00
commit 91cba070f6
353 changed files with 17506 additions and 4301 deletions

2
.gitignore vendored
View file

@ -3,3 +3,5 @@ target
*.iml
logs
tmp_notes.**
tmp
clearing-parent/backend-api/src/main/resources/meta.json

2
build_without_tests.cmd Normal file
View file

@ -0,0 +1,2 @@
start mvn clean install -Dmaven.test.skip=true -P distributive
pause

View file

@ -1,18 +1,50 @@
package ru.spcex.clearing.account.config;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import ru.spcex.clearing.account.config.settings.AccountServiceSettings;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.config.KafkaConsumerFactory;
import ru.spcex.clearing.platform.messaging.config.KafkaProducerFactory;
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
@Configuration
public class KafkaConfig {
@Autowired
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public Consumer<String, Object> createProducer(AccountServiceSettings settings) {
return KafkaConsumerFactory.consumer(settings.getKafka());
public Consumer<String, Object> createConsumer(AccountServiceSettings settings) {
return KafkaConsumerFactory.consumer(settings.getKafkaConsumer());
}
@Autowired
@Bean
public Producer<String, Object> createProducer(AccountServiceSettings settings) {
return KafkaProducerFactory.producer(settings.getKafkaProducer());
}
@Autowired
@Bean
public KafkaSender kafkaSender(Producer<String, Object> kafkaProducer, ImdgProvider imdgProvider) {
ImdgId imdgIdGenerator = imdgProvider.getImdgIdGenerator();
return KafkaSender
.setup()
.producer(kafkaProducer)
.idGenerator(imdgIdGenerator::nextId)
.imdgProvider(s -> {
Imdg<RequestInfo> imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
return imdg::insert;
})
.build();
}
}

View file

@ -4,6 +4,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import ru.spcex.clearing.platform.messaging.config.element.KafkaConsumerSettings;
import ru.spcex.clearing.platform.messaging.config.element.KafkaProducerSettings;
import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
@Component
@ -11,7 +12,8 @@ import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
@ConfigurationProperties("account-service")
public class AccountServiceSettings {
private HazelcastClientParams hazelcast;
private KafkaConsumerSettings kafka;
private KafkaConsumerSettings kafkaConsumer;
private KafkaProducerSettings kafkaProducer;
public HazelcastClientParams getHazelcast() {
return hazelcast;
@ -21,11 +23,19 @@ public class AccountServiceSettings {
this.hazelcast = hazelcast;
}
public KafkaConsumerSettings getKafka() {
return kafka;
public KafkaConsumerSettings getKafkaConsumer() {
return kafkaConsumer;
}
public void setKafka(KafkaConsumerSettings kafka) {
this.kafka = kafka;
public void setKafkaConsumer(KafkaConsumerSettings kafkaConsumer) {
this.kafkaConsumer = kafkaConsumer;
}
public KafkaProducerSettings getKafkaProducer() {
return kafkaProducer;
}
public void setKafkaProducer(KafkaProducerSettings kafkaProducer) {
this.kafkaProducer = kafkaProducer;
}
}

View file

@ -0,0 +1,76 @@
package ru.spcex.clearing.account.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.clearing.classes.statics.data.account.Account;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdf01Request;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.AccountSdfToStatementRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.util.ArrayList;
import java.util.List;
@Service
public class AccountService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<Account> accountMap;
private final KafkaSender kafkaSender;
@Autowired
public AccountService(Consumer<String, Object> kafkaQueue, ImdgProvider imdgProvider, KafkaSender kafkaSender) {
super(kafkaQueue);
this.accountMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
this.kafkaSender = kafkaSender;
}
@Override
public void afterPropertiesSet() {
callback(AccountSdf01Request.class)
.setConsumer(this::accountNew)
.forDestination(Consts.ACCOUNT_NEW, callbacks::put);
init();
}
private void accountNew(BaseRequest<AccountSdf01Request> userRequest) {
AccountSdf01Request req = userRequest.getRequestPayload();
log.debug("AccountSdf01Request received");
List<AccountSdfToStatementRequestPart> accountToStatement = new ArrayList<>();
for (AccountSdfRequestPart accountReq : req.getAccounts()) {
Account account = new Account();
account.setAccount(accountReq.getAccount());
//fixme account.setCompany();
accountMap.insert(account);
AccountSdfToStatementRequestPart responsePart = responsePart(accountReq.getSdfId());
accountToStatement.add(responsePart);
}
sendStatementRequestBack(req.getGroupingSdf01Id(), accountToStatement);
log.debug("successfully processed, grouping id={}, processed number={}", req.getGroupingSdf01Id(), accountToStatement.size());
}
private AccountSdfToStatementRequestPart responsePart(Long sdf01Id) {
AccountSdfToStatementRequestPart responsePart = new AccountSdfToStatementRequestPart();
responsePart.setSdfId(sdf01Id);
responsePart.setErrorCode(null);
responsePart.setErrorText(null);
return responsePart;
}
private void sendStatementRequestBack(Long groupingSdf01Id, List<AccountSdfToStatementRequestPart> results) {
StatementRequest request = new StatementRequest();
request.setGroupId(groupingSdf01Id);
request.setAccountCreationResults(results);
kafkaSender.sendRequestToQueue(Consts.STATEMENT_PROCESS, request);
}
}

View file

@ -1,6 +1,7 @@
package ru.spcex.clearing.account.service;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
@ -23,8 +24,8 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
private final Imdg<BankAccount> bankAccountMap;
@Autowired
public BankAccountService(Consumer<String, Object> kafkaQueue, ImdgProvider imdgProvider) {
super(kafkaQueue);
public BankAccountService(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer, ImdgProvider imdgProvider) {
super(kafkaQueue, kafkaProducer);
this.bankAccountMap = imdgProvider.getImdg(IMDGDistributedNames.Map_BankAccount, BankAccount.class);
}

View file

@ -1,11 +1,19 @@
spring.main.web-application-type=none
account-service.hazelcast.cluster-members=127.0.0.1
account-service.hazelcast.cluster-members=127.0.0.1:5701
account-service.hazelcast.login=dev
account-service.hazelcast.password=dev-pass
account-service.kafka.bootstrap-servers=localhost:9092
account-service.kafka.group-id=dev-group
account-service.kafka.enable-auto-commit=false
account-service.kafka.session-timeout-ms=30000
account-service.kafka.auto-offset-reset=latest
account-service.kafka.linger-ms=1
account-service.kafka.buffer-memory=33554432
account-service.kafka-consumer.bootstrap-servers=localhost:9092
account-service.kafka-consumer.group-id=dev-group-account-service
account-service.kafka-consumer.enable-auto-commit=true
account-service.kafka-consumer.session-timeout-ms=30000
account-service.kafka-consumer.auto-offset-reset=latest
account-service.kafka-consumer.linger-ms=1
account-service.kafka-consumer.buffer-memory=33554432
account-service.kafka-producer.bootstrap-servers=localhost:9092
account-service.kafka-producer.acks=all
account-service.kafka-producer.retries=0
account-service.kafka-producer.batch-size=16384
account-service.kafka-producer.linger-ms=1
account-service.kafka-producer.buffer-memory=33554432

View file

@ -6,6 +6,7 @@ import com.hazelcast.core.IMap;
import org.apache.kafka.clients.consumer.ConsumerRecord;
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.common.TopicPartition;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -47,10 +48,12 @@ public class BankAccountServiceTest {
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
private MockConsumer<String, Object> mockConsumer;
private MockProducer<String, Object> mockProducer;
@BeforeEach
void setUp() {
mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
mockProducer = new MockProducer<>();
}
/**
@ -118,7 +121,7 @@ public class BankAccountServiceTest {
//ACT
//service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, hazelcastServiceTest);
BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer, hazelcastServiceTest);
Thread.sleep(10000);
//callbacks set up
bankAccountService.afterPropertiesSet();
@ -220,7 +223,7 @@ public class BankAccountServiceTest {
//ACT
//service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, hazelcastServiceTest);
BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer, hazelcastServiceTest);
Thread.sleep(10000);
//callbacks set up
bankAccountService.afterPropertiesSet();
@ -304,7 +307,7 @@ public class BankAccountServiceTest {
//ACT
//service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, hazelcastServiceTest);
BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer, hazelcastServiceTest);
Thread.sleep(10000);
//callbacks set up
bankAccountService.afterPropertiesSet();

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>backend-api</artifactId>
@ -8,12 +8,12 @@
<description>Clearing backend API module</description>
<packaging>jar</packaging>
<parent>
<artifactId>clearing-parent</artifactId>
<parent>
<artifactId>clearing-parent</artifactId>
<groupId>ru.spcex.clearing</groupId>
<version>SPCEX-1.0.0.0</version>
</parent>
<properties>
<keycloak-spring-boot-starter.version>17.0.1</keycloak-spring-boot-starter.version>
@ -25,9 +25,9 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
@ -53,6 +53,14 @@
<groupId>ru.spcex.clearing</groupId>
<artifactId>classes</artifactId>
</dependency>
<dependency>
<groupId>ru.spcex.clearing</groupId>
<artifactId>dictionary</artifactId>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-enum</artifactId>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.springframework</groupId>
@ -74,18 +82,17 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>${keycloak-spring-boot-starter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>${keycloak-spring-boot-starter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
@ -96,6 +103,7 @@
<excludes>
<exclude>application.properties</exclude>
<exclude>keycloak.json</exclude>
<exclude>meta/**</exclude>
</excludes>
<filtering>false</filtering>
</resource>
@ -117,6 +125,59 @@
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xml-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>transform</goal>
</goals>
</execution>
</executions>
<configuration>
<transformationSets>
<transformationSet>
<dir>src/main/resources/meta</dir>
<excludes>
<exclude>meta.server.xslt</exclude>
</excludes>
<stylesheet>src/main/resources/meta/meta.server.xslt</stylesheet>
<fileMappers>
<fileMapper
implementation="org.codehaus.plexus.components.io.filemappers.FileExtensionMapper">
<targetExtension>.json</targetExtension>
</fileMapper>
</fileMappers>
</transformationSet>
</transformationSets>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-meta</id>
<phase>process-classes</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/src/main/resources</outputDirectory>
<resources>
<resource>
<directory>${basedir}/target/generated-resources/xml/xslt</directory>
<includes>
<include>meta.json</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

View file

@ -1,5 +1,8 @@
package ru.spcex.clearing.backendapi.config;
import org.apache.kafka.clients.consumer.Consumer;
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.springframework.beans.factory.annotation.Autowired;
@ -7,6 +10,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import ru.spcex.clearing.backendapi.config.element.BackendApiSettings;
import ru.spcex.clearing.platform.messaging.config.KafkaConsumerFactory;
import ru.spcex.clearing.platform.messaging.config.KafkaProducerFactory;
@Configuration
@ -16,7 +20,7 @@ public class KafkaConfig {
@Autowired
@Bean
public Producer<String, Object> createProducer(BackendApiSettings settings) {
return KafkaProducerFactory.producer(settings.getKafka());
return KafkaProducerFactory.producer(settings.getKafkaProducer());
}
@Profile("kafkaDisabled")
@ -25,4 +29,17 @@ public class KafkaConfig {
return new MockProducer<>(true, (topic, data) -> data != null ? data.getBytes() : new byte[0], (topic, data) -> data.toString().getBytes());
}
@Profile("!kafkaDisabled")
@Autowired
@Bean
public Consumer<String, Object> createConsumer(BackendApiSettings settings) {
return KafkaConsumerFactory.consumer(settings.getKafkaConsumer());
}
@Profile("kafkaDisabled")
@Bean
public Consumer<String, Object> createConsumerMock() {
return new MockConsumer<>(OffsetResetStrategy.NONE);
}
}

View file

@ -0,0 +1,21 @@
package ru.spcex.clearing.backendapi.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.nio.file.Files;
@Configuration
public class MetaConfiguration {
@Value("file:${spring.config.location}/meta.json")
private Resource meta;
@Bean("metaJson")
public String metaJsonConfiguration() throws IOException {
if (!meta.isReadable()) throw new IllegalStateException("cannot read meta.json from spring.config.location");
return Files.readString(meta.getFile().toPath());
}
}

View file

@ -2,8 +2,10 @@ package ru.spcex.clearing.backendapi.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.server.Cookie;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
@ -12,6 +14,7 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.servlet.config.annotation.*;
import ru.spcex.clearing.backendapi.config.element.BackendApiSettings;
import java.util.List;
import java.util.function.Consumer;
@ -23,10 +26,14 @@ import java.util.function.Consumer;
@CrossOrigin
public class WebConfig implements WebMvcConfigurer {
private final MappingJackson2HttpMessageConverter customJsonHttpConverter;
private final String sameSite;
@Autowired
public WebConfig(@Qualifier("customJsonHttpConverter") MappingJackson2HttpMessageConverter customJsonHttpConverter) {
public WebConfig(@Qualifier("customJsonHttpConverter") MappingJackson2HttpMessageConverter customJsonHttpConverter,
BackendApiSettings backendSettings
) {
this.customJsonHttpConverter = customJsonHttpConverter;
this.sameSite = backendSettings.getSecurity().getSameSite();
}
@Override
@ -75,4 +82,19 @@ public class WebConfig implements WebMvcConfigurer {
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
@Bean
public CookieSameSiteSupplier applicationCookieSameSiteSupplier() {
if (sameSite == null) {
return null;
} else if (sameSite.equalsIgnoreCase(Cookie.SameSite.NONE.attributeValue())) {
return CookieSameSiteSupplier.ofNone();
} else if (sameSite.equalsIgnoreCase(Cookie.SameSite.LAX.attributeValue())) {
return CookieSameSiteSupplier.ofNone();
} else if (sameSite.equalsIgnoreCase(Cookie.SameSite.STRICT.attributeValue())) {
return CookieSameSiteSupplier.ofStrict();
} else {
throw new IllegalStateException("unknown SameSite setting");
}
}
}

View file

@ -4,6 +4,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import ru.spcex.clearing.backendapi.security.element.SecuritySettings;
import ru.spcex.clearing.platform.messaging.config.element.KafkaConsumerSettings;
import ru.spcex.clearing.platform.messaging.config.element.KafkaProducerSettings;
import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
@ -12,7 +13,8 @@ import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
@ConfigurationProperties("backend-api")
public class BackendApiSettings {
private HazelcastClientParams hazelcast;
private KafkaProducerSettings kafka;
private KafkaProducerSettings kafkaProducer;
private KafkaConsumerSettings kafkaConsumer;
private SecuritySettings security;
private String exampleSetting;
@ -24,12 +26,20 @@ public class BackendApiSettings {
this.hazelcast = hazelcast;
}
public KafkaProducerSettings getKafka() {
return kafka;
public KafkaProducerSettings getKafkaProducer() {
return kafkaProducer;
}
public void setKafka(KafkaProducerSettings kafka) {
this.kafka = kafka;
public void setKafkaProducer(KafkaProducerSettings kafkaProducer) {
this.kafkaProducer = kafkaProducer;
}
public KafkaConsumerSettings getKafkaConsumer() {
return kafkaConsumer;
}
public void setKafkaConsumer(KafkaConsumerSettings kafkaConsumer) {
this.kafkaConsumer = kafkaConsumer;
}
public String getExampleSetting() {

View file

@ -39,7 +39,7 @@ public class QueueExceptionHandler extends ResponseEntityExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public BasicSpcexResponse handleValidationException(ActionValidationException e) {
log.error("Default scoring exception handler: {}", ExceptionUtils.getStackTrace(e));
log.error("Default exception handler: {}", ExceptionUtils.getStackTrace(e));
EnumMessage firstError = e.getErrors().iterator().next();
BasicSpcexResponse errorResponse = new BasicSpcexResponse();
errorResponse.setCode(firstError.getSubject().getId());
@ -55,7 +55,7 @@ public class QueueExceptionHandler extends ResponseEntityExceptionHandler {
UnrecognizedPropertyException jacksonException = (UnrecognizedPropertyException) ex.getCause();
message = new EnumMessage(BackEndError.UnknownJsonProperty, jacksonException.getPropertyName());
} catch (ClassCastException e) {
log.error(ExceptionUtils.getStackTrace(e));
log.error(ExceptionUtils.getStackTrace(ex));
message = new EnumMessage(BackEndError.FailedToReadHttpMessage);
}
errorResponse.setCode(message.getSubject().getId());
@ -68,7 +68,7 @@ public class QueueExceptionHandler extends ResponseEntityExceptionHandler {
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public BasicSpcexResponse handleDefault(Throwable e) {
log.error("Default scoring exception handler: {}", ExceptionUtils.getStackTrace(e));
log.error("Default exception handler: {}", ExceptionUtils.getStackTrace(e));
BasicSpcexResponse errorResponse = new BasicSpcexResponse();
errorResponse.setCode(-1);
errorResponse.setMessage("internal server error");

View file

@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.*;
import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
import ru.spcex.clearing.backendapi.controller.queue.AbstractQueueController;
import ru.spcex.clearing.backendapi.controller.request.cud.common.CommonDeleteAction;
import ru.spcex.clearing.backendapi.controller.request.cud.company.ClearingMemberCategoryNewAction;
import ru.spcex.clearing.backendapi.controller.request.cud.company.ClearingMemberCategoryUpdateAction;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
@ -34,6 +35,16 @@ public class EditClearingMemberCategoryController extends AbstractQueueControlle
this.stateLoader = stateLoader;
}
@ApiOperation(value = "new clearing category.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CudResponse add(
@ApiParam(value = "Параметры команды в JSON формате.", required = true)
@RequestBody ClearingMemberCategoryNewAction clearingMemberCategoryNewAction) throws ExecutionException, InterruptedException {
return processRequest(Consts.DESTINATION_CLEARING_MEMBER_CATEGORY_NEW, clearingMemberCategoryNewAction);
}
@ApiOperation(value = "update clearing member category.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)

View file

@ -1,28 +1,49 @@
package ru.spcex.clearing.backendapi.controller.queue.scheduler;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
import ru.clearing.classes.statics.data.scheduler.TaskRunner;
import ru.clearing.classes.statics.data.user.User;
import ru.spcex.clearing.backendapi.controller.queue.AbstractQueueController;
import ru.spcex.clearing.backendapi.controller.request.cud.schedule.TaskRunnerNew;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.schedule.TaskRunnerBackendGetAll;
import ru.spcex.clearing.backendapi.errors.NotFound404Exception;
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.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@Controller
@RequestMapping("/schedule/task-runners")
public class TaskRunnerController {
@RequestMapping("/task-runners")
public class TaskRunnerController extends AbstractQueueController {
private final IStateLoader stateLoader;
private final Imdg<User> userImdg;
@Autowired
public TaskRunnerController(IStateLoader stateLoader) {
public TaskRunnerController(IStateLoader stateLoader, IOperator operator, ImdgProvider imdgProvider) {
super(operator);
this.stateLoader = stateLoader;
this.userImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_User, User.class);
}
@ApiOperation(value = "get all TaskRunners.")
@ -35,4 +56,36 @@ public class TaskRunnerController {
response.fromEntity(all);
return response;
}
@ApiOperation(value = "create task runner.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@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 {
TaskRunnerNew taskRunnerCommand = new TaskRunnerNew();
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);
}
taskRunnerCommand.setTask(dictionaryName);
taskRunnerCommand.setUserId(user.getId());
return processRequest(Consts.TASK_RUNNER_NEW, taskRunnerCommand);
}
@Autowired
private IMessageResolver errorResolver;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ResponseBody
@ExceptionHandler(NotFound404Exception.class)
public BasicSpcexResponse conflict(NotFound404Exception ex) {
BasicSpcexResponse response = new BasicSpcexResponse();
EnumMessage message = ex.getError();
response.setCode(message.getSubject().getId());
response.setMessage(errorResolver.resolve(message));
return response;
}
}

View file

@ -1,38 +0,0 @@
package ru.spcex.clearing.backendapi.controller.queue.user;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import ru.clearing.classes.statics.data.user.UserSettings;
import ru.spcex.clearing.backendapi.controller.response.entity.user.UserSettingsBackendGetAll;
import ru.spcex.clearing.backendapi.service.IStateLoader;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import java.util.Collection;
@Controller
@RequestMapping("/user-settings")
public class UserSettingsSessionController {
private final IStateLoader stateLoader;
@Autowired
public UserSettingsSessionController(IStateLoader stateLoader) {
this.stateLoader = stateLoader;
}
@ApiOperation(value = "get all user settings.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = UserSettingsBackendGetAll.class)})
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public UserSettingsBackendGetAll getAll() {
Collection<UserSettings> all = stateLoader.getAll(IMDGDistributedNames.Map_UserSettings, UserSettings.class);
var response = new UserSettingsBackendGetAll();
response.fromEntity(all);
return response;
}
}

View file

@ -0,0 +1,76 @@
package ru.spcex.clearing.backendapi.controller.queue.utilities;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import ru.clearing.classes.statics.data.user.User;
import ru.clearing.classes.statics.data.user.UserSettings;
import ru.spcex.clearing.backendapi.controller.queue.AbstractQueueController;
import ru.spcex.clearing.backendapi.controller.request.cud.utilities.UserSettingsUpdateAction;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.user.UserSettingsBackendGetAll;
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.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@Controller
@RequestMapping("/utilities/user-settings")
public class UserSettingsController extends AbstractQueueController {
private final IStateLoader stateLoader;
private final Imdg<User> userImdg;
@Autowired
public UserSettingsController(IOperator operator, IStateLoader stateLoader, ImdgProvider imdgProvider) {
super(operator);
this.stateLoader = stateLoader;
this.userImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_User, User.class);
}
@ApiOperation(value = "get all user settings.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = UserSettingsBackendGetAll.class)})
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public UserSettingsBackendGetAll getAll() {
Collection<UserSettings> all = stateLoader.getAll(IMDGDistributedNames.Map_UserSettings, UserSettings.class);
var response = new UserSettingsBackendGetAll();
response.fromEntity(all);
return response;
}
@ApiOperation(value = "update user settings.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CudResponse update(
@ApiParam(value = "Новые значения полей объекта.", required = true)
@RequestBody UserSettingsUpdateAction userSettingsUpdateAction) throws ExecutionException, InterruptedException {
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);
}
userSettingsUpdateAction.setUserId(user.getId());
return processRequest(Consts.USER_SETTINGS_UPDATE, userSettingsUpdateAction);
}
}

View file

@ -5,13 +5,14 @@ import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.platform.classes.base.interfaces.WithId;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class CommonDeleteAction implements IAction<CommonDeleteRequest> {
public class CommonDeleteAction implements IAction<CommonDeleteRequest>, WithId {
@JsonProperty
public Long id;

View file

@ -0,0 +1,48 @@
package ru.spcex.clearing.backendapi.controller.request.cud.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryNewRequest;
public class ClearingMemberCategoryNewAction implements IAction<ClearingMemberCategoryNewRequest> {
@ApiModelProperty(value = "Идентификатор компании", example = "1234")
@JsonProperty
private Long companyId;
@ApiModelProperty(value = "Идентификатор категории участника клиринга", example = "ABCD")
@JsonProperty
private String clearingMemberCategory;
@Override
public ClearingMemberCategoryNewRequest toRequest() {
ClearingMemberCategoryNewRequest request = new ClearingMemberCategoryNewRequest();
request.setCompanyId(companyId);
request.setClearingMemberCategory(this.clearingMemberCategory);
return request;
}
@ApiModelProperty(hidden = true)
@Override
public ActionType getActionType() {
return ActionType.NEW;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getClearingMemberCategory() {
return clearingMemberCategory;
}
public void setClearingMemberCategory(String clearingMemberCategory) {
this.clearingMemberCategory = clearingMemberCategory;
}
}

View file

@ -0,0 +1,60 @@
package ru.spcex.clearing.backendapi.controller.request.cud.schedule;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.TaskRunnerCommandRequest;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class TaskRunnerNew implements IAction<TaskRunnerCommandRequest> {
@ApiModelProperty(value = "Идентификатор единоличного исполнительного органа", example = "ABCD")
@JsonProperty
private String task;
@JsonIgnore
private Long userId;
@Override
public TaskRunnerCommandRequest toRequest() {
TaskRunnerCommandRequest taskRunnerCommandRequest = new TaskRunnerCommandRequest();
taskRunnerCommandRequest.setTaskName(task);
taskRunnerCommandRequest.setUserId(userId);
return taskRunnerCommandRequest;
}
@Override
public ActionType getActionType() {
return ActionType.NEW;
}
@Override
public Collection<EnumMessage> validate() {
if (task == null) {
return List.of(new EnumMessage(BackEndError.ValidationError,"url parameter 'task-code'"));
}
return Collections.emptyList();
}
public String getTask() {
return task;
}
public void setTask(String task) {
this.task = task;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
}

View file

@ -8,10 +8,10 @@ import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityNewRequest;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.InstantDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import java.time.Instant;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -19,14 +19,14 @@ import java.util.List;
public class MoneyMarketSecurityNewAction implements IAction<MoneyMarketSecurityNewRequest> {
@ApiModelProperty(value = "Дата начала действия", example = "2022-01-20")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Europe/Moscow")
@JsonDeserialize(using = InstantDeserializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
public Instant startDate;
public LocalDate startDate;
@ApiModelProperty(value = "Дата окончания действия", example = "2022-02-21")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Europe/Moscow")
@JsonDeserialize(using = InstantDeserializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
public Instant endDate;
public LocalDate endDate;
@ApiModelProperty(value = "Номинал", example = "20.5")
@JsonProperty
public Double nominalValue;
@ -73,19 +73,19 @@ public class MoneyMarketSecurityNewAction implements IAction<MoneyMarketSecurity
return ActionType.NEW;
}
public Instant getStartDate() {
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(Instant startDate) {
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public Instant getEndDate() {
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(Instant endDate) {
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}

View file

@ -7,19 +7,20 @@ import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.InstantDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import ru.spcex.platform.classes.base.interfaces.WithId;
import java.time.Instant;
import java.time.LocalDate;
public class MoneyMarketSecurityUpdateAction implements IAction<MoneyMarketSecurityUpdateRequest> {
public class MoneyMarketSecurityUpdateAction implements IAction<MoneyMarketSecurityUpdateRequest>, WithId {
@ApiModelProperty(hidden = true)
@JsonProperty
public Long id;
@ApiModelProperty(value = "Дата окончания действия", example = "2022-02-21")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Europe/Moscow")
@JsonDeserialize(using = InstantDeserializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
public Instant endDate;
public LocalDate endDate;
@ApiModelProperty(value = "Номинал", example = "20.5")
@JsonProperty
public Double nominalValue;
@ -56,11 +57,11 @@ public class MoneyMarketSecurityUpdateAction implements IAction<MoneyMarketSecur
}
public Instant getEndDate() {
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(Instant endDate) {
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}

View file

@ -8,10 +8,11 @@ import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateNewRequest;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.InstantDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import java.time.Instant;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -19,17 +20,17 @@ import java.util.List;
public class KeyRateNewAction implements IAction<KeyRateNewRequest> {
@ApiModelProperty(value = "Ключевая ставка ЦБ РФ", example = "12.5")
@JsonProperty
public Double keyRate;
public BigDecimal keyRate;
@ApiModelProperty(value = "Дата начала действия ключевой ставки", example = "2022-01-20")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Europe/Moscow")
@JsonDeserialize(using = InstantDeserializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
public Instant startDate;
public LocalDate startDate;
@ApiModelProperty(value = "Дата окончания действия ключевой ставки", example = "2022-04-20")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Europe/Moscow")
@JsonDeserialize(using = InstantDeserializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
public Instant endDate;
public LocalDate endDate;
@ApiModelProperty(value = "Документ ЦБ", example = "Lorem ipsum")
@JsonProperty
public String document;
@ -57,27 +58,27 @@ public class KeyRateNewAction implements IAction<KeyRateNewRequest> {
return req;
}
public Double getKeyRate() {
public BigDecimal getKeyRate() {
return keyRate;
}
public void setKeyRate(Double keyRate) {
public void setKeyRate(BigDecimal keyRate) {
this.keyRate = keyRate;
}
public Instant getStartDate() {
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(Instant startDate) {
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public Instant getEndDate() {
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(Instant endDate) {
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}

View file

@ -7,9 +7,10 @@ import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.InstantDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import java.time.Instant;
import java.math.BigDecimal;
import java.time.LocalDate;
public class KeyRateUpdateAction implements IAction<KeyRateUpdateRequest> {
@ApiModelProperty(hidden = true)
@ -17,17 +18,17 @@ public class KeyRateUpdateAction implements IAction<KeyRateUpdateRequest> {
public Long id;
@ApiModelProperty(value = "Ключевая ставка ЦБ РФ", example = "12.5")
@JsonProperty
public Double keyRate;
public BigDecimal keyRate;
@ApiModelProperty(value = "Дата начала действия ключевой ставки", example = "2022-01-20")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Europe/Moscow")
@JsonDeserialize(using = InstantDeserializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
public Instant startDate;
public LocalDate startDate;
@ApiModelProperty(value = "Дата окончания действия ключевой ставки", example = "2022-04-20")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Europe/Moscow")
@JsonDeserialize(using = InstantDeserializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
public Instant endDate;
public LocalDate endDate;
@ApiModelProperty(value = "Документ ЦБ", example = "Lorem ipsum")
@JsonProperty
public String document;
@ -49,27 +50,27 @@ public class KeyRateUpdateAction implements IAction<KeyRateUpdateRequest> {
return req;
}
public Double getKeyRate() {
public BigDecimal getKeyRate() {
return keyRate;
}
public void setKeyRate(Double keyRate) {
public void setKeyRate(BigDecimal keyRate) {
this.keyRate = keyRate;
}
public Instant getStartDate() {
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(Instant startDate) {
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public Instant getEndDate() {
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(Instant endDate) {
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}
@ -77,6 +78,10 @@ public class KeyRateUpdateAction implements IAction<KeyRateUpdateRequest> {
return document;
}
public void setDocument(String document) {
this.document = document;
}
public Long getId() {
return id;
}
@ -84,8 +89,4 @@ public class KeyRateUpdateAction implements IAction<KeyRateUpdateRequest> {
public void setId(Long id) {
this.id = id;
}
public void setDocument(String document) {
this.document = document;
}
}

View file

@ -0,0 +1,54 @@
package ru.spcex.clearing.backendapi.controller.request.cud.utilities;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.UserSettingsUpdateRequest;
public class UserSettingsUpdateAction implements IAction<UserSettingsUpdateRequest> {
@ApiModelProperty(hidden = true)
@JsonProperty
public Long userId;
@JsonProperty
public String version;
public String json;
@JsonProperty("json")
public void unpackRawJson(JsonNode json) {
this.json = json.toString();
}
@ApiModelProperty(hidden = true)
@Override
public ActionType getActionType() {
return ActionType.UPDATE;
}
@Override
public UserSettingsUpdateRequest toRequest() {
var req = new UserSettingsUpdateRequest();
req.setVersion(version);
req.setJson(json);
req.setUserId(userId);
return req;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}

View file

@ -17,18 +17,6 @@ public class AccountBackendGetAll extends BasicSpcexResponse {
@ApiModelProperty(value = "Полезная нагрузка")
private AccountBackendPayload payload = new AccountBackendPayload();
private static class AccountBackendPayload {
private List<AccountBackendGetFields> items = new ArrayList<>();
public List<AccountBackendGetFields> getItems() {
return items;
}
public void setItems(List<AccountBackendGetFields> items) {
this.items = items;
}
}
public AccountBackendPayload getPayload() {
return payload;
}
@ -45,7 +33,7 @@ public class AccountBackendGetAll extends BasicSpcexResponse {
singleItem.setAccount(account.getAccount());
singleItem.setAccountType(account.getAccountType());
singleItem.setRelationId(account.getRelationId());
singleItem.setStatus(account.getStatus());
singleItem.setStatus(account.getAccountStatus());
singleItem.setProcessingSign(account.getProcessingSign());
singleItem.setCreated(account.getCreated());
singleItem.setUpdated(account.getUpdated());
@ -53,4 +41,16 @@ public class AccountBackendGetAll extends BasicSpcexResponse {
}
}
private static class AccountBackendPayload {
private List<AccountBackendGetFields> items = new ArrayList<>();
public List<AccountBackendGetFields> getItems() {
return items;
}
public void setItems(List<AccountBackendGetFields> items) {
this.items = items;
}
}
}

View file

@ -51,26 +51,23 @@ public class CompanyBackendGetAll extends BasicSpcexResponse {
singleItem.setFullName(company.getFullName());
singleItem.setCreated(company.getCreated());
singleItem.setUpdated(company.getUpdated());
CompanyBackendGetFields.CompanyInfoFields companyInfoFields = new CompanyBackendGetFields.CompanyInfoFields();
CompanyInfo profile = company.getProfile();
companyInfoFields.setId(profile.getId());
companyInfoFields.setCompanyId(profile.getCompanyId());
companyInfoFields.setClearingMemberCategory(profile.getClearingMemberCategory());
companyInfoFields.setCorporationSoleType(profile.getCorporationSoleType());
companyInfoFields.setCountryCode(profile.getCountryCode());
companyInfoFields.setDescription(profile.getDescription());
companyInfoFields.setProfessionalSign(profile.getProfessionalSign());
companyInfoFields.setLegalKind(profile.getLegalKind());
companyInfoFields.setOrganizationType(profile.getOrganizationType());
companyInfoFields.setResidence(profile.getResidence());
companyInfoFields.setShortName(profile.getShortName());
companyInfoFields.setFullName(profile.getFullName());
companyInfoFields.setShortNameEng(profile.getShortNameEng());
companyInfoFields.setFullNameEng(profile.getFullNameEng());
companyInfoFields.setTradingCode(profile.getTradingCode());
companyInfoFields.setClearingCode(profile.getClearingCode());
companyInfoFields.setRegistrationCode(profile.getRegistrationCode());
singleItem.setProfile(companyInfoFields);
if (profile != null) {
singleItem.setCorporationSoleType(profile.getCorporationSoleType());
singleItem.setCountryCode(profile.getCountryCode());
singleItem.setDescription(profile.getDescription());
singleItem.setProfessionalSign(profile.getProfessionalSign());
singleItem.setLegalKind(profile.getLegalKind());
singleItem.setOrganizationType(profile.getOrganizationType());
singleItem.setResidence(profile.getResidence());
singleItem.setShortName(profile.getShortName());
singleItem.setFullName(profile.getFullName());
singleItem.setShortNameEng(profile.getShortNameEng());
singleItem.setFullNameEng(profile.getFullNameEng());
singleItem.setTradingCode(profile.getTradingCode());
singleItem.setClearingCode(profile.getClearingCode());
singleItem.setRegistrationCode(profile.getRegistrationCode());
}
payload.getItems().add(singleItem);
}
}

View file

@ -28,7 +28,25 @@ public class CompanyBackendGetFields {
@JsonProperty
private Instant updated;
@JsonProperty
private CompanyInfoFields profile;
private String clearingMemberCategory; // ref CHAR(4),
@JsonProperty
private String corporationSoleType; // ref CHAR(4),
@JsonProperty
private String countryCode; //ref CHAR(4),
@JsonProperty
private String description;
@JsonProperty
private String professionalSign; // ref CHAR(4),
@JsonProperty
private String legalKind; // ref CHAR(4),
@JsonProperty
private String organizationType; // ref CHAR(4),
@JsonProperty
private String residence; // ref CHAR(4),
@JsonProperty
private String shortNameEng;
@JsonProperty
private String fullNameEng;
public Long getId() {
return id;
@ -102,184 +120,256 @@ public class CompanyBackendGetFields {
this.updated = updated;
}
public CompanyInfoFields getProfile() {
return profile;
public String getClearingMemberCategory() {
return clearingMemberCategory;
}
public void setProfile(CompanyInfoFields profile) {
this.profile = profile;
public void setClearingMemberCategory(String clearingMemberCategory) {
this.clearingMemberCategory = clearingMemberCategory;
}
static class CompanyInfoFields {
@JsonProperty
private Long id;
@JsonProperty
private Long companyId; // Company.CompanyInfo.companyId = CompanyInfo.id
@JsonProperty
private String clearingMemberCategory; // ref CHAR(4),
@JsonProperty
private String corporationSoleType; // ref CHAR(4),
@JsonProperty
private String countryCode; //ref CHAR(4),
@JsonProperty
private String description;
@JsonProperty
private String professionalSign; // ref CHAR(4),
@JsonProperty
private String legalKind; // ref CHAR(4),
@JsonProperty
private String organizationType; // ref CHAR(4),
@JsonProperty
private String residence; // ref CHAR(4),
@JsonProperty
private String shortName;
@JsonProperty
private String fullName;
@JsonProperty
private String shortNameEng;
@JsonProperty
private String fullNameEng;
@JsonProperty
private String tradingCode;
@JsonProperty
private String clearingCode;
@JsonProperty
private String registrationCode;
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getClearingMemberCategory() {
return clearingMemberCategory;
}
public void setClearingMemberCategory(String clearingMemberCategory) {
this.clearingMemberCategory = clearingMemberCategory;
}
public String getCorporationSoleType() {
return corporationSoleType;
}
public void setCorporationSoleType(String corporationSoleType) {
this.corporationSoleType = corporationSoleType;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getProfessionalSign() {
return professionalSign;
}
public void setProfessionalSign(String professionalSign) {
this.professionalSign = professionalSign;
}
public String getLegalKind() {
return legalKind;
}
public void setLegalKind(String legalKind) {
this.legalKind = legalKind;
}
public String getOrganizationType() {
return organizationType;
}
public void setOrganizationType(String organizationType) {
this.organizationType = organizationType;
}
public String getResidence() {
return residence;
}
public void setResidence(String residence) {
this.residence = residence;
}
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getShortNameEng() {
return shortNameEng;
}
public void setShortNameEng(String shortNameEng) {
this.shortNameEng = shortNameEng;
}
public String getFullNameEng() {
return fullNameEng;
}
public void setFullNameEng(String fullNameEng) {
this.fullNameEng = fullNameEng;
}
public String getTradingCode() {
return tradingCode;
}
public void setTradingCode(String tradingCode) {
this.tradingCode = tradingCode;
}
public String getClearingCode() {
return clearingCode;
}
public void setClearingCode(String clearingCode) {
this.clearingCode = clearingCode;
}
public String getRegistrationCode() {
return registrationCode;
}
public void setRegistrationCode(String registrationCode) {
this.registrationCode = registrationCode;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCorporationSoleType() {
return corporationSoleType;
}
public void setCorporationSoleType(String corporationSoleType) {
this.corporationSoleType = corporationSoleType;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getProfessionalSign() {
return professionalSign;
}
public void setProfessionalSign(String professionalSign) {
this.professionalSign = professionalSign;
}
public String getLegalKind() {
return legalKind;
}
public void setLegalKind(String legalKind) {
this.legalKind = legalKind;
}
public String getOrganizationType() {
return organizationType;
}
public void setOrganizationType(String organizationType) {
this.organizationType = organizationType;
}
public String getResidence() {
return residence;
}
public void setResidence(String residence) {
this.residence = residence;
}
public String getShortNameEng() {
return shortNameEng;
}
public void setShortNameEng(String shortNameEng) {
this.shortNameEng = shortNameEng;
}
public String getFullNameEng() {
return fullNameEng;
}
public void setFullNameEng(String fullNameEng) {
this.fullNameEng = fullNameEng;
}
// static class CompanyInfoFields {
// @JsonProperty
// private Long id;
// @JsonProperty
// private Long companyId; // Company.CompanyInfo.companyId = CompanyInfo.id
// @JsonProperty
// private String clearingMemberCategory; // ref CHAR(4),
// @JsonProperty
// private String corporationSoleType; // ref CHAR(4),
// @JsonProperty
// private String countryCode; //ref CHAR(4),
// @JsonProperty
// private String description;
// @JsonProperty
// private String professionalSign; // ref CHAR(4),
// @JsonProperty
// private String legalKind; // ref CHAR(4),
// @JsonProperty
// private String organizationType; // ref CHAR(4),
// @JsonProperty
// private String residence; // ref CHAR(4),
// @JsonProperty
// private String shortName;
// @JsonProperty
// private String fullName;
// @JsonProperty
// private String shortNameEng;
// @JsonProperty
// private String fullNameEng;
// @JsonProperty
// private String tradingCode;
// @JsonProperty
// private String clearingCode;
// @JsonProperty
// private String registrationCode;
//
// public Long getCompanyId() {
// return companyId;
// }
//
// public void setCompanyId(Long companyId) {
// this.companyId = companyId;
// }
//
// public String getClearingMemberCategory() {
// return clearingMemberCategory;
// }
//
// public void setClearingMemberCategory(String clearingMemberCategory) {
// this.clearingMemberCategory = clearingMemberCategory;
// }
//
// public String getCorporationSoleType() {
// return corporationSoleType;
// }
//
// public void setCorporationSoleType(String corporationSoleType) {
// this.corporationSoleType = corporationSoleType;
// }
//
// public String getCountryCode() {
// return countryCode;
// }
//
// public void setCountryCode(String countryCode) {
// this.countryCode = countryCode;
// }
//
// public String getDescription() {
// return description;
// }
//
// public void setDescription(String description) {
// this.description = description;
// }
//
// public String getProfessionalSign() {
// return professionalSign;
// }
//
// public void setProfessionalSign(String professionalSign) {
// this.professionalSign = professionalSign;
// }
//
// public String getLegalKind() {
// return legalKind;
// }
//
// public void setLegalKind(String legalKind) {
// this.legalKind = legalKind;
// }
//
// public String getOrganizationType() {
// return organizationType;
// }
//
// public void setOrganizationType(String organizationType) {
// this.organizationType = organizationType;
// }
//
// public String getResidence() {
// return residence;
// }
//
// public void setResidence(String residence) {
// this.residence = residence;
// }
//
// public String getShortName() {
// return shortName;
// }
//
// public void setShortName(String shortName) {
// this.shortName = shortName;
// }
//
// public String getFullName() {
// return fullName;
// }
//
// public void setFullName(String fullName) {
// this.fullName = fullName;
// }
//
// public String getShortNameEng() {
// return shortNameEng;
// }
//
// public void setShortNameEng(String shortNameEng) {
// this.shortNameEng = shortNameEng;
// }
//
// public String getFullNameEng() {
// return fullNameEng;
// }
//
// public void setFullNameEng(String fullNameEng) {
// this.fullNameEng = fullNameEng;
// }
//
// public String getTradingCode() {
// return tradingCode;
// }
//
// public void setTradingCode(String tradingCode) {
// this.tradingCode = tradingCode;
// }
//
// public String getClearingCode() {
// return clearingCode;
// }
//
// public void setClearingCode(String clearingCode) {
// this.clearingCode = clearingCode;
// }
//
// public String getRegistrationCode() {
// return registrationCode;
// }
//
// public void setRegistrationCode(String registrationCode) {
// this.registrationCode = registrationCode;
// }
//
// public Long getId() {
// return id;
// }
//
// public void setId(Long id) {
// this.id = id;
// }
// }
}

View file

@ -43,7 +43,6 @@ public class CompanyBackendInfoGetAll extends BasicSpcexResponse {
var singleItem = new CompanyBackendInfoGetFields();
singleItem.setId(companyInfo.getId());
singleItem.setCompanyId(companyInfo.getCompanyId());
singleItem.setClearingMemberCategory(companyInfo.getClearingMemberCategory());
singleItem.setCorporationSoleType(companyInfo.getCorporationSoleType());
singleItem.setCountryCode(companyInfo.getCountryCode());
singleItem.setDescription(companyInfo.getDescription());

View file

@ -2,9 +2,9 @@ package ru.spcex.clearing.backendapi.controller.response.entity.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import java.time.Instant;
import java.time.LocalDate;
public class ProfileDocumentBackendGetFields {
@JsonProperty
@ -14,8 +14,8 @@ public class ProfileDocumentBackendGetFields {
@JsonProperty
private String documentType;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant issueDate;
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate issueDate;
@JsonProperty
private String issuePlace;
@JsonProperty
@ -29,11 +29,11 @@ public class ProfileDocumentBackendGetFields {
@JsonProperty
private String place;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant validFromDate;
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate validFromDate;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant validToDate;
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate validToDate;
@JsonProperty
private String link;
@ -61,11 +61,11 @@ public class ProfileDocumentBackendGetFields {
this.documentType = documentType;
}
public Instant getIssueDate() {
public LocalDate getIssueDate() {
return issueDate;
}
public void setIssueDate(Instant issueDate) {
public void setIssueDate(LocalDate issueDate) {
this.issueDate = issueDate;
}
@ -117,19 +117,19 @@ public class ProfileDocumentBackendGetFields {
this.place = place;
}
public Instant getValidFromDate() {
public LocalDate getValidFromDate() {
return validFromDate;
}
public void setValidFromDate(Instant validFromDate) {
public void setValidFromDate(LocalDate validFromDate) {
this.validFromDate = validFromDate;
}
public Instant getValidToDate() {
public LocalDate getValidToDate() {
return validToDate;
}
public void setValidToDate(Instant validToDate) {
public void setValidToDate(LocalDate validToDate) {
this.validToDate = validToDate;
}

View file

@ -0,0 +1,49 @@
package ru.spcex.clearing.backendapi.controller.response.entity.dictionary;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import ru.clearing.platform.dictionary.AbstractDictionary;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ApiModel(description = "Ответ при получении объектов словаря.")
public class DictionaryBackendGetAll extends BasicSpcexResponse {
@JsonProperty
@ApiModelProperty(value = "Полезная нагрузка")
private DictionaryBackendPayload payload = new DictionaryBackendPayload();
public void fromEntity(Collection<AbstractDictionary> dictionaryValues) {
var payload = this.getPayload();
for (AbstractDictionary dictionaryValue : dictionaryValues) {
var singleItem = new DictionaryBackendGetFields();
singleItem.fromEntity(dictionaryValue);
payload.getItems().add(singleItem);
}
}
private static class DictionaryBackendPayload {
private List<DictionaryBackendGetFields> items = new ArrayList<>();
public List<DictionaryBackendGetFields> getItems() {
return items;
}
public void setItems(List<DictionaryBackendGetFields> items) {
this.items = items;
}
}
public DictionaryBackendPayload getPayload() {
return payload;
}
public void setPayload(DictionaryBackendPayload payload) {
this.payload = payload;
}
}

View file

@ -0,0 +1,48 @@
package ru.spcex.clearing.backendapi.controller.response.entity.dictionary;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import ru.clearing.platform.dictionary.AbstractDictionary;
public class DictionaryBackendGetFields {
@JsonProperty
@ApiModelProperty(value = "Идентификатор", example = "1234")
private Long id;
@JsonProperty
@ApiModelProperty(value = "", example = "")
private String code;
@JsonProperty
@ApiModelProperty(value = "Имя банка", example = "Сбербанк")
private String name;
public void fromEntity(AbstractDictionary dictionaryValue) {
this.id = dictionaryValue.getId();
this.code = dictionaryValue.getCode();
this.name = dictionaryValue.getName();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View file

@ -0,0 +1,30 @@
package ru.spcex.clearing.backendapi.controller.response.entity.dictionary;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import ru.clearing.platform.dictionary.AbstractDictionary;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
@ApiModel(description = "Ответ при получении объекта BankAccount.")
public class DictionaryBackendGetSingleValue extends BasicSpcexResponse {
@JsonProperty
@ApiModelProperty(value = "Поля объекта")
private DictionaryBackendGetFields payload;
public DictionaryBackendGetFields getPayload() {
return payload;
}
public void fromEntity(AbstractDictionary dictionaryValue) {
var payload = new DictionaryBackendGetFields();
this.setPayload(payload);
payload.fromEntity(dictionaryValue);
}
public void setPayload(DictionaryBackendGetFields payload) {
this.payload = payload;
}
}

View file

@ -2,9 +2,11 @@ package ru.spcex.clearing.backendapi.controller.response.entity.schedule;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalTimeSerializer;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
public class SchedulerAllTodayBackendGetFields {
@JsonProperty
@ -12,11 +14,11 @@ public class SchedulerAllTodayBackendGetFields {
@JsonProperty
private String task;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant taskTime;
@JsonSerialize(using = LocalTimeSerializer.class)
private LocalTime taskTime;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant clearingDate;
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate clearingDate;
@JsonProperty
private String market;
@JsonProperty
@ -44,19 +46,19 @@ public class SchedulerAllTodayBackendGetFields {
this.task = task;
}
public Instant getTaskTime() {
public LocalTime getTaskTime() {
return taskTime;
}
public void setTaskTime(Instant taskTime) {
public void setTaskTime(LocalTime taskTime) {
this.taskTime = taskTime;
}
public Instant getClearingDate() {
public LocalDate getClearingDate() {
return clearingDate;
}
public void setClearingDate(Instant clearingDate) {
public void setClearingDate(LocalDate clearingDate) {
this.clearingDate = clearingDate;
}

View file

@ -3,8 +3,12 @@ package ru.spcex.clearing.backendapi.controller.response.entity.schedule;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalTimeSerializer;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
public class SchedulerBackendGetFields {
@JsonProperty
@ -12,11 +16,11 @@ public class SchedulerBackendGetFields {
@JsonProperty
private String task;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant taskTime;
@JsonSerialize(using = LocalTimeSerializer.class)
private LocalTime taskTime;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant clearingDate;
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate clearingDate;
@JsonProperty
private String market;
@JsonProperty
@ -46,19 +50,19 @@ public class SchedulerBackendGetFields {
this.task = task;
}
public Instant getTaskTime() {
public LocalTime getTaskTime() {
return taskTime;
}
public void setTaskTime(Instant taskTime) {
public void setTaskTime(LocalTime taskTime) {
this.taskTime = taskTime;
}
public Instant getClearingDate() {
public LocalDate getClearingDate() {
return clearingDate;
}
public void setClearingDate(Instant clearingDate) {
public void setClearingDate(LocalDate clearingDate) {
this.clearingDate = clearingDate;
}

View file

@ -3,8 +3,10 @@ package ru.spcex.clearing.backendapi.controller.response.entity.schedule;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalTimeSerializer;
import java.time.Instant;
import java.time.LocalTime;
public class TimetableBackendGetFields {
@JsonProperty
@ -12,8 +14,8 @@ public class TimetableBackendGetFields {
@JsonProperty
private String task;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant taskTime;
@JsonSerialize(using = LocalTimeSerializer.class)
private LocalTime taskTime;
@JsonProperty
private String taskStatus;
@JsonProperty
@ -39,11 +41,11 @@ public class TimetableBackendGetFields {
this.task = task;
}
public Instant getTaskTime() {
public LocalTime getTaskTime() {
return taskTime;
}
public void setTaskTime(Instant taskTime) {
public void setTaskTime(LocalTime taskTime) {
this.taskTime = taskTime;
}

View file

@ -3,15 +3,17 @@ package ru.spcex.clearing.backendapi.controller.response.entity.schedule;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import java.time.Instant;
import java.time.LocalDate;
public class TradingCalendarBackendGetFields {
@JsonProperty
private Long id;
@JsonProperty
@JsonSerialize(using = InstantSerializer.class)
private Instant clearingDate;
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate clearingDate;
@JsonProperty
private Long companyId;
@JsonProperty
@ -31,11 +33,11 @@ public class TradingCalendarBackendGetFields {
this.id = id;
}
public Instant getClearingDate() {
public LocalDate getClearingDate() {
return clearingDate;
}
public void setClearingDate(Instant clearingDate) {
public void setClearingDate(LocalDate clearingDate) {
this.clearingDate = clearingDate;
}

View file

@ -2,10 +2,10 @@ package ru.spcex.clearing.backendapi.controller.response.entity.securities;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
public class MoneyMarketSecurityBackendGetFields {
@JsonProperty
@ -14,12 +14,12 @@ public class MoneyMarketSecurityBackendGetFields {
private Long securityId;// (linked to security)
@JsonProperty
private String description;
@JsonSerialize(using = InstantSerializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
@JsonProperty
private Instant startDate;
@JsonSerialize(using = InstantSerializer.class)
private LocalDate startDate;
@JsonSerialize(using = LocalDateSerializer.class)
@JsonProperty
private Instant endDate;
private LocalDate endDate;
@JsonProperty
private BigDecimal nominalValue;
@JsonProperty
@ -55,19 +55,19 @@ public class MoneyMarketSecurityBackendGetFields {
this.description = description;
}
public Instant getStartDate() {
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(Instant startDate) {
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public Instant getEndDate() {
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(Instant endDate) {
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}

View file

@ -42,7 +42,7 @@ public class KeyRateBackendGetAll extends BasicSpcexResponse {
for (var keyRate : keyRates) {
var singleItem = new KeyRateBackendGetFields();
singleItem.setId(keyRate.getId());
singleItem.setRate(keyRate.getRate());
singleItem.setKeyRate(keyRate.getRate());
singleItem.setStartDate(keyRate.getStartDate());
singleItem.setEndDate(keyRate.getEndDate());
singleItem.setDocument(keyRate.getDocument());

View file

@ -2,21 +2,22 @@ package ru.spcex.clearing.backendapi.controller.response.entity.utilities;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import java.time.Instant;
import java.math.BigDecimal;
import java.time.LocalDate;
public class KeyRateBackendGetFields {
@JsonProperty
private Long id;
@JsonProperty
private Double rate;
@JsonSerialize(using = InstantSerializer.class)
private BigDecimal keyRate;
@JsonSerialize(using = LocalDateSerializer.class)
@JsonProperty
private Instant startDate;
@JsonSerialize(using = InstantSerializer.class)
private LocalDate startDate;
@JsonSerialize(using = LocalDateSerializer.class)
@JsonProperty
private Instant endDate;
private LocalDate endDate;
@JsonProperty
private String document;
@JsonProperty
@ -30,27 +31,27 @@ public class KeyRateBackendGetFields {
this.id = id;
}
public Double getRate() {
return rate;
public BigDecimal getKeyRate() {
return keyRate;
}
public void setRate(Double rate) {
this.rate = rate;
public void setKeyRate(BigDecimal keyRate) {
this.keyRate = keyRate;
}
public Instant getStartDate() {
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(Instant startDate) {
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public Instant getEndDate() {
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(Instant endDate) {
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}

View file

@ -0,0 +1,51 @@
package ru.spcex.clearing.backendapi.controller.response.system;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.EnumSerializer;
import ru.spcex.clearing.platform.messaging.service.Status;
/**
* Банковские реквизиты для перечисления денежных средств
* @ApiModel(description = "Ответ в результате отправки операции в топик Kafka.")
* @ApiModelProperty(value = "Информация о принятом запросе")
**/
@ApiModel(description = "Ответ при получении статуса запроса.")
public class RequestInfoResponse extends BasicSpcexResponse {
@JsonProperty
@ApiModelProperty(value = "Поля объекта")
private RequestInfoPayload payload;
public RequestInfoPayload getPayload() {
return payload;
}
public void setStatus(Status status) {
this.payload = new RequestInfoPayload();
payload.setStatus(status);
}
public void setPayload(RequestInfoPayload payload) {
this.payload = payload;
}
private static class RequestInfoPayload {
@JsonProperty
@JsonSerialize(using = EnumSerializer.class)
private Status status;
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
}
}

View file

@ -0,0 +1,139 @@
package ru.spcex.clearing.backendapi.controller.system;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import ru.clearing.platform.dictionary.AbstractDictionary;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.dictionary.DictionaryBackendGetAll;
import ru.spcex.clearing.backendapi.controller.response.entity.dictionary.DictionaryBackendGetSingleValue;
import ru.spcex.clearing.backendapi.errors.ActionValidationException;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.backendapi.errors.NotFound404Exception;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Controller
@RequestMapping("/dictionaries")
public class DictionaryController {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Map<String, Imdg<?>> allDictionaryMaps;
private final ImdgProvider imdgProvider;
@Autowired
public DictionaryController(ImdgProvider imdgProvider) {
this.imdgProvider = imdgProvider;
this.allDictionaryMaps = new ConcurrentHashMap<>();
}
@ApiOperation(value = "get all dictionary value.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = DictionaryBackendGetAll.class)})
@RequestMapping(value = "/{dictionary-name}", method = RequestMethod.GET)
@ResponseBody
public DictionaryBackendGetAll getAll(@ApiParam(value = "Название словаря", required = true, example = "moneyFlowSide")
@PathVariable("dictionary-name") String dictionaryName) {
Imdg<AbstractDictionary> dictionary = extractDictionaryImdgFromUrlParameter(dictionaryName, AbstractDictionary.class);
Collection<AbstractDictionary> allValues = dictionary.getAllValues();
DictionaryBackendGetAll response = new DictionaryBackendGetAll();
response.fromEntity(allValues);
return response;
}
@ApiOperation(value = "get dictionary value by id.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = DictionaryBackendGetSingleValue.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(value = "/{dictionary-name}/{id}", method = RequestMethod.GET)
@ResponseBody
public DictionaryBackendGetSingleValue getById(@ApiParam(value = "Название словаря", required = true, example = "moneyFlowSide")
@PathVariable("dictionary-name") String dictionaryName,
@ApiParam(value = "Идентификатор объекта", required = true, example = "1234")
@PathVariable("id") Long id) {
Imdg<AbstractDictionary> dictionary = extractDictionaryImdgFromUrlParameter(dictionaryName, AbstractDictionary.class);
AbstractDictionary value = dictionary.getSingleObjectByID(id);
if (value == null) throw new NotFound404Exception(dictionaryName + " id='" + id + "'");
DictionaryBackendGetSingleValue response = new DictionaryBackendGetSingleValue();
response.fromEntity(value);
return response;
}
@ApiOperation(value = "get dictionary value by code.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = DictionaryBackendGetSingleValue.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(value = "/{dictionary-name}/code/{code}", method = RequestMethod.GET)
@ResponseBody
public DictionaryBackendGetSingleValue getByCode(@ApiParam(value = "Название словаря", required = true, example = "moneyFlowSide")
@PathVariable("dictionary-name") String dictionaryName,
@ApiParam(value = "Код словаря", required = true, example = "1234")
@PathVariable("code") String code) {
Imdg<AbstractDictionary> dictionary = extractDictionaryImdgFromUrlParameter(dictionaryName, AbstractDictionary.class);
AbstractDictionary value = dictionary.getSingleObjectByFieldValues(Map.of("code", code));
if (value == null) throw new NotFound404Exception(dictionaryName + " code='" + code + "'");
DictionaryBackendGetSingleValue response = new DictionaryBackendGetSingleValue();
response.fromEntity(value);
return response;
}
@SuppressWarnings("unchecked")
private <T extends SpcexObjectBase> Imdg<T> extractDictionaryImdgFromUrlParameter(String dictionaryNameFromUrl, Class<T> clazz) {
if (dictionaryNameFromUrl == null || dictionaryNameFromUrl.length() < 1) {
throw new ActionValidationException(BackEndError.ValidationError, "dictionary-name");
}
String actualDictionaryName = "Map_"
+ dictionaryNameFromUrl.substring(0, 1).toUpperCase()
+ dictionaryNameFromUrl.substring(1)
+ "Dictionary";
Imdg<T> dictionary = (Imdg<T>) allDictionaryMaps.computeIfAbsent(actualDictionaryName, (mapName1) -> {
Imdg<T> potentialImdg = imdgProvider.getImdg(actualDictionaryName, clazz);
if (potentialImdg.size() == 0) {
log.warn("coudln't find dictionary {}", actualDictionaryName);
return null;
}
return potentialImdg;
});
if (dictionary == null) {
throw new ActionValidationException(BackEndError.DictionaryNotFound, dictionaryNameFromUrl);
}
return dictionary;
}
@Autowired
private IMessageResolver errorResolver;
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
@ExceptionHandler(ActionValidationException.class)
public BasicSpcexResponse conflict(ActionValidationException ex) {
BasicSpcexResponse response = new BasicSpcexResponse();
EnumMessage message = ex.getErrors().stream().findFirst().orElseThrow();
response.setCode(message.getSubject().getId());
response.setMessage(errorResolver.resolve(message));
return response;
}
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ResponseBody
@ExceptionHandler(NotFound404Exception.class)
public BasicSpcexResponse conflict(NotFound404Exception ex) {
BasicSpcexResponse response = new BasicSpcexResponse();
EnumMessage message = ex.getError();
response.setCode(message.getSubject().getId());
response.setMessage(errorResolver.resolve(message));
return response;
}
}

View file

@ -0,0 +1,31 @@
package ru.spcex.clearing.backendapi.controller.system;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/meta")
public class MetaController {
private final String metaRawJson;
@Autowired
public MetaController(@Qualifier("metaJson") String meta) {
this.metaRawJson = meta;
}
@ApiOperation(value = "get meta.json")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK")})
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String getAll() {
return metaRawJson;
}
}

View file

@ -0,0 +1,48 @@
package ru.spcex.clearing.backendapi.controller.system;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.system.RequestInfoResponse;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
@Controller
@RequestMapping("/requests")
public class RequestStatusController {
private final Imdg<RequestInfo> imdg;
@Autowired
public RequestStatusController(ImdgProvider imdgProvider) {
this.imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
}
@ApiOperation(value = "get request status.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = RequestInfoResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public RequestInfoResponse getById(@ApiParam(value = "Идентификатор объекта", required = true, example = "1234")
@PathVariable("id") Long id) {
RequestInfo singleObjectByID;
if (id == null || (singleObjectByID = imdg.getSingleObjectByID(id)) == null) {
RequestInfoResponse response = new RequestInfoResponse();
response.setCode(-1L);
response.setMessage("cannot find request with id='" + id + "'.");
return response;
}
RequestInfoResponse response = new RequestInfoResponse();
response.setStatus(singleObjectByID.getStatus());
return response;
}
}

View file

@ -1,6 +1,7 @@
package ru.spcex.clearing.backendapi.errors;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import java.util.Collection;
import java.util.List;
@ -16,6 +17,10 @@ public class ActionValidationException extends RuntimeException {
this.errors = List.of(error);
}
public ActionValidationException(IEnumId subject, Object... args) {
this.errors = List.of(new EnumMessage(subject, args));
}
public Collection<EnumMessage> getErrors() {
return errors;
}

View file

@ -3,10 +3,13 @@ package ru.spcex.clearing.backendapi.errors;
import ru.spcex.platform.utils.enumeration.IEnumId;
public enum BackEndError implements IEnumId {
ValidationError(3000L),
UnknownJsonProperty(3001L),
FailedToReadHttpMessage(3002L),
KeycloakRepeatedRoles(3003L);
ValidationError(9000L),
UnknownJsonProperty(9001L),
FailedToReadHttpMessage(9002L),
KeycloakRepeatedRoles(9003L),
DictionaryNotFound(9004L),
ResourceNotFound(9005L)
;
private final Long id;
BackEndError(Long id) {

View file

@ -0,0 +1,16 @@
package ru.spcex.clearing.backendapi.errors;
import ru.spcex.platform.utils.enumeration.EnumMessage;
public class NotFound404Exception extends RuntimeException {
private final EnumMessage error;
public NotFound404Exception(String comment) {
this.error = new EnumMessage(BackEndError.ResourceNotFound, comment);
}
public EnumMessage getError() {
return error;
}
}

View file

@ -70,7 +70,7 @@ public class ClearingCorsFilter extends OncePerRequestFilter {
// } else {
// methods = "*";
// }
// setHeaderValue(httpServletResponse, H_ACCESS_CONTROL_ALLOW_METHODS, methods);
setHeaderValue(httpServletResponse, H_ACCESS_CONTROL_ALLOW_METHODS, "*");
// String headers;
// if (head.length > 0) {
@ -78,7 +78,7 @@ public class ClearingCorsFilter extends OncePerRequestFilter {
// } else {
// headers = "*";
// }
// setHeaderValue(httpServletResponse, H_ACCESS_CONTROL_ALLOW_HEADERS, headers);
setHeaderValue(httpServletResponse, H_ACCESS_CONTROL_ALLOW_HEADERS, "*");
setHeaderValue(httpServletResponse, H_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
log.trace("cors filter -> added ok");

View file

@ -27,13 +27,11 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import ru.spcex.clearing.backendapi.service.UserAuthProcessor;
import ru.spcex.platform.enumeration.UserRole;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
@Component("keycloakRestAuthenticationProvider")
@ -44,6 +42,13 @@ public class KeycloakRestTemplateAuthenticationProvider implements Authenticatio
private final HttpServletResponse currentHttpResponse;
private final RestTemplate restTemplate;
private final UserAuthProcessor userAutoCreation;
private final static Map<String, UserRole> roleMapping = new HashMap<>();
static {
roleMapping.put("CS_MKR_ADMIN", UserRole.Admin);
roleMapping.put("CS_MKR_SUPERVISER", UserRole.Superviser);
roleMapping.put("CS_MKR_SECURITY", UserRole.Security);
}
public KeycloakRestTemplateAuthenticationProvider(KeycloakConfigResolver resolver, HttpServletRequest currentHttpRequest, HttpServletResponse currentHttpResponse,
@Qualifier("clearing-rest") RestTemplate restTemplate, UserAuthProcessor userAutoCreation) {
@ -82,16 +87,28 @@ public class KeycloakRestTemplateAuthenticationProvider implements Authenticatio
AccessToken accessToken = AdapterTokenVerifier.verifyToken(accessTokenString, deployment);
//todo cors settings
accessToken.setAllowedOrigins(Collections.singleton("*"));
List<SimpleGrantedAuthority> realmRoles = accessToken.getRealmAccess().getRoles().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
RefreshableKeycloakSecurityContext skSession = new RefreshableKeycloakSecurityContext(deployment, null, accessTokenString, accessToken, null, null, refreshTokenString);
String principalName = AdapterUtils.getPrincipalName(deployment, accessToken);
final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<>(principalName, skSession);
final Set<String> roles = AdapterUtils.getRolesFromSecurityContext(skSession);
final KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, skSession);
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(skSession);
Set<String> effectiveRoles = roles
.stream()
.map(s -> {
UserRole userRole = roleMapping.get(s);
return userRole != null ? userRole.getKey() : null;
})
.filter(Objects::nonNull)
.collect(Collectors.toSet());
List<SimpleGrantedAuthority> realmRoles = effectiveRoles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
final KeycloakAccount account = new SimpleKeycloakAccount(principal, effectiveRoles, skSession);
KeycloakAuthenticationToken keycloakAuthenticationToken = new KeycloakAuthenticationToken(account, false, realmRoles);
keycloakAuthenticationToken.setAuthenticated(true);
log.debug("login successful: login {}, roles {}", principalName, String.join(";", roles));
log.debug("login successful: login {}, roles from keycloak: {}; effective roles {}",
authentication.getName(),
String.join(";", roles),
String.join(";", effectiveRoles)
);
return keycloakAuthenticationToken;
} catch (VerificationException vex) {

View file

@ -0,0 +1,20 @@
package ru.spcex.clearing.backendapi.security;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.spi.KeycloakAccount;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.security.core.Authentication;
public class KeycloakUtils {
/**
* Достать username из Keycloak имплементации Authentication
*/
public static String getUserNameFromAuthentication(Authentication authentication) {
KeycloakAuthenticationToken auth = (KeycloakAuthenticationToken) authentication;
KeycloakAccount details = (KeycloakAccount) auth.getDetails();
return ((KeycloakPrincipal) details.getPrincipal())
.getKeycloakSecurityContext()
.getToken()
.getPreferredUsername();
}
}

View file

@ -18,6 +18,7 @@ import org.springframework.security.web.authentication.session.SessionAuthentica
import ru.spcex.clearing.backendapi.config.element.BackendApiSettings;
import ru.spcex.clearing.backendapi.security.handlers.AuthAuditSuccessLoginHandler;
import ru.spcex.clearing.backendapi.security.handlers.LogoutAuditSuccessHandler;
import ru.spcex.platform.enumeration.UserRole;
@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ -68,7 +69,7 @@ public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
if (securityDisabled) {
anyReq.permitAll();
} else {
anyReq.hasAnyRole("admin", "default-roles-master")
anyReq.hasAnyRole(UserRole.Admin.getKey(), UserRole.Security.getKey(), UserRole.Superviser.getKey())
.and()
.formLogin()
.successHandler(loginSuccessHandler)

View file

@ -2,6 +2,7 @@ package ru.spcex.clearing.backendapi.security.element;
public class SecuritySettings {
private Boolean authorizationDisabled = false;
private String sameSite;
public Boolean getAuthorizationDisabled() {
return authorizationDisabled;
@ -10,4 +11,12 @@ public class SecuritySettings {
public void setAuthorizationDisabled(Boolean authorizationDisabled) {
this.authorizationDisabled = authorizationDisabled;
}
public String getSameSite() {
return sameSite;
}
public void setSameSite(String sameSite) {
this.sameSite = sameSite;
}
}

View file

@ -0,0 +1,48 @@
package ru.spcex.clearing.backendapi.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.stereotype.Service;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
@Service
public class RequestInfoAccepter extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<RequestInfo> requestInfoImdg;
public RequestInfoAccepter(Consumer<String, Object> kafkaQueue, ImdgProvider imdgProvider) {
super(kafkaQueue);
this.requestInfoImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
}
@Override
public void afterPropertiesSet() throws Exception {
callback(RequestInfoUpdate.class)
.setConsumer(this::updateRequestInfo)
.forDestination(Consts.REQUEST_INFO_UPDATE, callbacks::put);
init();
}
private void updateRequestInfo(BaseRequest<RequestInfoUpdate> requestInfoUpdateBaseRequest) {
//will throw exception for any class other than RequestInfoUpdate
RequestInfoUpdate statusInfo = requestInfoUpdateBaseRequest.getRequestPayload();
RequestInfo requestInfo = requestInfoImdg.getSingleObjectByID(statusInfo.getId());
if (requestInfo == null) {
log.warn("unknown requestInfo id={}", statusInfo.getId());
return;
}
requestInfo.setStatus(statusInfo.getStatus());
requestInfoImdg.update(requestInfo);
}
}

View file

@ -7,13 +7,18 @@ import org.springframework.stereotype.Service;
import ru.spcex.clearing.backendapi.controller.response.cud.QueueSuccessResponse;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.ActionValidationException;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.backendapi.errors.NotFound404Exception;
import ru.spcex.clearing.backendapi.service.IOperator;
import ru.spcex.clearing.backendapi.service.validation.ActionValidationProvider;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
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.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidator;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
@ -24,16 +29,18 @@ public class OperatorImpl implements IOperator {
private final Producer<String, Object> kafka;
private final ImdgId idGenerator;
private final ImdgProvider imdgProvider;
private final ActionValidationProvider validation;
public OperatorImpl(Producer<String, Object> kafka, ImdgProvider imdgProvider) {
public OperatorImpl(Producer<String, Object> kafka, ImdgProvider imdgProvider, ActionValidationProvider validation) {
this.kafka = kafka;
this.idGenerator = imdgProvider.getImdgIdGenerator();
this.imdgProvider = imdgProvider;
this.validation = validation;
}
@Override
public QueueSuccessResponse sendRequestToQueue(String destination, IAction<?> iAction) throws ExecutionException, InterruptedException {
throwValidate(iAction);
throwValidate(destination, iAction);
BaseRequest<Object> request = new BaseRequest<>();
request.setId(idGenerator.nextId());
request.setActionType(iAction.getActionType());
@ -46,15 +53,25 @@ public class OperatorImpl implements IOperator {
}
private void saveRequestToStorage(String destination, BaseRequest<Object> request) {
Imdg<RequestInfo> requestStorage = imdgProvider.getImdg(destination, RequestInfo.class);
Imdg<RequestInfo> requestStorage = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
RequestInfo requestInfo = RequestInfo.create(request.getId());
requestStorage.insert(requestInfo);
}
private void throwValidate(IAction<?> iAction) {
private void throwValidate(String destination, IAction<?> iAction) {
Collection<EnumMessage> validationErrors = iAction.validate();
if (validationErrors.size() > 0) {
throw new ActionValidationException(validationErrors);
}
IValidator validator = validation.getValidator(destination, iAction);
if (validator != null) {
validator.tillFirstError().ifPresent(enumMessage -> {
if (enumMessage.getSubject().equalsById(BackEndError.ResourceNotFound.getId())) {
throw new NotFound404Exception((String) enumMessage.getArgs()[0]);
} else {
throw new ActionValidationException(enumMessage);
}
});
}
}
}

View file

@ -0,0 +1,82 @@
package ru.spcex.clearing.backendapi.service.validation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import ru.clearing.platform.dictionary.AbstractDictionary;
import ru.spcex.clearing.backendapi.controller.request.cud.schedule.TaskRunnerNew;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.service.validation.rules.PresentById;
import ru.spcex.clearing.backendapi.service.validation.rules.TaskRunnerNewValidationRule;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.classes.base.interfaces.WithId;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class ActionValidationProvider implements InitializingBean {
private final Map<String, Imdg<?>> allImdgMaps;
private final ImdgProvider imdgProvider;
private final Map<String, Function<?, IValidator>> validators;
public ActionValidationProvider(ImdgProvider imdgProvider) {
this.validators = new HashMap<>();
this.allImdgMaps = new HashMap<>();
this.imdgProvider = imdgProvider;
}
@Override
public void afterPropertiesSet() {
getImdg(IMDGDistributedNames.Map_TaskDictionary, AbstractDictionary.class);
getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, SpcexObjectBase.class);
validators.put(Consts.DESTINATION_MONEY_MARKET_SECURITY_UPDATE, idPresent(IMDGDistributedNames.Map_MoneyMarketSecurity));
validators.put(Consts.DESTINATION_MONEY_MARKET_SECURITY_DELETE, idPresent(IMDGDistributedNames.Map_MoneyMarketSecurity));
validators.put(Consts.TASK_RUNNER_NEW, taskRunnerNew());
}
@SuppressWarnings("unchecked")
public IValidator getValidator(String destination, Object action) {
Function<Object, IValidator> constructor = (Function<Object, IValidator>) validators.get(destination);
if (constructor != null)
return constructor.apply(action);
return null;
}
private <T extends IAction<?> & WithId> Function<T, IValidator> idPresent(String mapName) {
return iAction -> {
ImdgValidationContext<T> ctx = new ImdgValidationContext<>();
ctx.setValidatedObject(iAction);
ValidatorImpl<ImdgValidationContext<T>> iValidator = new ValidatorImpl<>(ctx);
iValidator.addRule(new PresentById(getImdg(mapName, SpcexObjectBase.class)));
return iValidator;
};
}
private Function<TaskRunnerNew, IValidator> taskRunnerNew() {
return taskRunnerNew -> {
ImdgValidationContext<TaskRunnerNew> ctx = new ImdgValidationContext<>();
ctx.setValidatedObject(taskRunnerNew);
ctx.addImdg(IMDGDistributedNames.Map_TaskDictionary, getImdg(IMDGDistributedNames.Map_TaskDictionary, AbstractDictionary.class));
ValidatorImpl<ImdgValidationContext<TaskRunnerNew>> iValidator = new ValidatorImpl<>(ctx);
iValidator.addRule(TaskRunnerNewValidationRule.knownTaskDictionary);
return iValidator;
};
}
@SuppressWarnings("unchecked")
private <T extends SpcexObjectBase> Imdg<T> getImdg(String mapName, Class<T> clazz) {
return (Imdg<T>) allImdgMaps.computeIfAbsent(mapName, (mapName1) -> imdgProvider.getImdg(mapName, clazz));
}
}

View file

@ -0,0 +1,28 @@
package ru.spcex.clearing.backendapi.service.validation.rules;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.classes.base.interfaces.WithId;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Optional;
public class PresentById implements IValidationRule<ImdgValidationContext<WithId>> {
private final Imdg<SpcexObjectBase> map;
public PresentById(Imdg<SpcexObjectBase> map) {
this.map = map;
}
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<WithId> context) {
WithId actionById = context.getValidatedObject();
if (map.getSingleObjectByID(actionById.getId()) == null) {
return of(BackEndError.ResourceNotFound, actionById.getId());
} else {
return empty();
}
}
}

View file

@ -0,0 +1,33 @@
package ru.spcex.clearing.backendapi.service.validation.rules;
import ru.clearing.platform.dictionary.AbstractDictionary;
import ru.spcex.clearing.backendapi.controller.request.cud.schedule.TaskRunnerNew;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Map;
import java.util.Optional;
public enum TaskRunnerNewValidationRule implements IValidationRule<ImdgValidationContext<TaskRunnerNew>> {
knownTaskDictionary() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<TaskRunnerNew> context) {
TaskRunnerNew validatedObject = context.getValidatedObject();
Imdg<AbstractDictionary> taskDictionaryImdg = context.obtainMap(IMDGDistributedNames.Map_TaskDictionary, AbstractDictionary.class);
AbstractDictionary taskEnum = taskDictionaryImdg.getSingleObjectByFieldValues(Map.of("code", validatedObject.getTask()));
if (taskEnum == null) {
return of(BackEndError.ResourceNotFound, "taskDictionary " + validatedObject.getTask());
}
return empty();
}
};
@Override
public String ruleName() {
return "TaskRunnerNewValidationRule." + name();
}
}

View file

@ -1,5 +1,9 @@
server.port=8080
server.servlet.context-path=/backend-api
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore/client.p12
server.ssl.key-store-password=Aa123456
server.ssl.enabled=true
spring.main.web-application-type=servlet
backend-api.example-setting=test
@ -8,14 +12,22 @@ backend-api.hazelcast.cluster-members=127.0.0.1:5701
backend-api.hazelcast.login=dev
backend-api.hazelcast.password=dev-pass
backend-api.kafka.bootstrap-servers=localhost:9092
backend-api.kafka.acks=all
backend-api.kafka.retries=0
backend-api.kafka.batch-size=16384
backend-api.kafka.linger-ms=1
backend-api.kafka.buffer-memory=33554432
backend-api.kafka-producer.bootstrap-servers=localhost:9092
backend-api.kafka-producer.acks=all
backend-api.kafka-producer.retries=0
backend-api.kafka-producer.batch-size=16384
backend-api.kafka-producer.linger-ms=1
backend-api.kafka-producer.buffer-memory=33554432
backend-api.security.authorization-disabled=true
backend-api.kafka-consumer.bootstrap-servers=localhost:9092
backend-api.kafka-consumer.group-id=dev-group-backend-api
backend-api.kafka-consumer.enable-auto-commit=true
backend-api.kafka-consumer.session-timeout-ms=30000
backend-api.kafka-consumer.auto-offset-reset=latest
backend-api.kafka-consumer.linger-ms=1
backend-api.kafka-consumer.buffer-memory=33554432
backend-api.security.authorization-disabled=false
##keycloak

View file

@ -1,237 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<meta version="0.0.0.0">
<enums>
<courierType id="1" code="POST" name="Почтой"/>
<courierType id="2" code="CAB" name="Личный кабинет с ЭЦП"/>
<courierType id="3" code="ORIG" name="Оригинал на бумаге"/>
<courierType id="3" code="STHS" name="Модуль обмена с Расчетной Организацией"/>
<termType id="1" code="S" name="Срочный"/>
<termType id="2" code="K" name="Комбинированный"/>
<termType id="3" code="V" name="До востребования"/>
<task id="1" code="GBAL" name="Зачисление остатков"/>
<task id="2" code="" name=""/>
<task id="3" code="ABLK" name="Блокировка счета"/>
<task id="4" code="GALB" name="Запрос остатков по всем счетам"/>
<taskStatus id="1" code="ACTV" name="Активна"/>
<taskStatus id="2" code="BLKD" name="Не активна"/>
<taskStatus id="3" code="CNCL" name="Отмена расписания"/>
<tradingStatus id="1" code="TRAD" name="Торговый"/>
<tradingStatus id="2" code="NTRD" name="Неторговый"/>
<source id="1" code="TIMT" name="Расписание"/>
<source id="2" code="SCHD" name="Планировщик"/>
<chargeType id="1" code="PRCT" name="Процент"/>
<chargeDirection id="1" code="GET" name="Получить"/>
<chargeDirection id="2" code="PAY" name="Заплатить"/>
<clearingStatus id="1" code="OK" name="Успешно"/>
<clearingStatus id="2" code="FAIL" name="Не успешно"/>
<clearingStatus id="3" code="MNG" name="Не учитывать"/>
<clearingStatus id="4" code="PROC" name="К клирингу"/>
<interestStatus id="1" code="FREE" name="Не требуется"/>
<interestStatus id="2" code="RTND" name="Возвращены"/>
<interestStatus id="3" code="DFLT" name="Не возвращены"/>
<workflowStatus id="1" code="ACTV" name="Активен"/>
<workflowStatus id="2" code="BLKD" name="Не активен"/>
<moneyFlowSide id="1" code="SELL" name="Привлечь"/>
<moneyFlowSide id="2" code="BUY" name="Разместить"/>
<balanceAccountType id="1" code="ACNT" name="Остатки по счетам"/>
<inOutDirection id="1" code="IN" name="Зачисление"/>
<inOutDirection id="2" code="OUT" name="Списание"/>
<moneyFlowSide id="1" code="BUY" name="Разместить"/>
<moneyFlowSide id="2" code="SELL" name="Привлечь"/>
<allowed id="1" code="ALWD" name="Разрешено"/>
<allowed id="2" code="DEND" name="Запрещено"/>
<serviceStatus id="1" code="ACTV" name="Активен"/>
<serviceStatus id="2" code="BLKD" name="Заблокирован"/>
<serviceStatus id="3" code="SSPD" name="Приостановлен"/>
<serviceStatus id="4" code="CLOS" name="Закрыт"/>
<serviceStatus id="4" code="ROPN" name="Возобновлен"/>
<statementType id="1" code="FULL" name="Установка суммы"/>
<statementType id="2" code="INCR" name="Изменение суммы"/>
<operationType id="1" code="STMT" name="Расчетные операции"/>
<operationType id="2" code="TRAD" name="Торговые операции"/>
<operationStatus id="1" code="PEND" name="В ожидании"/>
<operationStatus id="2" code="RJCT" name="Отклонена"/>
<operationStatus id="3" code="EXEC" name="Исполнена"/>
<service id="1" code="MKR" name="Денежный рынок МКР"/>
<serviceProduct id="1" code="PRNT" name="Расчет обязательств с процентом"/>
<serviceProduct id="2" code="ZERO" name="Расчет обязательств без процента"/>
<clearingCategory id="1" code="C" name="Категория «Ц» - Банк России"/>
<clearingCategory id="2" code="B" name="Категория «Б» - Кредитная организация ДР"/>
<clearingCategory id="3" code="F" name="Категория «Ф» - Участник рынка РЦБ"/>
<clearingCategory id="4" code="I" name="Категория «И» - Инициатор по ТБС"/>
<clearingCategory id="5" code="V" name="Категория «В» - Инициатор по ТКС"/>
<clearingCategory id="6" code="T" name="Категория «Т» - Участник товарного рынка"/>
<clearingCategory id="7" code="K" name="Категория «К» - Участник клиринга - Контроллер"/>
<managementJournalType id="1" code="CRPA" name="Корпоративное событие, связанное с допуском"/>
<managementJournalType id="2" code="DFLT" name="Отсутствие возврата по платежу"/>
<managementJournalType id="3" code="NOTC" name="Генерация уведомления"/>
<managementJournalType id="4" code="SETL" name="Взаимодействие с расчетной организацией"/>
<contactType id="1" code="ADRS" name="Адрес местонахождения"/>
<contactType id="2" code="POST" name="Почтовый адрес"/>
<contactType id="3" code="CONT" name="Контактное лицо"/>
<contactType id="4" code="MAIL" name="Электронная почта"/>
<contactType id="5" code="PHON" name="Телефон"/>
<contactType id="6" code="GDIR" name="Генеральный директор"/>
<contactType id="7" code="TRST" name="Доверенное лицо"/>
<contactType id="8" code="FAX" name="Факс"/>
<contactType id="9" code="INFO" name="Контактная информация"/>
<contactType id="10" code="CMNT" name="Примечание"/>
<corporationSoleType id="1" code="PRSD" name="Президент"/>
<corporationSoleType id="2" code="GDIR" name="Генеральный директор"/>
<corporationSoleType id="3" code="CMAN" name="Председатель правления"/>
<corporationSoleType id="4" code="MGNT" name="Управляющая компания"/>
<corporationSoleType id="5" code="OTHR" name="Другой"/>
<connectionState id="1" code="CNCT" name="Подключен"/>
<connectionState id="2" code="DSBL" name="Отключен"/>
<documentType id="1" code="PASP" name="Паспорт"/>
<documentType id="2" code="ICRT" name="Удостоверение личности"/>
<documentType id="3" code="PRXY" name="Доверенность"/>
<documentType id="4" code="CNTR" name="Договор клиринга"/>
<documentType id="5" code="REGS" name="Регистрация"/>
<documentType id="6" code="FORM" name="Анкета участника"/>
<documentType id="7" code="OGRN" name="ОГРН"/>
<documentType id="8" code="LICB" name="Банковская лицензия"/>
<documentType id="9" code="LICP" name="Лицензия проф. участника"/>
<documentType id="10" code="PLAC" name="Регистрация по месту пребывания"/>
<documentType id="11" code="INN" name="ИНН"/>
<documentType id="12" code="CIO" name="КИО"/>
<documentType id="13" code="LICR" name="Брокерская лицензия"/>
<documentType id="14" code="FIN" name="Финансовая отчетность"/>
<documentType id="15" code="TRST" name="Полномочия должностных лиц"/>
<documentType id="16" code="PMKR" name="Распоряжение на списание МКР"/>
<documentType id="17" code="TAUT" name="Допуск к торгам"/>
<documentType id="18" code="EDOC" name="Договор об электронном взаимодействии"/>
<documentType id="19" code="XCNT" name="Документ о расторжении Договора клиринга"/>
<legalKind id="1" code="JURD" name="Юридическое лицо"/>
<legalKind id="2" code="PHYS" name="Физическое лицо"/>
<organizationType id="1" code="CRED" name="Кредитная"/>
<organizationType id="2" code="NCRD" name="Некредитная"/>
<companySymbol id="1" code="OCVD" name="Общероссийский классификатор видов экономической деятельности" shortname="ОКВЭД"/>
<companySymbol id="2" code="INN" name="Индивидуальный налоговый номер" shortname="ИНН"/>
<companySymbol id="3" code="CPP" name="Код причины постановки" shortname="КПП"/>
<companySymbol id="4" code="OCPO" name="Общероссийский классификатор предприятий и организаций" shortname="ОКПО"/>
<companySymbol id="5" code="LICP" name="Номер лицензии профессионального участника" shortname="Лицензия профучастника"/>
<companySymbol id="6" code="LICB" name="Номер банковской лицензии" shortname="Лицензия банка"/>
<companySymbol id="7" code="BIC" name="Банковский идентификационный код" shortname="БИК"/>
<companySymbol id="8" code="OGRN" name="Основной государственный регистрационный номер" shortname="ОГРН"/>
<companySymbol id="9" code="CIO" name="Код иностранной организации" shortname="КИО"/>
<companyRole id="1" code="RPRT" name="Отчетная организация"/>
<companyRole id="2" code="CLRH" name="Клиринговая организация"/>
<companyRole id="3" code="EXCH" name="Торговая система"/>
<companyRole id="4" code="SETH" name="Расчетный центр"/>
<companyRole id="5" code="DEPS" name="Депозитарий"/>
<companyRole id="6" code="CLRM" name="Участник клиринга"/>
<userRole id="1" code="ADMN" name="Администратор Клиринга МКР"/>
<userRole id="2" code="SPVS" name="Супервайзер Клиринга МКР"/>
<userRole id="3" code="SCRT" name="Администратор безопасности Клиринга МКР"/>
<accountType id="1" code="CLRN" name="Торговый клиринговый счет"/>
<accountType id="2" code="BANK" name="Текущий банковский счет"/>
<accountType id="3" code="USPD" name="Счет невыясненных поступлений"/>
<accountType id="4" code="CORR" name="Корреспондентский счет"/>
<accountType id="5" code="INFO" name="Информационный счет"/>
<accountType id="6" code="PYER" name="Счет плательщика"/>
<instrumentType id="1" code="RATE" name="Инструмент Денежного рынка"/>
<instrumentType id="2" code="CRNC" name="Валюты"/>
<resultStatus id="1" code="NACK" name="Неуспешно"/>
<resultStatus id="2" code="ACK" name="Успешно"/>
<inOutSDfType id="1" code="0102" name="Входящий DF-01/Исходящий DF-02"/>
<currencyCode id="643" code="RUB" name="Российский рубль"/>
<!-- error code for securities_services -->
<errorCode id="1000" code="1 000" name="Общая ошибка модуля securities_services."/>
<errorCode id="1001" code="1 001" name="Нет прав на проведение данной операции."/>
<errorCode id="1002" code="1 002" name="Не заданы обязательные поля."/>
<errorCode id="1003" code="1 003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="1004" code="1 004" name="Неверное значение поля %s."/>
<errorCode id="1005" code="1 005" name="Такая запись уже существует."/>
<errorCode id="1006" code="1 006" name="Запись не найдена."/>
<errorCode id="1007" code="1 007" name="Пользователь не найден."/>
<errorCode id="1008" code="1 008" name="Пользователь неактивен."/>
<errorCode id="1010" code="1 010" name="Такой Инструмент уже существует."/>
<errorCode id="1011" code="1 011" name="Инструмент не найден."/>
<errorCode id="1012" code="1 012" name="Инструмент неактивен."/>
<!-- error code for utility_service -->
<errorCode id="2000" code="2 000" name="Общая ошибка модуля utility_service"/>
<errorCode id="2001" code="2 001" name="Нет прав на проведение данной операции."/>
<errorCode id="2002" code="2 002" name="Не заданы обязательные поля."/>
<errorCode id="2003" code="2 003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="2004" code="2 004" name="Неверное значение поля %s."/>
<errorCode id="2005" code="2 005" name="Такая запись уже существует."/>
<errorCode id="2006" code="2 006" name="Запись не найдена."/>
<!-- error code for company_services -->
<errorCode id="3000" code="3 000" name="Общая ошибка модуля company_services"/>
<errorCode id="3001" code="3 001" name="Нет прав на проведение данной операции."/>
<errorCode id="3002" code="3 002" name="Не заданы обязательные поля."/>
<errorCode id="3003" code="3 003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="3004" code="3 004" name="Неверное значение поля %s."/>
<errorCode id="3005" code="3 005" name="Такая запись уже существует."/>
<errorCode id="3006" code="3 006" name="Запись не найдена."/>
<errorCode id="3010" code="3 010" name="Такая Компания уже существует"/>
<errorCode id="3011" code="3 011" name="Компания не найдена."/>
<errorCode id="3012" code="3 012" name="Компания неактивна."/>
<errorCode id="3013" code="3 013" name="Профиль Компании не найден."/>
<errorCode id="3014" code="3 014" name="Реквизит Компании не найден."/>
<errorCode id="3015" code="3 015" name="Контакт Компании не найден."/>
<errorCode id="3016" code="3 016" name="Категория Компании не найдена."/>
<errorCode id="3017" code="3 017" name="Компании уже присвоена Категория %s."/>
<!-- error code for report_serivces -->
<errorCode id="4000" code="4 000" name="Общая ошибка модуля report_serivces"/>
<!-- == error code for processing accounts and balances == -->
<!-- error code for account_services -->
<errorCode id="5000" code="5 000" name="Общая ошибка модуля account_services"/>
<errorCode id="5001" code="5 001" name="Нет прав на проведение данной операции."/>
<errorCode id="5002" code="5 002" name="Не заданы обязательные поля."/>
<errorCode id="5003" code="5 003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="5004" code="5 004" name="Неверное значение поля %s."/>
<errorCode id="5005" code="5 005" name="Такая запись уже существует."/>
<errorCode id="5006" code="5 006" name="Запись не найдена."/>
<errorCode id="5010" code="5 010" name="Счет %s уже существует."/>
<errorCode id="5011" code="5 011" name="Счет %s не найден."/>
<errorCode id="5012" code="5 012" name="Счет %s неактивен."/>
<!-- error code for balance_services -->
<errorCode id="5200" code="5 200" name="Общая ошибка модуля balance_services"/>
<errorCode id="5211" code="5 211" name="Компания не найдена."/>
<errorCode id="5212" code="5 212" name="Компания неактивна."/>
<errorCode id="5213" code="5 213" name="Валюта не найдена."/>
<errorCode id="5214" code="5 214" name="Загрузка остатков возможна только на текущую дату."/>
<errorCode id="5215" code="5 215" name="Загрузка остатков возможна только по рынку МКР."/>
<errorCode id="5216" code="5 216" name="Загрузка остатков возможна только по собственным счетам."/>
<errorCode id="5217" code="5 217" name="Счет %s не найден."/>
<errorCode id="5218" code="5 218" name="Счет %s неактивен."/>
<!-- error code for проведение расчетов -->
<errorCode id="5400" code="5 400" name="Общая ошибка модуля проведения расчетов"/>
<!-- error code for dbf-loader -->
<errorCode id="5600" code="5 600" name="Общая ошибка модуля dbf-loader"/>
<!-- error code for dbf-export -->
<errorCode id="5800" code="5 800" name="Общая ошибка модуля dbf-export"/>
<!-- error code for api-lk-company -->
<errorCode id="6000" code="6 000" name="Общая ошибка модуля api-lk-company"/>
<!-- error code for scheduler_service -->
<errorCode id="7000" code="7 000" name="Общая ошибка модуля scheduler_service"/>
<errorCode id="7001" code="7 001" name="Нет прав на проведение данной операции."/>
<errorCode id="7002" code="7 002" name="Не заданы обязательные поля."/>
<errorCode id="7003" code="7 003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="7004" code="7 004" name="Неверное значение поля %s."/>
<errorCode id="7005" code="7 005" name="Такая запись уже существует."/>
<errorCode id="7006" code="7 006" name="Запись не найдена."/>
<errorCode id="7010" code="7 010" name="Невозможно добавить задачу на прошедшую дату."/>
<errorCode id="7011" code="7 011" name="Невозможно добавить задачу на прошедшее время."/>
<errorCode id="7012" code="7 012" name="Указанный в задаче нструмент не найден."/>
<errorCode id="7013" code="7 013" name="Указанный инструмент неактивен."/>
</enums>
<objects>
<company id="1" fullName="АО Санкт-Петербургская Валютная Биржа" shortName="СПВБ"/>
<company id="2" fullName="НКО ЗАО «Петербургский Расчетный Центр»" shortName="НКО АО ПРЦ"/>
<company id="3" fullName="Торговая организация" shortName="ТС"/>
<market id="1" code="MKRS" name="Денежный рынок МКР"/>
</objects>
</meta>

View file

@ -1,4 +1,7 @@
1=This is error example 1.
3000=validation error field '%s'
3001=unrecognized json property '%s'
3002=failed to read http message
9000=validation error field '%s'
9001=unrecognized json property '%s'
9002=failed to read http message
9003=Keycloak roles contain repeated elements
9004=couldn't find dictionary '%s'
9005=Not found %s

View file

@ -1,2 +1 @@
1=Пример ошибки с идентификатором 1.
3000=Ошибка валидации, поле: %s
1=Пример ошибки с идентификатором 1.

View file

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<meta version="0.0.0.0">
<enums>
<courierType id="1" code="STHS" name="ЭДО с Расчетной Организацией"/>
<termType id="1" code="S" name="Срочный"/>
<termType id="2" code="K" name="Комбинированный"/>
<termType id="3" code="V" name="До востребования"/>
<task id="1" code="GBAL" name="Зачисление остатков"/>
<task id="2" code="GBLC" name="Подтверждение зачисления остатков"/>
<task id="3" code="ABLK" name="Блокировка счета"/>
<task id="4" code="GALB" name="Запрос остатков по всем счетам"/>
<task id="5" code="ADBL" name="Дозачисление/списание остатков"/>
<task id="6" code="ADBC" name="Подтверждение дозачисления/списания остатков"/>
<task id="7" code="CORD" name="Формирование сводного платежного поручения"/>
<task id="8" code="CORC" name="Получение подтверждения переводов"/>
<task id="34" code="GBLD" name="Поступление средств"/>
<task id="35" code="GBDC" name="Подтверждение поступления средств"/>
<taskStatus id="1" code="ACTV" name="Активна"/>
<taskStatus id="2" code="BLKD" name="Не активна"/>
<taskStatus id="3" code="CNCL" name="Отмена расписания"/>
<tradingStatus id="1" code="TRAD" name="Торговый"/>
<tradingStatus id="2" code="NTRD" name="Неторговый"/>
<!--transactionStatus id="1" code="STLD" name="Рассчитан"/>
<transactionStatus id="2" code="SENT" name="Отправлен в ПРЦ"/>
<transactionStatus id="3" code="OK" name="Обработан ПРЦ"/>
<transactionStatus id="4" code="FAIL" name="Ошибка ПРЦ"/-->
<source id="1" code="TIMT" name="Расписание"/>
<source id="2" code="SCHD" name="Планировщик"/>
<chargeType id="1" code="PRCT" name="Процент"/>
<chargeDirection id="1" code="GET" name="Получить"/>
<chargeDirection id="2" code="PAY" name="Заплатить"/>
<clearingStatus id="1" code="OK" name="Успешно"/>
<clearingStatus id="2" code="FAIL" name="Не успешно"/>
<clearingStatus id="3" code="MNG" name="Не учитывать"/>
<clearingStatus id="4" code="PROC" name="К клирингу"/>
<interestStatus id="1" code="FREE" name="Не требуется"/>
<interestStatus id="2" code="RTND" name="Возвращены"/>
<interestStatus id="3" code="DFLT" name="Не возвращены"/>
<workflowStatus id="1" code="ACTV" name="Активен"/>
<workflowStatus id="2" code="BLKD" name="Не активен"/>
<accountStatus id="1" code="ACTV" name="Активен"/>
<accountStatus id="2" code="BLKD" name="Заблокирован"/>
<accountStatus id="3" code="CLOS" name="Закрыт"/>
<balanceAccountType id="1" code="ACNT" name="Остатки по счетам"/>
<inOutDirection id="1" code="IN" name="Зачисление"/>
<inOutDirection id="2" code="OUT" name="Списание"/>
<moneyFlowSide id="1" code="BUY" name="Разместить"/>
<moneyFlowSide id="2" code="SELL" name="Привлечь"/>
<allowed id="1" code="ALWD" name="Разрешено"/>
<allowed id="2" code="DEND" name="Запрещено"/>
<serviceStatus id="1" code="ACTV" name="Активен"/>
<serviceStatus id="2" code="BLKD" name="Заблокирован"/>
<serviceStatus id="3" code="SSPD" name="Приостановлен"/>
<serviceStatus id="4" code="CLOS" name="Закрыт"/>
<serviceStatus id="5" code="ROPN" name="Возобновлен"/>
<!--statementType id="1" code="FULL" name="Установка суммы"/-->
<statementType id="2" code="INCR" name="Изменение суммы"/>
<operationType id="1" code="STMT" name="Расчетные операции"/>
<operationType id="2" code="TRAD" name="Торговые операции"/>
<operationStatus id="1" code="PEND" name="В ожидании"/>
<operationStatus id="2" code="RJCT" name="Отклонена"/>
<operationStatus id="3" code="EXEC" name="Исполнена"/>
<operationStatus id="4" code="CNCL" name="Отменена"/>
<service id="1" code="MKR" name="Денежный рынок МКР"/>
<serviceProduct id="1" code="PRNT" name="Расчет обязательств с процентом"/>
<serviceProduct id="2" code="ZERO" name="Расчет обязательств без процента (по умолчанию)"/>
<sector id="1" code="MKR" name="Секция Денежного рынка МКР"/>
<clearingCategory id="1" code="C" name="Категория «Ц» - Банк России"/>
<clearingCategory id="2" code="B" name="Категория «Б» - Кредитная организация ДР"/>
<clearingCategory id="3" code="F" name="Категория «Ф» - Участник рынка РЦБ"/>
<clearingCategory id="4" code="I" name="Категория «И» - Инициатор по ТБС"/>
<clearingCategory id="5" code="V" name="Категория «В» - Инициатор по ТКС"/>
<clearingCategory id="6" code="T" name="Категория «Т» - Участник товарного рынка"/>
<clearingCategory id="7" code="K" name="Категория «К» - Участник клиринга - Контроллер"/>
<managementJournalType id="1" code="CRPA" name="Корпоративное событие, связанное с допуском"/>
<managementJournalType id="2" code="DFLT" name="Отсутствие возврата по платежу"/>
<managementJournalType id="3" code="NOTC" name="Генерация уведомления"/>
<managementJournalType id="4" code="SETL" name="Взаимодействие с расчетной организацией"/>
<managementJournalStatus id="1" code="CRT" name="Создано"/>
<managementJournalPurpose id="1" code="ACC" name="Доступ"/>
<managementJournalPurpose id="2" code="NOND" name="Не поставка"/>
<managementJournalPurpose id="3" code="DEL" name="Удалена"/>
<contactType id="1" code="ADRS" name="Адрес местонахождения"/>
<contactType id="2" code="POST" name="Почтовый адрес"/>
<contactType id="3" code="CONT" name="Контактное лицо"/>
<contactType id="4" code="MAIL" name="Электронная почта"/>
<contactType id="5" code="PHON" name="Телефон"/>
<contactType id="6" code="GDIR" name="Генеральный директор"/>
<contactType id="7" code="TRST" name="Доверенное лицо"/>
<contactType id="8" code="FAX" name="Факс"/>
<contactType id="9" code="INFO" name="Контактная информация"/>
<contactType id="10" code="CMNT" name="Примечание"/>
<corporationSoleType id="1" code="PRSD" name="Президент"/>
<corporationSoleType id="2" code="GDIR" name="Генеральный директор"/>
<corporationSoleType id="3" code="CMAN" name="Председатель правления"/>
<corporationSoleType id="4" code="MGNT" name="Управляющая компания"/>
<corporationSoleType id="5" code="OTHR" name="Другой"/>
<connectionState id="1" code="CNCT" name="Подключен"/>
<connectionState id="2" code="DSBL" name="Отключен"/>
<documentType id="1" code="PASP" name="Паспорт"/>
<documentType id="2" code="ICRT" name="Удостоверение личности"/>
<documentType id="3" code="PRXY" name="Доверенность"/>
<documentType id="4" code="CNTR" name="Договор клиринга"/>
<documentType id="5" code="REGS" name="Регистрация"/>
<documentType id="6" code="FORM" name="Анкета участника"/>
<documentType id="7" code="OGRN" name="ОГРН"/>
<documentType id="8" code="LICB" name="Банковская лицензия"/>
<documentType id="9" code="LICP" name="Лицензия проф. участника"/>
<documentType id="10" code="PLAC" name="Регистрация по месту пребывания"/>
<documentType id="11" code="INN" name="ИНН"/>
<documentType id="12" code="CIO" name="КИО"/>
<documentType id="13" code="LICR" name="Брокерская лицензия"/>
<documentType id="14" code="FIN" name="Финансовая отчетность"/>
<documentType id="15" code="TRST" name="Полномочия должностных лиц"/>
<documentType id="16" code="PMKR" name="Распоряжение на списание МКР"/>
<documentType id="17" code="TAUT" name="Допуск к торгам"/>
<documentType id="18" code="EDOC" name="Договор об электронном взаимодействии"/>
<documentType id="19" code="XCNT" name="Документ о расторжении Договора клиринга"/>
<legalKind id="1" code="JURD" name="Юридическое лицо"/>
<legalKind id="2" code="PHYS" name="Физическое лицо"/>
<organizationType id="1" code="CRED" name="Кредитная"/>
<organizationType id="2" code="NCRD" name="Некредитная"/>
<companySymbol id="1" code="OCVD" name="Общероссийский классификатор видов экономической деятельности" shortname="ОКВЭД"/>
<companySymbol id="2" code="INN" name="Индивидуальный налоговый номер" shortname="ИНН"/>
<companySymbol id="3" code="CPP" name="Код причины постановки" shortname="КПП"/>
<companySymbol id="4" code="OCPO" name="Общероссийский классификатор предприятий и организаций" shortname="ОКПО"/>
<companySymbol id="5" code="LICP" name="Номер лицензии профессионального участника" shortname="Лицензия профучастника"/>
<companySymbol id="6" code="LICB" name="Номер банковской лицензии" shortname="Лицензия банка"/>
<companySymbol id="7" code="BIC" name="Банковский идентификационный код" shortname="БИК"/>
<companySymbol id="8" code="OGRN" name="Основной государственный регистрационный номер" shortname="ОГРН"/>
<companySymbol id="9" code="CIO" name="Код иностранной организации" shortname="КИО"/>
<companyRole id="1" code="RPRT" name="Отчетная организация"/>
<companyRole id="2" code="CLRH" name="Клиринговая организация"/>
<companyRole id="3" code="EXCH" name="Торговая система"/>
<companyRole id="4" code="SETH" name="Расчетный центр"/>
<companyRole id="5" code="DEPS" name="Депозитарий"/>
<companyRole id="6" code="CLRM" name="Участник клиринга"/>
<userRole id="1" code="ADMN" name="Администратор Клиринга МКР"/>
<userRole id="2" code="SPVS" name="Супервайзер Клиринга МКР"/>
<userRole id="3" code="SCRT" name="Администратор безопасности Клиринга МКР"/>
<accountType id="1" code="CLRN" name="Торговый клиринговый счет"/>
<accountType id="2" code="BANK" name="Текущий банковский счет"/>
<accountType id="3" code="USPD" name="Счет невыясненных поступлений"/>
<accountType id="4" code="CORR" name="Корреспондентский счет"/>
<accountType id="5" code="INFO" name="Информационный счет"/>
<accountType id="6" code="PYER" name="Счет плательщика"/>
<instrumentType id="1" code="RATE" name="Инструмент Денежного рынка"/>
<instrumentType id="2" code="CRNC" name="Валюты"/>
<resultStatus id="1" code="NACK" name="Неуспешно"/>
<resultStatus id="2" code="ACK" name="Успешно"/>
<inOutSDfType id="1" code="0102" name="Входящий ДФ-01/Исходящий ДФ-02"/>
<inOutSDfType id="2" code="1617" name="Входящий ДФ-16/Исходящий ДФ-17"/>
<inOutSDfType id="3" code="0910" name="Входящий ДФ-09/Исходящий ДФ-10"/>
<!--sessionStatus id="1" code="ACTV" name="Сессия активна"/>
<sessionStatus id="2" code="CLRN" name="Идет клиринг"/-->
<!--objectType id="1" code="STMT" name="STATEMENT"/-->
<!--notificationStatus id="1" code="PEND" name="В ожидании"/>
<notificationStatus id="2" code="CNCL" name="Отменено"/>
<notificationStatus id="3" code="ACPT" name="Принято"/-->
<currencyCode id="643" code="RUB" name="Российский рубль"/>
<!-- error code for securities_services -->
<errorCode id="1000" code="1000" name="Общая ошибка модуля securities_services."/>
<errorCode id="1001" code="1001" name="Нет прав на проведение данной операции."/>
<errorCode id="1002" code="1002" name="Не заданы обязательные поля."/>
<errorCode id="1003" code="1003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="1004" code="1004" name="Неверное значение поля %s."/>
<errorCode id="1005" code="1005" name="Такая запись уже существует."/>
<errorCode id="1006" code="1006" name="Запись не найдена."/>
<errorCode id="1007" code="1007" name="Пользователь не найден."/>
<errorCode id="1008" code="1008" name="Пользователь неактивен."/>
<errorCode id="1010" code="1010" name="Такой Инструмент уже существует."/>
<errorCode id="1011" code="1011" name="Инструмент не найден."/>
<errorCode id="1012" code="1012" name="Инструмент неактивен."/>
<!-- error code for utility_service -->
<errorCode id="2000" code="2000" name="Общая ошибка модуля utility_service"/>
<errorCode id="2001" code="2001" name="Нет прав на проведение данной операции."/>
<errorCode id="2002" code="2002" name="Не заданы обязательные поля."/>
<errorCode id="2003" code="2003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="2004" code="2004" name="Неверное значение поля %s."/>
<errorCode id="2005" code="2005" name="Такая запись уже существует."/>
<errorCode id="2006" code="2006" name="Запись не найдена."/>
<!-- error code for company_services -->
<errorCode id="3000" code="3000" name="Общая ошибка модуля company_services"/>
<errorCode id="3001" code="3001" name="Нет прав на проведение данной операции."/>
<errorCode id="3002" code="3002" name="Не заданы обязательные поля."/>
<errorCode id="3003" code="3003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="3004" code="3004" name="Неверное значение поля %s."/>
<errorCode id="3005" code="3005" name="Такая запись уже существует."/>
<errorCode id="3006" code="3006" name="Запись не найдена."/>
<errorCode id="3010" code="3010" name="Такая Компания уже существует"/>
<errorCode id="3011" code="3011" name="Компания не найдена."/>
<errorCode id="3012" code="3012" name="Компания неактивна."/>
<errorCode id="3013" code="3013" name="Профиль Компании не найден."/>
<errorCode id="3014" code="3014" name="Реквизит Компании не найден."/>
<errorCode id="3015" code="3015" name="Контакт Компании не найден."/>
<errorCode id="3016" code="3016" name="Категория Компании не найдена."/>
<errorCode id="3017" code="3017" name="Компании уже присвоена Категория %s."/>
<!-- error code for report_serivces -->
<errorCode id="4000" code="4000" name="Общая ошибка модуля report_serivces"/>
<!-- == error code for processing accounts and balances == -->
<!-- error code for account_services -->
<errorCode id="5000" code="5000" name="Общая ошибка модуля account_services"/>
<errorCode id="5001" code="5001" name="Нет прав на проведение данной операции."/>
<errorCode id="5002" code="5002" name="Не заданы обязательные поля."/>
<errorCode id="5003" code="5003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="5004" code="5004" name="Неверное значение поля %s."/>
<errorCode id="5005" code="5005" name="Такая запись уже существует."/>
<errorCode id="5006" code="5006" name="Запись не найдена."/>
<errorCode id="5010" code="5010" name="Счет %s уже существует."/>
<errorCode id="5011" code="5011" name="Счет %s не найден."/>
<errorCode id="5012" code="5012" name="Счет %s неактивен."/>
<errorCode id="5013" code="5013" name="Компания не найдена."/>
<errorCode id="5014" code="5014" name="Компания неактивна."/>
<!-- error code for balance_services -->
<errorCode id="5200" code="5200" name="Общая ошибка модуля balance_services"/>
<errorCode id="5210" code="5210" name="Клиринговая сессия неактивна."/>
<errorCode id="5211" code="5211" name="Компания не найдена."/>
<errorCode id="5212" code="5212" name="Компания неактивна."/>
<errorCode id="5213" code="5213" name="Валюта не найдена."/>
<errorCode id="5214" code="5214" name="Загрузка остатков возможна только на текущую дату."/>
<errorCode id="5215" code="5215" name="Загрузка остатков возможна только по рынку МКР."/>
<errorCode id="5216" code="5216" name="Загрузка остатков возможна только по собственным счетам."/>
<errorCode id="5217" code="5217" name="Счет %s не найден."/>
<errorCode id="5218" code="5218" name="Счет %s неактивен."/>
<errorCode id="5219" code="5219" name="Дозачисления/списания возможны только по рынку МКР."/>
<errorCode id="5220" code="5220" name="Сумма списания превышает сумму средств на счете."/>
<errorCode id="5221" code="5221" name="Поступление средств возможно только по рынку МКР."/>
<errorCode id="5222" code="5222" name="Сумма списания превышает сумму средств на счете."/>
<!-- error code for проведение расчетов -->
<errorCode id="5400" code="5400" name="Общая ошибка модуля проведения расчетов"/>
<!-- error code for dbf-loader -->
<errorCode id="5600" code="5600" name="Общая ошибка модуля dbf-loader"/>
<!-- error code for dbf-export -->
<errorCode id="5800" code="5800" name="Общая ошибка модуля dbf-export"/>
<!-- error code for api-lk-company -->
<errorCode id="6000" code="6000" name="Общая ошибка модуля api-lk-company"/>
<!-- error code for scheduler_service -->
<errorCode id="7000" code="7000" name="Общая ошибка модуля scheduler_service"/>
<errorCode id="7001" code="7001" name="Нет прав на проведение данной операции."/>
<errorCode id="7002" code="7002" name="Не заданы обязательные поля."/>
<errorCode id="7003" code="7003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="7004" code="7004" name="Неверное значение поля %s."/>
<errorCode id="7005" code="7005" name="Такая запись уже существует."/>
<errorCode id="7006" code="7006" name="Запись не найдена."/>
<errorCode id="7010" code="7010" name="Невозможно добавить задачу на прошедшую дату."/>
<errorCode id="7011" code="7011" name="Невозможно добавить задачу на прошедшее время."/>
<errorCode id="7012" code="7012" name="Указанный в задаче нструмент не найден."/>
<errorCode id="7013" code="7013" name="Указанный инструмент неактивен."/>
<errorCode id="7014" code="7014" name="Указанная в задаче компания не найдена."/>
<errorCode id="7015" code="7015" name="Указанная компания неактивна."/>
<!-- error code for utility_service -->
<errorCode id="8000" code="8000" name="Общая ошибка модуля utility_service"/>
<errorCode id="8001" code="8001" name="Нет прав на проведение данной операции."/>
<errorCode id="8002" code="8002" name="Не заданы обязательные поля."/>
<errorCode id="8003" code="8003" name="Запись с указанным идентификатором в справочнике %s не найдена."/>
<errorCode id="8004" code="8004" name="Неверное значение поля %s."/>
<errorCode id="8005" code="8005" name="Такая запись уже существует."/>
<errorCode id="8006" code="8006" name="Запись не найдена."/>
<!-- error code for backend_api -->
<errorCode id="9000" code="9000" name="Ошибка проверки поля %s"/>
<errorCode id="9001" code="9001" name="Неопознанное значение json свойства %s"/>
<errorCode id="9002" code="9002" name="Не удалось обработать http сообщение"/>
<errorCode id="9003" code="9003" name="Keycloak роли содержат дубликаты"/>
<errorCode id="9004" code="9004" name="Не может обнаружитьт словарь %s"/>
<errorCode id="9005" code="9005" name="Не найдено ресурс %s"/>
</enums>
<objects>
<company id="1" fullName="АО Санкт-Петербургская Валютная Биржа" shortName="СПВБ"/>
<company id="2" fullName="НКО ЗАО «Петербургский Расчетный Центр»" shortName="НКО АО ПРЦ"/>
<company id="3" fullName="Торговая организация" shortName="ТС"/>
<market id="1" code="MKRS" name="Денежный рынок МКР"/>
</objects>
</meta>

View file

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output version="1.0" method="text" indent="no" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="meta">
{
"version": "<xsl:value-of select="@version"/>",
<xsl:apply-templates select="*"/>
}
</xsl:template>
<xsl:template match="enums">
"enums": {
<xsl:apply-templates select="*" mode="enums"/>
}
</xsl:template>
<xsl:template match="objects">
,"objects": {
<xsl:apply-templates select="*" mode="objects"/>
}
</xsl:template>
<xsl:template match="views">
,"views": {
<!--xsl:apply-templates select="*" mode="views"/-->
}
</xsl:template>
<xsl:template match="reports"></xsl:template>
<xsl:template match="types">
,"types": [
<xsl:apply-templates select="*" mode="types"/>
]
</xsl:template>
<xsl:template match="*" mode="types">
<xsl:if test="position() > 1">,</xsl:if>
{
"<xsl:value-of select="name(.)"/>": {
<xsl:for-each select="@*">
"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>"
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
}}
</xsl:template>
<xsl:template match="*" mode="enums">
<xsl:if test="position() > 1">,</xsl:if>
"<xsl:value-of select="name(.)"/>": {
<xsl:for-each select="@*[name()!='class']">
"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>",
</xsl:for-each>
"fields": [<xsl:apply-templates select="*" mode="field"/>]
}
</xsl:template>
<xsl:template match="*" mode="objects">
<xsl:if test="position() > 1">,</xsl:if>
"<xsl:value-of select="name(.)"/>": {
<xsl:for-each select="@*[name()!='class']">
"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>",
</xsl:for-each>
"fields": [<xsl:apply-templates select="*[name()!='actions']" mode="field"/>]
<xsl:apply-templates select="query|subscription|subscriptionHistory" mode="objects"/>
<xsl:if test="actions">,"actions":[<xsl:apply-templates select="actions" mode="objects"/>]</xsl:if>
}
</xsl:template>
<xsl:template match="query" mode="objects"></xsl:template>
<xsl:template match="subscription" mode="objects"></xsl:template>
<xsl:template match="subscriptionHistory" mode="objects"></xsl:template>
<xsl:template match="views" mode="objects"></xsl:template>
<xsl:template match="actions" mode="objects">
<xsl:for-each select="*">
<xsl:if test="position() > 1">,</xsl:if>
{"<xsl:value-of select="name()"/>":
{
<xsl:for-each select="@*">
"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>",
</xsl:for-each>
"fields": [<xsl:apply-templates select="*" mode="field"/>]
}}
</xsl:for-each>
</xsl:template>
<xsl:template match="*" mode="views">
<xsl:if test="position() > 1">,</xsl:if>
"<xsl:value-of select="name(.)"/>": {
<xsl:for-each select="@*">
"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>",
</xsl:for-each>
<xsl:if test="source">"sources": [<xsl:apply-templates select="source" mode="views"/>]</xsl:if>
<xsl:if test="set">,"fields":[<xsl:apply-templates select="set" mode="views"/>]</xsl:if>
}
</xsl:template>
<xsl:template match="source" mode="views">
<xsl:if test="position() > 1">,</xsl:if>
"<xsl:value-of select="@code"/>"
</xsl:template>
<xsl:template match="set" mode="views">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:choose>
<xsl:when test="count(field)=1">
<xsl:apply-templates select="field"/>
</xsl:when>
<xsl:otherwise>
{<xsl:for-each select="field[position() = 1]">
<xsl:for-each select="@*[name()!='source']">
<xsl:if test="position() > 1">,</xsl:if>
"<xsl:value-of select="name()"/>":
<xsl:variable name="attrName"><xsl:value-of select="name()"/></xsl:variable>
{
<xsl:for-each select="parent::*/parent::*/field/@*[name()=$attrName]">
<xsl:apply-templates select="." mode="withSource"/>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
}
</xsl:for-each>
</xsl:for-each>
}
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*" mode="field">
<xsl:if test="position() > 1">,</xsl:if>
{"<xsl:value-of select="name()"/>":
{
<xsl:for-each select="@*">
<xsl:choose>
<xsl:when test="name()='type'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='length'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='searchable'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='sortable'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='visible'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='ignore'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='required'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='cacheable'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:otherwise>"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>"</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
}}
</xsl:template>
<xsl:template match="value">
<xsl:if test="position() > 1">,</xsl:if>
{"<xsl:value-of select="name()"/>":
{
<xsl:for-each select="@*">
<xsl:choose>
<xsl:when test="name()='id'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='code'">"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>"</xsl:when>
<xsl:when test="name()='name'">"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>"</xsl:when>
<xsl:otherwise>"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>"</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
}}
</xsl:template>
<xsl:template match="@*" mode="withSource">
<xsl:choose>
<xsl:when test="name()='type'">"<xsl:value-of select="parent::*/@source"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='length'">"<xsl:value-of select="parent::*/@source"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='searchable'">"<xsl:value-of select="parent::*/@source"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='sortable'">"<xsl:value-of select="parent::*/@source"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='visible'">"<xsl:value-of select="parent::*/@source"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='required'">"<xsl:value-of select="parent::*/@source"/>": <xsl:value-of select="."/></xsl:when>
<xsl:when test="name()='cacheable'">"<xsl:value-of select="parent::*/@source"/>": <xsl:value-of select="."/></xsl:when>
<xsl:otherwise>"<xsl:value-of select="parent::*/@source"/>": "<xsl:value-of select="."/>"</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View file

@ -4,6 +4,7 @@ import org.apache.kafka.clients.producer.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.imdg.api.Imdg;
@ -22,7 +23,7 @@ public class KafkaSenderConfig {
.producer(kafkaProducer)
.idGenerator(imdgIdGenerator::nextId)
.imdgProvider(s -> {
Imdg<RequestInfo> imdg = imdgProvider.getImdg(s, RequestInfo.class);
Imdg<RequestInfo> imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
return imdg::insert;
})
.build();

View file

@ -0,0 +1,22 @@
package ru.spcex.clearing.balance.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.balance.service.AbstractExecutor;
import ru.spcex.clearing.balance.service.Sdf01Executor;
import ru.spcex.platform.classes.base.interfaces.WithAccount;
import ru.spcex.platform.enumeration.SdfTable;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class SdfExecutorsConfig {
@Bean("sdfExecutors")
public Map<SdfTable, AbstractExecutor<? extends WithAccount>> executorsMap(Sdf01Executor sdf01Executor) {
Map<SdfTable, AbstractExecutor<? extends WithAccount>> executors = new HashMap<>();
executors.put(SdfTable.SDF_01, sdf01Executor);
return executors;
}
}

View file

@ -4,35 +4,113 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.sdf.SDf01;
import ru.spcex.clearing.balance.validation.Sdf01ValidationRule;
import ru.clearing.classes.statics.data.sdf.SDf09;
import ru.clearing.classes.statics.data.sdf.SDf16;
import ru.spcex.clearing.balance.validation.*;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
@Configuration
public class ValidationConfig {
private final Map<String, Imdg<? extends SpcexObjectBase>> imdgs;
public ValidationConfig(ImdgProvider imdgProvider) {
this.imdgs = new HashMap<>();
BiConsumer<String, Class<? extends SpcexObjectBase>> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass));
addImdg.accept(IMDGDistributedNames.Map_Account, Account.class);
addImdg.accept(IMDGDistributedNames.Map_Company, Company.class);
addImdg.accept(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
addImdg.accept(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);
}
/**
* чтобы во всех валидаторах был один экземпляр Imdg
*/
private Imdg<?> getImdg(String key) {
return imdgs.get(key);
}
@Autowired
@Bean("sdf01Validator")
public Function<SDf01, IValidator> sdf01Validator(ImdgProvider imdgProvider) {
public Function<SDf01, IValidator> sdf01Validator() {
return sDf01 -> {
ImdgValidationContext<SDf01> context = new ImdgValidationContext<>();
context.setValidatedObject(sDf01);
BiConsumer<String, Class<? extends SpcexObjectBase>> addImdg = (s, aClass) -> context.addImdg(s, imdgProvider.getImdg(s, aClass));
addImdg.accept(IMDGDistributedNames.Map_Account, Account.class);
Consumer<String> addImdg = (s) -> context.addImdg(s, getImdg(s));
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_Company);
return new ValidatorImpl<>(context,
Sdf01ValidationRule.CompanyPresent,
Sdf01ValidationRule.AccountPresent,
Sdf01ValidationRule.CurrencyCode,
Sdf01ValidationRule.CurrentDateOnly,
Sdf01ValidationRule.Market,
MarketIsUValidationRule.instance,
Sdf01ValidationRule.accountType);
};
}
@Bean("sdf16Validator")
public Function<SDf16, IValidator> sdf16Validator(ImdgProvider imdgProvider) {
return sDf16 -> {
ImdgValidationContext<SDf16> context = new ImdgValidationContext<>();
context.setValidatedObject(sDf16);
Consumer<String> addImdg = (s) -> context.addImdg(s, getImdg(s));
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_Company);
return new ValidatorImpl<>(context,
Sdf01ValidationRule.CompanyPresent,
SdfCommonValidationRule.AccountPresent,
MarketIsUValidationRule.instance);
};
}
@Bean("sdf09Validator")
public Function<SDf09, IValidator> sdf09Validator() {
return sDf09 -> {
ImdgValidationContext<SDf09> context = new ImdgValidationContext<>();
context.setValidatedObject(sDf09);
Consumer<String> addImdg = (s) -> context.addImdg(s, getImdg(s));
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_Company);
addImdg.accept(IMDGDistributedNames.Map_CompanySymbols);
addImdg.accept(IMDGDistributedNames.Map_AccountBalance);
return new ValidatorImpl<>(context,
Sdf09ValidationRule.CompanyPresent,
Sdf09ValidationRule.AccountPresent,
MarketIsUValidationRule.instance,
Sdf09ValidationRule.BalanceEnough
);
};
}
@Autowired
@Bean("accountBalanceValidator")
public Function<AccountBalanceValidation, IValidator> accountBalanceValidator(ImdgProvider imdgProvider) {
return fieldsToValidateWrapper -> {
ImdgValidationContext<AccountBalanceValidation> context = new ImdgValidationContext<>();
context.setValidatedObject(fieldsToValidateWrapper);
Consumer<String> addImdg = (s) -> context.addImdg(s, getImdg(s));
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_Company);
return new ValidatorImpl<>(context,
AccountBalanceValidationRule.CompanyPresent,
AccountBalanceValidationRule.AccountOk);
};
}
}

View file

@ -8,7 +8,9 @@ public enum BalanceError implements IEnumId {
CurrentDateOnly(5214L),
WrongMarket(5215L),
WrongAccount(5215L),
AccountNotPresent(-1L);
AccountNotPresent(5217L),
AccountNotActive(5218L),
BalanceNotEnough(5222L),
;
private final Long id;

View file

@ -0,0 +1,10 @@
package ru.spcex.clearing.balance.service;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.platform.classes.base.interfaces.WithAccount;
import java.util.Collection;
public abstract class AbstractExecutor<T extends WithAccount> {
abstract Result execute(Collection<T> sdf, StatementRequest statementRequest);
}

View file

@ -0,0 +1,79 @@
package ru.spcex.clearing.balance.service;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.spcex.clearing.balance.validation.AccountBalanceValidation;
import ru.spcex.clearing.balance.validation.ValidationStored;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.BalanceAccountType;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidator;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
@Component
public class AccountBalanceService {
private final ImdgProvider imdgProvider;
private final Imdg<AccountBalance> accountBalanceImdg;
private final Function<AccountBalanceValidation, IValidator> validationFactory;
public AccountBalanceService(ImdgProvider imdgProvider,
@Qualifier("accountBalanceValidator") Function<AccountBalanceValidation, IValidator> validationFactory) {
this.imdgProvider = imdgProvider;
this.validationFactory = validationFactory;
this.accountBalanceImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);
}
public AccountResult createAccountBalance(Long addresseeId, Long accountId, BigDecimal amount,
String cashMovementCurrencyCode) {
IValidator validator = validationFactory.apply(new AccountBalanceValidation(addresseeId, accountId));
Optional<EnumMessage> validationError = validator
.tillFirstError();
if (validationError.isPresent()) return new AccountResult(validationError.get());
Account account = validator.getStored(ValidationStored.Account);
Company company = validator.getStored(ValidationStored.Company);
//которой accountBalance.accountId=statement.accountId и accountBalance.companyId=statement.companyId:
AccountBalance accountBalance = accountBalanceImdg.getSingleObjectByFieldValues(
Map.of("accountId", accountId, "companyId", addresseeId)
);
if (accountBalance == null) {
accountBalance = new AccountBalance();
accountBalance.setCompanyId(addresseeId);
accountBalance.setCreated(Instant.now());
accountBalance.setAccountId(accountId);
accountBalance.setAccountType(account.getAccountType());
accountBalance.setAccount(account.getAccount());
accountBalance.setOpenBalanceAmount(amount);
accountBalance.setFreeBalanceAmount(amount);
accountBalance.setBalanceAmount(amount);
accountBalance.setBalanceAccountType(BalanceAccountType.Active.getKey());
accountBalance.setClearingDate(LocalDate.now());
accountBalance.setCurrencyCode(cashMovementCurrencyCode);
accountBalance.setTradingCode(company.getTradingCode());
accountBalance.setShortName(company.getShortName());
accountBalance.setFullName(company.getFullName());
return new AccountResult(accountBalance);
} else {
accountBalance.setUpdated(Instant.now());
accountBalance.setAccountId(accountId);
accountBalance.setAccountType(account.getAccountType());
accountBalance.setAccount(account.getAccount());
accountBalance.setOpenBalanceAmount(amount);
accountBalance.setFreeBalanceAmount(amount);
accountBalance.setBalanceAmount(amount);
accountBalance.setCurrencyCode(cashMovementCurrencyCode);
return new AccountResult(accountBalance);
}
}
}

View file

@ -0,0 +1,25 @@
package ru.spcex.clearing.balance.service;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.spcex.platform.utils.enumeration.EnumMessage;
public class AccountResult {
private EnumMessage error; //if was
private AccountBalance account;
public AccountResult(EnumMessage validationError) {
this.error = validationError;
}
public AccountResult(AccountBalance account) {
this.account = account;
}
public EnumMessage getError() {
return error;
}
public AccountBalance getAccount() {
return account;
}
}

View file

@ -0,0 +1,27 @@
package ru.spcex.clearing.balance.service;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart;
import java.util.ArrayList;
import java.util.List;
public class Result {
private List<AccountSdfRequestPart> accountRequests = new ArrayList<>();
private Long generationId;
public List<AccountSdfRequestPart> getAccountRequests() {
return accountRequests;
}
public void setAccountRequests(List<AccountSdfRequestPart> accountRequests) {
this.accountRequests = accountRequests;
}
public Long getGenerationId() {
return generationId;
}
public void setGenerationId(Long generationId) {
this.generationId = generationId;
}
}

View file

@ -0,0 +1,194 @@
package ru.spcex.clearing.balance.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.sdf.SDf01;
import ru.clearing.classes.statics.data.sdf.SDf02;
import ru.clearing.classes.statics.data.statement.Statement;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.balance.validation.ValidationStored;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.number.BigDecimalUtil;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
@Service
public class Sdf01Executor extends AbstractExecutor<SDf01> {
private final Logger log = LoggerFactory.getLogger(getClass());
private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy");
private final Imdg<Statement> statementImdg;
private final Function<SDf01, IValidator> sDf01Validator;
private final LoggingService errorLogger;
private final Imdg<SDf02> sdf02Imdg;
private final ImdgProvider imdgProvider;
private final AccountBalanceService accountBalanceService;
private final IMessageResolver errorResolver;
private final Imdg<AccountBalance> accountBalanceImdg;
public Sdf01Executor(Function<SDf01, IValidator> sDf01Validator,
LoggingService errorLogger,
ImdgProvider imdgProvider,
AccountBalanceService accountBalanceService,
IMessageResolver errorResolver) {
this.statementImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class);
this.sdf02Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf02, SDf02.class);
this.accountBalanceImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);;
this.sDf01Validator = sDf01Validator;
this.errorLogger = errorLogger;
this.imdgProvider = imdgProvider;
this.accountBalanceService = accountBalanceService;
this.errorResolver = errorResolver;
}
public Result execute(Collection<SDf01> sdf, StatementRequest statementRequest){
Result result = new Result();
Long generationIdForGroup = imdgProvider.getImdgIdGenerator().nextId();
result.setGenerationId(generationIdForGroup);
for (SDf01 sdf01 : sdf) {
IValidator validator = sDf01Validator.apply(sdf01);
Optional<EnumMessage> error = validator.tillFirstError();
Company company = validator.getStored(ValidationStored.Company);
if (statementRequest.getAccountCreationResults().size() == 0
&& BalanceError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
//на данном шаге company существует -> getId ok
//формируем пакетный запрос на добавление account
//ответ придет в этот же метод, process
result.getAccountRequests().add(createAccountRequestPart(sdf01.getId(), sdf01.getAccount(), company.getId()));
log.info("account {} for sdf01.id={} not found - send request for creation", sdf01.getAccount(), sdf01.getId());
continue;
} else if (BalanceError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
log.error("fatal error: resumed processing after generating accounts, but no account found for sdf01.id={}", sdf01.getId());
}
if (error.isPresent()) {
errorLogger.logError("sdf01.id={}", error.get(), sdf01.getId());
sdf02Imdg.insert(createErrorSdf02(sdf01, error.get(), generationIdForGroup));
continue;
}
Statement statement = statementImdg.getSingleObjectByFieldValues(Map.of("account", sdf01.getAccount()));
if (statement == null) {
statement = createFlow(sdf01,
company,
validator.getStored(ValidationStored.Account));
} else {
updateFlow(statement, sdf01,
validator.getStored(ValidationStored.Account));
}
SDf02 sdf02New = createSuccessSdf02(sdf01, generationIdForGroup);
sdf02Imdg.insert(sdf02New);
statement.setOutSDfId(sdf02New.getId());
AccountResult accountResult = accountBalanceService.createAccountBalance(statement.getAddresseeId(), statement.getAccountId(), statement.getAmount(), statement.getCashMovementCurrencyCode());
if (accountResult.getError() != null) {
statement.setErrorCode(accountResult.getError().getSubject().getId().toString());
statement.setErrorText(errorResolver.resolve(accountResult.getError()));
} else {
accountBalanceImdg.insert(accountResult.getAccount()); //insert == update?
statement.setOperationStatus(OperationStatus.Executed.getKey());
}
statementImdg.update(statement);
}
return result;
}
private Statement createFlow(SDf01 sdf01, Company company, Account account) {
Statement statement = new Statement();
statement.setAddresseeId(company.getId());
statement.setSenderId(Sender.Prc.getId());
statement.setCreated(Instant.now());
statement.setClearingDate(LocalDate.now());
statement.setStatementType(StatementType.full.getKey());
statement.setAccountId(account.getId());
statement.setAccount(sdf01.getAccount());
statement.setInOutDirection(InOutDirection.in.getKey());
statement.setSettlementDate(LocalDate.parse(sdf01.getDat(), datFormatter));
statement.setAmount(BigDecimalUtil.parse(sdf01.getRemainder()));
statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey());
statement.setOperationStatus(OperationStatus.Pending.getKey());
statement.setInSDfId(sdf01.getId());
statement.setInOutSDfType(InOutSDfType.type1.getKey());
statementImdg.insert(statement);
return statement;
}
private void updateFlow(Statement statement, SDf01 sdf01, Account account) {
statement.setUpdated(Instant.now());
statement.setAccountId(account.getId());
statement.setAccount(sdf01.getAccount());
statement.setInOutDirection(InOutDirection.in.getKey());
statement.setSettlementDate(LocalDate.parse(sdf01.getDat(), datFormatter));
statement.setAmount(BigDecimalUtil.parse(sdf01.getRemainder()));
statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey());
statementImdg.update(statement);
}
private AccountSdfRequestPart createAccountRequestPart(Long sdf01Id, String account, Long companyId) {
AccountSdfRequestPart req = new AccountSdfRequestPart();
req.setAccount(account);
req.setCompanyId(companyId);
req.setSdfId(sdf01Id);
return req;
}
private SDf02 createErrorSdf02(SDf01 sdf01, EnumMessage error, Long generationIdForGroup) {
SDf02 sDf02 = new SDf02();
sDf02.setCurr_code(sdf01.getCurr_code());
sDf02.setAccount(sdf01.getAccount());
sDf02.setRemainder(sdf01.getRemainder());
sDf02.setDeal(sdf01.getDeal());
sDf02.setAcc_code(sdf01.getAcc_code());
sDf02.setDat(sdf01.getDat());
sDf02.setMarket(sdf01.getMarket());
sDf02.setAcc_name(sdf01.getAcc_name());
sDf02.setAcc_type(sdf01.getAcc_type());
sDf02.setSumengage(sdf01.getSumengage());
sDf02.setSumunblock(sdf01.getSumunblock());
sDf02.setFile_type(sdf01.getFile_type());
sDf02.setInSDf01Id(sdf01.getId());
String errorId = error.getSubject().getId().toString();
sDf02.setResult(errorId.substring(errorId.length() - 3));
sDf02.setGenerationId(generationIdForGroup);
sDf02.setGenerationTime(Instant.now());
return sDf02;
}
private SDf02 createSuccessSdf02(SDf01 sdf01, Long generationIdForGroup) {
SDf02 sDf02 = new SDf02();
sDf02.setCurr_code(sdf01.getCurr_code());
sDf02.setAccount(sdf01.getAccount());
sDf02.setRemainder(sdf01.getRemainder());
sDf02.setDeal(sdf01.getDeal());
sDf02.setAcc_code(sdf01.getAcc_code());
sDf02.setDat(sdf01.getDat());
sDf02.setMarket(sdf01.getMarket());
sDf02.setAcc_name(sdf01.getAcc_name());
sDf02.setAcc_type(sdf01.getAcc_type());
sDf02.setSumengage(sdf01.getSumengage());
sDf02.setSumunblock(sdf01.getSumunblock());
sDf02.setFile_type(sdf01.getFile_type());
sDf02.setInSDf01Id(sdf01.getId());
sDf02.setGenerationId(generationIdForGroup);
sDf02.setGenerationTime(Instant.now());
sDf02.setResult("OK!");
return sDf02;
}
}

View file

@ -1,59 +0,0 @@
package ru.spcex.clearing.balance.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.stereotype.Service;
import ru.clearing.classes.statics.data.sdf.SDf02;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.SDf02NewRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
@Service
public class Sdf02Service extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<SDf02> sdf8Map;
public Sdf02Service(Consumer<String, Object> kafkaQueue, ImdgProvider imdgProvider) {
super(kafkaQueue);
this.sdf8Map = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf02, SDf02.class);
}
@Override
public void afterPropertiesSet() {
callback(SDf02NewRequest.class)
.setConsumer(this::newSDf02)
.forDestination(Consts.DESTINATION_SDF02_NEW, callbacks::put);
init();
}
private void newSDf02(BaseRequest<SDf02NewRequest> userRequest) {
SDf02NewRequest req = userRequest.getRequestPayload();
log.debug("SDf02NewRequest received");
SDf02 sDf02 = new SDf02();
sDf02.setCurr_code(req.getCurr_code());
sDf02.setAccount(req.getAccount());
sDf02.setRemainder(req.getRemainder());
sDf02.setDeal(req.getDeal());
sDf02.setAcc_code(req.getAcc_code());
sDf02.setDat(req.getDat());
sDf02.setMarket(req.getMarket());
sDf02.setAcc_name(req.getAcc_name());
sDf02.setAcc_type(req.getAcc_type());
sDf02.setSumengage(req.getSumengage());
sDf02.setSumunblock(req.getSumunblock());
sDf02.setFile_type(req.getFile_type());
sDf02.setResult(req.getResult());
// sDf02.setFileName(req.getFileName());
sDf02.setGenerationTime(req.getGenerationTime());
sDf02.setGenerationId(req.getGenerationId());
sdf8Map.insert(sDf02);
log.debug("successfully processed, new id {}", sDf02.getId());
}
}

View file

@ -0,0 +1,167 @@
package ru.spcex.clearing.balance.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.sdf.SDf09;
import ru.clearing.classes.statics.data.sdf.SDf10;
import ru.clearing.classes.statics.data.statement.Statement;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.balance.validation.ValidationStored;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
@Service
public class Sdf09Executor extends AbstractExecutor<SDf09> {
private final Logger log = LoggerFactory.getLogger(getClass());
private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy");
private final Imdg<Statement> statementImdg;
private final Function<SDf09, IValidator> sDf09Validator;
private final LoggingService errorLogger;
private final Imdg<SDf10> sdf10Imdg;
private final ImdgProvider imdgProvider;
private final AccountBalanceService accountBalanceService;
private final IMessageResolver errorResolver;
private final Imdg<AccountBalance> accountBalanceImdg;
public Sdf09Executor(Function<SDf09, IValidator> sDf09Validator,
LoggingService errorLogger,
ImdgProvider imdgProvider,
AccountBalanceService accountBalanceService,
IMessageResolver errorResolver) {
this.statementImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class);
this.sdf10Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf10, SDf10.class);
this.accountBalanceImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);;
this.sDf09Validator = sDf09Validator;
this.errorLogger = errorLogger;
this.imdgProvider = imdgProvider;
this.accountBalanceService = accountBalanceService;
this.errorResolver = errorResolver;
}
public Result execute(Collection<SDf09> sdf, StatementRequest statementRequest){
Result result = new Result();
Long generationIdForGroup = imdgProvider.getImdgIdGenerator().nextId();
result.setGenerationId(generationIdForGroup);
for (SDf09 sdf09 : sdf) {
IValidator validator = sDf09Validator.apply(sdf09);
Optional<EnumMessage> error = validator.tillFirstError();
Company company = validator.getStored(ValidationStored.Company);
if (statementRequest.getAccountCreationResults().size() == 0
&& BalanceError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
//на данном шаге company существует -> getId ok
//формируем пакетный запрос на добавление account
//ответ придет в этот же метод, process
result.getAccountRequests().add(createAccountRequestPart(sdf09.getId(), sdf09.getAccount(), company.getId()));
log.info("account {} for sdf01.id={} not found - send request for creation", sdf09.getAccount(), sdf09.getId());
continue;
} else if (BalanceError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
log.error("fatal error: resumed processing after generating accounts, but no account found for sdf01.id={}", sdf09.getId());
}
if (error.isPresent()) {
errorLogger.logError("sdf01.id={}", error.get(), sdf09.getId());
sdf10Imdg.insert(createErrorSdf10(sdf09, error.get(), generationIdForGroup));
continue;
}
Statement statement = statementImdg.getSingleObjectByFieldValues(Map.of("account", sdf09.getAccount()));
if (statement == null) {
statement = createFlow(sdf09,
company,
validator.getStored(ValidationStored.Account));
} else {
updateFlow(statement, sdf09,
validator.getStored(ValidationStored.Account));
}
SDf10 sdf10New = createSuccessSdf10(sdf09, generationIdForGroup);
sdf10Imdg.insert(sdf10New);
statement.setOutSDfId(sdf10New.getId());
AccountResult accountResult = accountBalanceService.createAccountBalance(statement.getAddresseeId(), statement.getAccountId(), statement.getAmount(), statement.getCashMovementCurrencyCode());
if (accountResult.getError() != null) {
statement.setErrorCode(accountResult.getError().getSubject().getId().toString());
statement.setErrorText(errorResolver.resolve(accountResult.getError()));
} else {
accountBalanceImdg.insert(accountResult.getAccount()); //insert == update?
statement.setOperationStatus(OperationStatus.Executed.getKey());
}
statementImdg.update(statement);
}
return result;
}
private Statement createFlow(SDf09 sdf09, Company company, Account account) {
Statement statement = new Statement();
statement.setAddresseeId(company.getId());
statement.setSenderId(Sender.Prc.getId());
statement.setCreated(Instant.now());
statement.setClearingDate(LocalDate.now());
statement.setStatementType(StatementType.full.getKey());
statement.setAccountId(account.getId());
statement.setAccount(sdf09.getAccount());
statement.setInOutDirection(InOutDirection.in.getKey());
statement.setAmount(sdf09.getSum());
statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey());
statement.setOperationStatus(OperationStatus.Pending.getKey());
statement.setInSDfId(sdf09.getId());
statement.setInOutSDfType(InOutSDfType.type9.getKey());
statementImdg.insert(statement);
return statement;
}
private void updateFlow(Statement statement, SDf09 sdf09, Account account) {
statement.setUpdated(Instant.now());
statement.setAccountId(account.getId());
statement.setAccount(sdf09.getAccount());
statement.setInOutDirection(InOutDirection.in.getKey());
statement.setAmount(sdf09.getSum());
statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey());
statementImdg.update(statement);
}
private AccountSdfRequestPart createAccountRequestPart(Long sdf09Id, String account, Long companyId) {
AccountSdfRequestPart req = new AccountSdfRequestPart();
req.setAccount(account);
req.setCompanyId(companyId);
req.setSdfId(sdf09Id);
return req;
}
private SDf10 createErrorSdf10(SDf09 sdf09, EnumMessage error, Long generationIdForGroup) {
SDf10 sDf10 = createSuccessSdf10(sdf09, generationIdForGroup);
String errorId = error.getSubject().getId().toString();
sDf10.setResult(errorId.substring(errorId.length() - 3));
return sDf10;
}
private SDf10 createSuccessSdf10(SDf09 sdf09, Long generationIdForGroup) {
SDf10 sDf10 = new SDf10();
sDf10.setAccount(sdf09.getAccount());
sDf10.setSum(sdf09.getSum());
sDf10.setMarket(sdf09.getMarket());
sDf10.setType(sdf09.getType());
sDf10.setNumber(sdf09.getNumber());
sDf10.setINN(sdf09.getInn());
sDf10.setResult("OK");
sDf10.setGenerationId(generationIdForGroup);
sDf10.setGenerationTime(Instant.now());
sDf10.setIn_s_df09_id(sdf09.getId());
return sDf10;
}
}

View file

@ -0,0 +1,191 @@
package ru.spcex.clearing.balance.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.sdf.SDf16;
import ru.clearing.classes.statics.data.sdf.SDf17;
import ru.clearing.classes.statics.data.statement.Statement;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.balance.validation.ValidationStored;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
@Service
public class Sdf16Executor extends AbstractExecutor<SDf16> {
private final Logger log = LoggerFactory.getLogger(getClass());
private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy");
private final Imdg<Statement> statementImdg;
private final Function<SDf16, IValidator> sDf16Validator;
private final LoggingService errorLogger;
private final Imdg<SDf17> sdf17Imdg;
private final ImdgProvider imdgProvider;
private final AccountBalanceService accountBalanceService;
private final IMessageResolver errorResolver;
private final Imdg<AccountBalance> accountBalanceImdg;
public Sdf16Executor(Function<SDf16, IValidator> sDf16Validator,
LoggingService errorLogger,
ImdgProvider imdgProvider,
AccountBalanceService accountBalanceService,
IMessageResolver errorResolver) {
this.statementImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class);
this.sdf17Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf17, SDf17.class);
this.accountBalanceImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);;
this.sDf16Validator = sDf16Validator;
this.errorLogger = errorLogger;
this.imdgProvider = imdgProvider;
this.accountBalanceService = accountBalanceService;
this.errorResolver = errorResolver;
}
public Result execute(Collection<SDf16> sdf, StatementRequest statementRequest){
Result result = new Result();
Long generationIdForGroup = imdgProvider.getImdgIdGenerator().nextId();
result.setGenerationId(generationIdForGroup);
for (SDf16 sdfItem : sdf) {
IValidator validator = sDf16Validator.apply(sdfItem);
Optional<EnumMessage> error = validator.tillFirstError();
Company company = validator.getStored(ValidationStored.Company);
if (statementRequest.getAccountCreationResults().size() == 0
&& BalanceError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
//на данном шаге company существует -> getId ok
//формируем пакетный запрос на добавление account
//ответ придет в этот же метод, process
result.getAccountRequests().add(createAccountRequestPart(sdfItem.getId(), sdfItem.getAccount(), company.getId()));
log.info("account {} for sdf01.id={} not found - send request for creation", sdfItem.getAccount(), sdfItem.getId());
continue;
} else if (BalanceError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
log.error("fatal error: resumed processing after generating accounts, but no account found for sdf01.id={}", sdfItem.getId());
}
if (error.isPresent()) {
errorLogger.logError("sdf01.id={}", error.get(), sdfItem.getId());
sdf17Imdg.insert(createErrorSdfRes(sdfItem, error.get(), generationIdForGroup));
continue;
}
Statement statement = statementImdg.getSingleObjectByFieldValues(Map.of("account", sdfItem.getAccount()));
if (statement == null) {
statement = createFlow(sdfItem,
company,
validator.getStored(ValidationStored.Account));
} else {
updateFlow(statement, sdfItem,
validator.getStored(ValidationStored.Account));
}
SDf17 sdfNew = createSuccessSdfRes(sdfItem, generationIdForGroup);
sdf17Imdg.insert(sdfNew);
statement.setOutSDfId(sdfNew.getId());
AccountResult accountResult = accountBalanceService.createAccountBalance(statement.getAddresseeId(), statement.getAccountId(), statement.getAmount(), statement.getCashMovementCurrencyCode());
if (accountResult.getError() != null) {
statement.setErrorCode(accountResult.getError().getSubject().getId().toString());
statement.setErrorText(errorResolver.resolve(accountResult.getError()));
} else {
accountBalanceImdg.insert(accountResult.getAccount()); //insert == update?
statement.setOperationStatus(OperationStatus.Executed.getKey());
}
statementImdg.update(statement);
}
return result;
}
private Statement createFlow(SDf16 sdf, Company company, Account account) {
Statement statement = new Statement();
statement.setAddresseeId(company.getId());
statement.setSenderId(Sender.Prc.getId());
statement.setCreated(Instant.now());
statement.setClearingDate(LocalDate.now());
statement.setStatementType(StatementType.full.getKey());
statement.setAccountId(account.getId());
statement.setAccount(sdf.getAccount());
statement.setInOutDirection(InOutDirection.in.getKey());
// statement.setSettlementDate(LocalDate.parse(sdf.getDat(), datFormatter));
// statement.setAmount(BigDecimalUtil.parse(sdf.getRemainder()));
statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey());
statement.setOperationStatus(OperationStatus.Pending.getKey());
statement.setInSDfId(sdf.getId());
statement.setInOutSDfType(InOutSDfType.type1.getKey());
statementImdg.insert(statement);
return statement;
}
private void updateFlow(Statement statement, SDf16 sdf, Account account) {
statement.setUpdated(Instant.now());
statement.setAccountId(account.getId());
statement.setAccount(sdf.getAccount());
statement.setInOutDirection(InOutDirection.in.getKey());
// statement.setSettlementDate(LocalDate.parse(sdf.getDat(), datFormatter));
// statement.setAmount(BigDecimalUtil.parse(sdf.getRemainder()));
statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey());
statementImdg.update(statement);
}
private AccountSdfRequestPart createAccountRequestPart(Long sdfId, String account, Long companyId) {
AccountSdfRequestPart req = new AccountSdfRequestPart();
req.setAccount(account);
req.setCompanyId(companyId);
req.setSdfId(sdfId);
return req;
}
private SDf17 createErrorSdfRes(SDf16 sdf, EnumMessage error, Long generationIdForGroup) {
SDf17 errorSdf = new SDf17();
// errorSdf.setCurr_code(sdf.getCurr_code());
errorSdf.setAccount(sdf.getAccount());
// errorSdf.setRemainder(sdf.getRemainder());
// errorSdf.setDeal(sdf.getDeal());
// errorSdf.setAcc_code(sdf.getAcc_code());
// errorSdf.setDat(sdf.getDat());
errorSdf.setMarket(sdf.getMarket());
// errorSdf.setAcc_name(sdf.getAcc_name());
// errorSdf.setAcc_type(sdf.getAcc_type());
// errorSdf.setSumengage(sdf.getSumengage());
// errorSdf.setSumunblock(sdf.getSumunblock());
// errorSdf.setFile_type(sdf.getFile_type());
// errorSdf.setInSDf01Id(sdf.getId());
// String errorId = error.getSubject().getId().toString();
// errorSdf.setResult(errorId.substring(errorId.length() - 3));
errorSdf.setGenerationId(generationIdForGroup);
errorSdf.setGenerationTime(Instant.now());
return errorSdf;
}
private SDf17 createSuccessSdfRes(SDf16 sdf, Long generationIdForGroup) {
SDf17 successSdf = new SDf17();
// successSdf.setCurr_code(sdf.getCurr_code());
successSdf.setAccount(sdf.getAccount());
// successSdf.setRemainder(sdf.getRemainder());
// successSdf.setDeal(sdf.getDeal());
// successSdf.setAcc_code(sdf.getAcc_code());
// successSdf.setDat(sdf.getDat());
successSdf.setMarket(sdf.getMarket());
// successSdf.setAcc_name(sdf.getAcc_name());
// successSdf.setAcc_type(sdf.getAcc_type());
// successSdf.setSumengage(sdf.getSumengage());
// successSdf.setSumunblock(sdf.getSumunblock());
// successSdf.setFile_type(sdf.getFile_type());
// successSdf.setInSDf01Id(sdf.getId());
successSdf.setGenerationId(generationIdForGroup);
successSdf.setGenerationTime(Instant.now());
// successSdf.setResult("OK!");
return successSdf;
}
}

View file

@ -7,27 +7,25 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.sdf.SDf01;
import ru.clearing.classes.statics.data.statement.Statement;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.balance.validation.ValidationStored;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.account.AccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdf01Request;
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.ExportToFileRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.classes.base.interfaces.WithAccount;
import ru.spcex.platform.enumeration.SdfTable;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidator;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class StatementService extends QueueConsumer implements InitializingBean {
@ -35,71 +33,63 @@ public class StatementService extends QueueConsumer implements InitializingBean
private final ImdgProvider imdgProvider;
private final KafkaSender kafkaReqProducer;
private final LoggingService errorLogger;
private final Imdg<SDf01> sdf01Imdg;
private final Imdg<Company> companyImdg;
private final Imdg<Account> accountImdg;
private final Imdg<Statement> statementImdg;
private final Function<SDf01, IValidator> sDf01Validator;
private final Imdg<? extends WithAccount> sdf01Imdg;
private final Map<SdfTable, AbstractExecutor<? extends WithAccount>> executorsMap;
@Autowired
public StatementService(Consumer<String, Object> kafkaQueue, ImdgProvider imdgProvider, KafkaSender kafkaReqProducer, LoggingService errorLogger,
@Qualifier("sdf01Validator") Function<SDf01, IValidator> sDf01Validator) {
public StatementService(Consumer<String, Object> kafkaQueue,
ImdgProvider imdgProvider,
KafkaSender kafkaReqProducer,
@Qualifier("sdfExecutors") Map<SdfTable, AbstractExecutor<? extends WithAccount>> executorsMap) {
super(kafkaQueue);
this.imdgProvider = imdgProvider;
this.sdf01Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf01, SDf01.class);
this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
this.statementImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class);
this.kafkaReqProducer = kafkaReqProducer;
this.errorLogger = errorLogger;
this.sDf01Validator = sDf01Validator;
this.executorsMap = executorsMap;
}
@Override
public void afterPropertiesSet() throws Exception {
callback(StatementRequest.class)
.setConsumer(this::process)
.forDestination(Consts.DESTINATION_SDF02_NEW, callbacks::put);
.forDestination(Consts.STATEMENT_PROCESS, callbacks::put);
init();
}
private void process(BaseRequest<StatementRequest> systemRequest) {
StatementRequest sdfInfo = systemRequest.getRequestPayload();
SDf01 sdf01 = sdf01Imdg.getSingleObjectByID(sdfInfo.getSdf01Id());
Company company = companyImdg.getSingleObjectByFieldValues(Map.of("tradingCode", sdf01.getDeal()));
if (company == null) {
errorLogger.logError("sdf01.id={}", new EnumMessage(BalanceError.CompanyNotFound), sdfInfo.getSdf01Id());
return;
}
IValidator validator = sDf01Validator.apply(sdf01);
Optional<EnumMessage> error = validator.tillFirstError();
if (BalanceError.AccountNotPresent.equals(error.map(EnumMessage::getSubject).orElse(null))) {
kafkaReqProducer.sendRequestToQueue(Consts.ACCOUNT_NEW, createAccountRequest(sdf01.getAccount()));
log.info("account not found - send request for creation");
return;
}
if (error.isPresent()) {
errorLogger.logError("sdf01.id={}", error.get(), sdf01.getId());
return;
}
Statement statement = statementImdg.getSingleObjectByFieldValues(Map.of("account", sdf01.getAccount()));
if (statement == null) {
createFlow(sdfInfo, validator.getStored(ValidationStored.Sdf01Account));
StatementRequest statementRequest = systemRequest.getRequestPayload();
Collection<? extends WithAccount> sdfGroup;
SdfTable table = statementRequest.getTable();
//map = getMapByTable(table)
if (statementRequest.getAccountCreationResults().size() == 0) {
sdfGroup = sdf01Imdg.getCollectionObjectsByFieldValues(Map.of("generationId", statementRequest.getGroupId()));
} else {
// updateFlow(statement);
sdfGroup = statementRequest.getAccountCreationResults()
.stream()
.filter(part -> part.getErrorCode() == null) //fixme эти случае должны попадать в ошибочный sdf02
.map(part -> sdf01Imdg.getSingleObjectByID(part.getSdfId()))
.collect(Collectors.toList());
}
// sdf01Group = sdf01Group
// .stream()
// .sorted(Comparator.comparing(SpcexObjectBase::getId))
// .collect(Collectors.toList());
AbstractExecutor service = executorsMap.get(table);
Result res = service.execute(sdfGroup, statementRequest);
if (res.getAccountRequests().size() == 0) {
ExportToFileRequest exportRequest = new ExportToFileRequest();
exportRequest.setSdfGroupId(res.getGenerationId());
exportRequest.setNameOfTable("DF-02");
kafkaReqProducer.sendRequestToQueue(Consts.EXPORT_PROCESS, exportRequest);
} else {
kafkaReqProducer.sendRequestToQueue(Consts.ACCOUNT_NEW, createAccountsRequest(statementRequest.getGroupId(), res.getAccountRequests()));
}
}
private void createFlow(StatementRequest sdfInfo, Account storedObject) {
}
private AccountNewRequest createAccountRequest(String account) {
AccountNewRequest req = new AccountNewRequest();
req.setAccount(account);
return req;
private AccountSdf01Request createAccountsRequest(Long sdf01GroupingId, List<AccountSdfRequestPart> accountRequests) {
AccountSdf01Request r = new AccountSdf01Request();
r.setGroupingSdf01Id(sdf01GroupingId);
r.setAccounts(accountRequests);
return r;
}
}

View file

@ -0,0 +1,3 @@
package ru.spcex.clearing.balance.validation;
public record AccountBalanceValidation(Long addresseeId, Long accountId) {}

View file

@ -0,0 +1,55 @@
package ru.spcex.clearing.balance.validation;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.Status;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Optional;
public enum AccountBalanceValidationRule implements IValidationRule<ImdgValidationContext<AccountBalanceValidation>> {
CompanyPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<AccountBalanceValidation> context) {
AccountBalanceValidation validatedObject = context.getValidatedObject();
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
Company company = companyImdg.getSingleObjectByID(validatedObject.addresseeId());
if (company == null) {
return of( BalanceError.CompanyNotFound);
}
context.storeObject(ValidationStored.Company, company);
return empty();
}
},
AccountOk() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<AccountBalanceValidation> context) {
AccountBalanceValidation validatedObject = context.getValidatedObject();
Imdg<Account> accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
Account account = accountImdg.getSingleObjectByFieldValues(Map.of("id", validatedObject.accountId(),
"accountType", AccountType.Clrn.getKey()));
if (account == null) {
return of(BalanceError.AccountNotPresent);
}
if (!Status.Active.equalsByKey(account.getAccountStatus())) {
return of(BalanceError.AccountNotActive, account.getId());
}
context.storeObject(ValidationStored.Account, account);
return empty();
}
};
private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy");
@Override
public String ruleName() {
return "Sdf01ValidationRule." + name();
}
}

View file

@ -0,0 +1,23 @@
package ru.spcex.clearing.balance.validation;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.platform.classes.base.interfaces.WithMarket;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Optional;
public class MarketIsUValidationRule implements IValidationRule<ImdgValidationContext<WithMarket>> {
public static final MarketIsUValidationRule instance = new MarketIsUValidationRule();
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<WithMarket> context) {
WithMarket validatedObject = context.getValidatedObject();
if (!"U".equals(validatedObject.getMarket())) {
return of(BalanceError.WrongMarket);
}
return empty();
}
}

View file

@ -1,20 +1,35 @@
package ru.spcex.clearing.balance.validation;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.sdf.SDf01;
import ru.spcex.clearing.balance.config.ImdgValidationContext;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Optional;
public enum Sdf01ValidationRule implements IValidationRule<ImdgValidationContext<SDf01>> {
CompanyPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf01> context) {
SDf01 sdf01 = context.getValidatedObject();
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
Company company = companyImdg.getSingleObjectByFieldValues(Map.of("tradingCode", sdf01.getDeal()));
if (company == null) {
return of( BalanceError.CompanyNotFound);
}
context.storeObject(ValidationStored.Company, company);
return empty();
}
},
AccountPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf01> context) {
@ -25,7 +40,7 @@ public enum Sdf01ValidationRule implements IValidationRule<ImdgValidationContext
if (account == null) {
return of(BalanceError.AccountNotPresent);
}
context.storeObject(ValidationStored.Sdf01Account, account);
context.storeObject(ValidationStored.Account, account);
return empty();
}
},
@ -44,22 +59,12 @@ public enum Sdf01ValidationRule implements IValidationRule<ImdgValidationContext
public Optional<EnumMessage> validate(ImdgValidationContext<SDf01> context) {
SDf01 sdf01 = context.getValidatedObject();
//fixme string format???
if (!LocalDate.now().toString().equals(sdf01.getDat())) {
if (!LocalDate.now().equals(LocalDate.parse(sdf01.getDat(), datFormatter))) {
return of(BalanceError.CurrentDateOnly);
}
return empty();
}
},
Market() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf01> context) {
SDf01 sdf01 = context.getValidatedObject();
if (!"U".equals(sdf01.getMarket())) {
return of(BalanceError.WrongMarket);
}
return empty();
}
},
accountType() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf01> context) {
@ -70,6 +75,8 @@ public enum Sdf01ValidationRule implements IValidationRule<ImdgValidationContext
return empty();
}
};
private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy");
@Override
public String ruleName() {
return "Sdf01ValidationRule." + name();

View file

@ -0,0 +1,89 @@
package ru.spcex.clearing.balance.validation;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.sdf.SDf09;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.CompanySymbol;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Optional;
public enum Sdf09ValidationRule implements IValidationRule<ImdgValidationContext<SDf09>> {
CompanyPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf09> context) {
SDf09 sdf09 = context.getValidatedObject();
Imdg<CompanySymbols> companySymbolImdg = context.obtainMap(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
CompanySymbols symbol = companySymbolImdg
.getSingleObjectByFieldValues(Map.of("companySymbol", CompanySymbol.INN.getKey(),
"companySymbolValue", sdf09.getInn()));
Company company = companyImdg.getSingleObjectByID(symbol.getCompanyId());
if (company == null) {
return of( BalanceError.CompanyNotFound);
}
context.storeObject(ValidationStored.Company, company);
return empty();
}
},
AccountPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf09> context) {
SDf09 sdf09 = context.getValidatedObject();
Imdg<Account> accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
Account account = accountImdg.getSingleObjectByFieldValues(Map.of("account", sdf09.getAccount(),
"accountType", AccountType.Clrn.getKey()));
if (account == null) {
return of(BalanceError.AccountNotPresent);
}
context.storeObject(ValidationStored.Account, account);
return empty();
}
},
Market() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf09> context) {
SDf09 sdf09 = context.getValidatedObject();
if (!"U".equals(sdf09.getMarket())) {
return of(BalanceError.WrongMarket);
}
return empty();
}
},
BalanceEnough() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf09> context) {
SDf09 validatedObject = context.getValidatedObject();
if (validatedObject.getSum().compareTo(BigDecimal.ZERO) >= 0) {
return empty();
}
Imdg<AccountBalance> balanceImdg = context.obtainMap(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);
AccountBalance balance = balanceImdg.getSingleObjectByFieldValues(Map.of("account", validatedObject.getAccount(),
"accountType", AccountType.Clrn.getKey()));
if (balance == null) {
return of(BalanceError.BalanceNotEnough);
}
if (balance.getFreeBalanceAmount().compareTo(validatedObject.getSum()) < 0) {
return of(BalanceError.BalanceNotEnough);
}
return empty();
}
}
;
@Override
public String ruleName() {
return "Sdf09ValidationRule." + name();
}
}

View file

@ -0,0 +1,41 @@
package ru.spcex.clearing.balance.validation;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.sdf.SDf16;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Map;
import java.util.Optional;
public enum Sdf16ValidationRule implements IValidationRule<ImdgValidationContext<SDf16>> {
CompanyPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf16> context) {
SDf16 sdf16 = context.getValidatedObject();
Imdg<CompanySymbols> companySymbolsImdg = context.obtainMap(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
CompanySymbols companySymbols = companySymbolsImdg.getSingleObjectByFieldValues(Map.of("companySymbolValue", sdf16.getInn()));
// CompanySymbols companySymbols = companySymbolsImdg.getSingleObjectByFieldValues(Map.of("companySymbolValue", sdf16.getInn()));//search by bic
Company company = null;
if (companySymbols != null) {
company = companyImdg.getSingleObjectByID(companySymbols.getCompanyId());
}
if (company == null) {
return of(BalanceError.CompanyNotFound);
}
context.storeObject(ValidationStored.Company, company);
return empty();
}
};
@Override
public String ruleName() {
return "Sdf01ValidationRule." + name();
}
}

View file

@ -0,0 +1,38 @@
package ru.spcex.clearing.balance.validation;
import ru.clearing.classes.statics.data.account.Account;
import ru.spcex.clearing.balance.errors.BalanceError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.classes.base.interfaces.WithAccount;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Optional;
public enum SdfCommonValidationRule implements IValidationRule<ImdgValidationContext<WithAccount>> {
AccountPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<WithAccount> context) {
WithAccount withAccount = context.getValidatedObject();
Imdg<Account> accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
Account account = accountImdg.getSingleObjectByFieldValues(Map.of("account", withAccount.getAccount(),
"accountType", AccountType.Clrn.getKey()));
if (account == null) {
return of(BalanceError.AccountNotPresent);
}
context.storeObject(ValidationStored.Account, account);
return empty();
}
};
private final static DateTimeFormatter datFormatter = DateTimeFormatter.ofPattern("dd.MM.yy");
@Override
public String ruleName() {
return "Sdf01ValidationRule." + name();
}
}

View file

@ -1,5 +1,5 @@
package ru.spcex.clearing.balance.validation;
public enum ValidationStored {
Sdf01Account;
Account, Company;
}

View file

@ -1,10 +1,10 @@
spring.main.web-application-type=none
balance-service.hazelcast.cluster-members=127.0.0.1
balance-service.hazelcast.cluster-members=127.0.0.1:5701
balance-service.hazelcast.login=dev
balance-service.hazelcast.password=dev-pass
balance-service.kafka-consumer.bootstrap-servers=localhost:9092
balance-service.kafka-consumer.group-id=dev-group
balance-service.kafka-consumer.group-id=dev-group-balance-service
balance-service.kafka-consumer.enable-auto-commit=false
balance-service.kafka-consumer.session-timeout-ms=30000
balance-service.kafka-consumer.auto-offset-reset=latest

View file

@ -14,7 +14,7 @@ public class Account extends BusinessObject {
private String account;
private String accountType;
private Long relationId;
private String status;
private String accountStatus;
private String processingSign;
public String getAccount() {
@ -41,12 +41,12 @@ public class Account extends BusinessObject {
this.relationId = value;
}
public String getStatus() {
return status;
public String getAccountStatus() {
return accountStatus;
}
public void setStatus(String value) {
this.status = value;
public void setAccountStatus(String value) {
this.accountStatus = value;
}
public String getProcessingSign() {

View file

@ -0,0 +1,187 @@
package ru.clearing.classes.statics.data.account;
import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.objects.BusinessObject;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* Счета
* <p>
* DB table: ACCOUNT_BALANCE
**/
public class AccountBalance extends BusinessObject {
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private Long companyId;
private Long accountId;
private String accountType;
private String account;
private BigDecimal openBalanceAmount;
private BigDecimal startBalanceAmount;
private BigDecimal closeBalanceAmount;
private BigDecimal tradeBalanceAmount;
private BigDecimal freeBalanceAmount;
private BigDecimal changeBalanceAmount;
private BigDecimal creditAmount;
private BigDecimal debitAmount;
private BigDecimal balanceAmount;
private String balanceAccountType;
private LocalDate clearingDate;
private String currencyCode;
private String tradingCode;
private String shortName;
private String fullName;
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public BigDecimal getOpenBalanceAmount() {
return openBalanceAmount;
}
public void setOpenBalanceAmount(BigDecimal openBalanceAmount) {
this.openBalanceAmount = openBalanceAmount;
}
public BigDecimal getStartBalanceAmount() {
return startBalanceAmount;
}
public void setStartBalanceAmount(BigDecimal startBalanceAmount) {
this.startBalanceAmount = startBalanceAmount;
}
public BigDecimal getCloseBalanceAmount() {
return closeBalanceAmount;
}
public void setCloseBalanceAmount(BigDecimal closeBalanceAmount) {
this.closeBalanceAmount = closeBalanceAmount;
}
public BigDecimal getTradeBalanceAmount() {
return tradeBalanceAmount;
}
public void setTradeBalanceAmount(BigDecimal tradeBalanceAmount) {
this.tradeBalanceAmount = tradeBalanceAmount;
}
public BigDecimal getFreeBalanceAmount() {
return freeBalanceAmount;
}
public void setFreeBalanceAmount(BigDecimal freeBalanceAmount) {
this.freeBalanceAmount = freeBalanceAmount;
}
public BigDecimal getChangeBalanceAmount() {
return changeBalanceAmount;
}
public void setChangeBalanceAmount(BigDecimal changeBalanceAmount) {
this.changeBalanceAmount = changeBalanceAmount;
}
public BigDecimal getCreditAmount() {
return creditAmount;
}
public void setCreditAmount(BigDecimal creditAmount) {
this.creditAmount = creditAmount;
}
public BigDecimal getDebitAmount() {
return debitAmount;
}
public void setDebitAmount(BigDecimal debitAmount) {
this.debitAmount = debitAmount;
}
public BigDecimal getBalanceAmount() {
return balanceAmount;
}
public void setBalanceAmount(BigDecimal balanceAmount) {
this.balanceAmount = balanceAmount;
}
public String getBalanceAccountType() {
return balanceAccountType;
}
public void setBalanceAccountType(String balanceAccountType) {
this.balanceAccountType = balanceAccountType;
}
public LocalDate getClearingDate() {
return clearingDate;
}
public void setClearingDate(LocalDate clearingDate) {
this.clearingDate = clearingDate;
}
public String getCurrencyCode() {
return currencyCode;
}
public void setCurrencyCode(String currencyCode) {
this.currencyCode = currencyCode;
}
public String getTradingCode() {
return tradingCode;
}
public void setTradingCode(String tradingCode) {
this.tradingCode = tradingCode;
}
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
}

View file

@ -0,0 +1,28 @@
package ru.clearing.classes.statics.data.account;
import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.objects.BusinessEvent;
import java.io.Serial;
/**
* Изменение состояния объекта Счета
* <p>
* DB table: ACCOUNT_BALANCE_HISTORY
**/
public class AccountBalanceHistory extends BusinessEvent<AccountBalance> {
@Serial
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private AccountBalance object;
@Override
public AccountBalance getObject() {
return object;
}
@Override
public void setObject(AccountBalance object) {
this.object = object;
}
}

View file

@ -1,8 +1,8 @@
package ru.clearing.classes.statics.data.company;
import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.statics.data.profile.CompanyInfo;
import ru.clearing.classes.objects.BusinessObject;
import ru.clearing.classes.statics.data.profile.CompanyInfo;
import java.io.Serial;

View file

@ -2,7 +2,6 @@ package ru.clearing.classes.statics.data.company.relation;
import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.objects.BusinessObject;
import ru.spcex.platform.classes.base.SpcexObjectBase;
/**
* Договорные отношения
@ -15,8 +14,8 @@ public class Relation extends BusinessObject {
private Long consumerId;
private Long supplierId;
private String serviceStatus;
private Long service;
private Long serviceProduct;
private String service;
private String serviceProduct;
private String comment;
public Long getConsumerId() {
@ -43,19 +42,19 @@ public class Relation extends BusinessObject {
this.serviceStatus = value;
}
public Long getService() {
public String getService() {
return service;
}
public void setService(Long value) {
public void setService(String value) {
this.service = value;
}
public Long getServiceProduct() {
public String getServiceProduct() {
return serviceProduct;
}
public void setServiceProduct(Long value) {
public void setServiceProduct(String value) {
this.serviceProduct = value;
}

View file

@ -4,7 +4,8 @@ import ru.clearing.classes.ConstSerializable;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
/**
* Журнал входящих документов
@ -14,33 +15,34 @@ import java.time.Instant;
public class InDocumentJournal extends SpcexObjectBase {
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private Instant registrationDate;
private Instant registrationTime;
private LocalDate registrationDate;
private LocalTime registrationTime;
private Long registrationNumber;
private String documentName;
private Long senderId;
private String sender;
private Long quantity;
private String clearingCode;
private String courierType;
private Instant emailDate;
private LocalDate emailDate;
private BigDecimal amount;
private Long dossierNumber;
private String dossierNumber;
private String comment;
private Instant receiptDate;
private LocalDate receiptDate;
private String resultStatus;
public Instant getRegistrationDate() {
public LocalDate getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Instant value) {
public void setRegistrationDate(LocalDate value) {
this.registrationDate = value;
}
public Instant getRegistrationTime() {
public LocalTime getRegistrationTime() {
return registrationTime;
}
public void setRegistrationTime(Instant value) {
public void setRegistrationTime(LocalTime value) {
this.registrationTime = value;
}
@ -60,12 +62,12 @@ public class InDocumentJournal extends SpcexObjectBase {
this.documentName = value;
}
public Long getSenderId() {
return senderId;
public String getSender() {
return sender;
}
public void setSenderId(Long value) {
this.senderId = value;
public void setSender(String value) {
this.sender = value;
}
public Long getQuantity() {
@ -92,11 +94,11 @@ public class InDocumentJournal extends SpcexObjectBase {
this.courierType = value;
}
public Instant getEmailDate() {
public LocalDate getEmailDate() {
return emailDate;
}
public void setEmailDate(Instant value) {
public void setEmailDate(LocalDate value) {
this.emailDate = value;
}
@ -108,11 +110,11 @@ public class InDocumentJournal extends SpcexObjectBase {
this.amount = value;
}
public Long getDossierNumber() {
public String getDossierNumber() {
return dossierNumber;
}
public void setDossierNumber(Long value) {
public void setDossierNumber(String value) {
this.dossierNumber = value;
}
@ -124,12 +126,19 @@ public class InDocumentJournal extends SpcexObjectBase {
this.comment = value;
}
public Instant getReceiptDate() {
public LocalDate getReceiptDate() {
return receiptDate;
}
public void setReceiptDate(Instant value) {
public void setReceiptDate(LocalDate value) {
this.receiptDate = value;
}
public String getResultStatus() {
return resultStatus;
}
public void setResultStatus(String resultStatus) {
this.resultStatus = resultStatus;
}
}

View file

@ -0,0 +1,89 @@
package ru.clearing.classes.statics.data.journal;
import ru.clearing.classes.objects.BusinessObject;
import java.time.Instant;
public class ManagementJournal extends BusinessObject {
private Long companyId;
private Long userId;
private String managementJournalType;
private String managementJournalPurpose;
private String managementJournalStatus;
private String text;
private String changeAccessSign;
private String changeDataSign;
private Instant eventDate;
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getManagementJournalType() {
return managementJournalType;
}
public void setManagementJournalType(String managementJournalType) {
this.managementJournalType = managementJournalType;
}
public String getManagementJournalPurpose() {
return managementJournalPurpose;
}
public void setManagementJournalPurpose(String managementJournalPurpose) {
this.managementJournalPurpose = managementJournalPurpose;
}
public String getManagementJournalStatus() {
return managementJournalStatus;
}
public void setManagementJournalStatus(String managementJournalStatus) {
this.managementJournalStatus = managementJournalStatus;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getChangeAccessSign() {
return changeAccessSign;
}
public void setChangeAccessSign(String changeAccessSign) {
this.changeAccessSign = changeAccessSign;
}
public String getChangeDataSign() {
return changeDataSign;
}
public void setChangeDataSign(String changeDataSign) {
this.changeDataSign = changeDataSign;
}
public Instant getEventDate() {
return eventDate;
}
public void setEventDate(Instant eventDate) {
this.eventDate = eventDate;
}
}

View file

@ -4,7 +4,8 @@ import ru.clearing.classes.ConstSerializable;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
/**
* Журнал исходящих документов
@ -14,32 +15,33 @@ import java.time.Instant;
public class OutDocumentJournal extends SpcexObjectBase {
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private Instant registrationDate;
private Instant registrationTime;
private LocalDate registrationDate;
private LocalTime registrationTime;
private Long registrationNumber;
private String documentName;
private Long addresseeId;
private String addressee;
private Long quantity;
private String clearingCode;
private String courierType;
private Instant emailDate;
private LocalDate emailDate;
private BigDecimal amount;
private Long dossierNumber;
private Instant postDate;
private String dossierNumber;
private LocalDate postDate;
private String resultStatus;
public Instant getRegistrationDate() {
public LocalDate getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Instant value) {
public void setRegistrationDate(LocalDate value) {
this.registrationDate = value;
}
public Instant getRegistrationTime() {
public LocalTime getRegistrationTime() {
return registrationTime;
}
public void setRegistrationTime(Instant value) {
public void setRegistrationTime(LocalTime value) {
this.registrationTime = value;
}
@ -59,12 +61,12 @@ public class OutDocumentJournal extends SpcexObjectBase {
this.documentName = value;
}
public Long getAddresseeId() {
return addresseeId;
public String getAddressee() {
return addressee;
}
public void setAddresseeId(Long value) {
this.addresseeId = value;
public void setAddressee(String value) {
this.addressee = value;
}
public Long getQuantity() {
@ -91,11 +93,11 @@ public class OutDocumentJournal extends SpcexObjectBase {
this.courierType = value;
}
public Instant getEmailDate() {
public LocalDate getEmailDate() {
return emailDate;
}
public void setEmailDate(Instant value) {
public void setEmailDate(LocalDate value) {
this.emailDate = value;
}
@ -107,20 +109,27 @@ public class OutDocumentJournal extends SpcexObjectBase {
this.amount = value;
}
public Long getDossierNumber() {
public String getDossierNumber() {
return dossierNumber;
}
public void setDossierNumber(Long value) {
public void setDossierNumber(String value) {
this.dossierNumber = value;
}
public Instant getPostDate() {
public LocalDate getPostDate() {
return postDate;
}
public void setPostDate(Instant value) {
public void setPostDate(LocalDate value) {
this.postDate = value;
}
public String getResultStatus() {
return resultStatus;
}
public void setResultStatus(String resultStatus) {
this.resultStatus = resultStatus;
}
}

View file

@ -3,7 +3,7 @@ package ru.clearing.classes.statics.data.messages;
import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.objects.BusinessObject;
import java.time.Instant;
import java.time.LocalDate;
/**
* Полные тексты ошибок
@ -16,7 +16,7 @@ public class ErrorText extends BusinessObject {
private String errorCode;
private String text;
private Long userId;
private Instant clearingDate;
private LocalDate clearingDate;
public String getErrorCode() {
return errorCode;
@ -42,11 +42,11 @@ public class ErrorText extends BusinessObject {
this.userId = value;
}
public Instant getClearingDate() {
public LocalDate getClearingDate() {
return clearingDate;
}
public void setClearingDate(Instant value) {
public void setClearingDate(LocalDate value) {
this.clearingDate = value;
}

View file

@ -0,0 +1,30 @@
package ru.clearing.classes.statics.data.misc;
import ru.clearing.classes.ConstSerializable;
import ru.clearing.classes.objects.BusinessObject;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalTime;
/**
* Счета
* <p>
* DB table: ADMITTED_DEAL
**/
public class AdmittedDeal extends BusinessObject {
private static final long serialVersionUID = ConstSerializable.serialVersionUID;
private String companyFullName;
private Instant executionDepositRegisterTradingDate;
private String exchangeExecutionId;
private LocalTime exchangeExecutionTime;
private Long securityShortName;
private String sellerFullName;
private String sellerClearingCode;
private String sellerAccount;
private String buyerFullName;
private String buyerClearingCode;
private String buyerAccount;
private BigDecimal executionDepositRegisterAmount;
}

View file

@ -0,0 +1,25 @@
package ru.clearing.classes.statics.data.misc;
import ru.spcex.platform.classes.base.SpcexObjectBase;
public class Currency extends SpcexObjectBase {
private String countryCode;
private String currencyCode;
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getCurrencyCode() {
return currencyCode;
}
public void setCurrencyCode(String currencyCode) {
this.currencyCode = currencyCode;
}
}

View file

@ -2,41 +2,42 @@ package ru.clearing.classes.statics.data.misc;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import java.time.Instant;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* Ключевая ставка ЦБ
*
* <p>
* DB table: KEY_RATE
**/
public class KeyRate extends SpcexObjectBase {
private Double rate;
private Instant startDate;
private Instant endDate;
private BigDecimal rate;
private LocalDate startDate;
private LocalDate endDate;
private String document;
private String workflowStatus;
public Double getRate() {
public BigDecimal getRate() {
return rate;
}
public void setRate(Double rate) {
public void setRate(BigDecimal rate) {
this.rate = rate;
}
public Instant getStartDate() {
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(Instant startDate) {
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public Instant getEndDate() {
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(Instant endDate) {
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}

View file

@ -0,0 +1,72 @@
package ru.clearing.classes.statics.data.misc;
import ru.clearing.classes.objects.BusinessObject;
import java.math.BigDecimal;
public class Listing extends BusinessObject {
private Long securityId;
private BigDecimal lotSize;
private String market;
private String symbolCode;
private String symbolName;
private String tradingCurrency;
private String workflowStatus;
public Long getSecurityId() {
return securityId;
}
public void setSecurityId(Long securityId) {
this.securityId = securityId;
}
public BigDecimal getLotSize() {
return lotSize;
}
public void setLotSize(BigDecimal lotSize) {
this.lotSize = lotSize;
}
public String getMarket() {
return market;
}
public void setMarket(String market) {
this.market = market;
}
public String getSymbolCode() {
return symbolCode;
}
public void setSymbolCode(String symbolCode) {
this.symbolCode = symbolCode;
}
public String getSymbolName() {
return symbolName;
}
public void setSymbolName(String symbolName) {
this.symbolName = symbolName;
}
public String getTradingCurrency() {
return tradingCurrency;
}
public void setTradingCurrency(String tradingCurrency) {
this.tradingCurrency = tradingCurrency;
}
public String getWorkflowStatus() {
return workflowStatus;
}
public void setWorkflowStatus(String workflowStatus) {
this.workflowStatus = workflowStatus;
}
}

Some files were not shown because too many files have changed in this diff Show more