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

This commit is contained in:
ialbert 2024-10-07 11:14:47 +03:00
commit 1c6f6ce36c
55 changed files with 1868 additions and 5277 deletions

View file

@ -3,6 +3,7 @@ package ru.spcex.clearing.account.config.settings;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import ru.spcex.clearing.account.config.settings.elem.AppSettings;
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;
@ -14,6 +15,7 @@ public class AccountServiceSettings {
private HazelcastClientParams hazelcast;
private KafkaConsumerSettings kafkaConsumer;
private KafkaProducerSettings kafkaProducer;
private AppSettings app;
public HazelcastClientParams getHazelcast() {
return hazelcast;
@ -38,4 +40,12 @@ public class AccountServiceSettings {
public void setKafkaProducer(KafkaProducerSettings kafkaProducer) {
this.kafkaProducer = kafkaProducer;
}
public AppSettings getApp() {
return app;
}
public void setApp(AppSettings app) {
this.app = app;
}
}

View file

@ -0,0 +1,13 @@
package ru.spcex.clearing.account.config.settings.elem;
public class AppSettings {
private String registryUnit = "T";
public String getRegistryUnit() {
return registryUnit;
}
public void setRegistryUnit(String registryUnit) {
this.registryUnit = registryUnit;
}
}

View file

@ -4,6 +4,7 @@ import java.time.Instant;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
@ -42,6 +43,8 @@ import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.imdg.validation.Stored;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
@ -145,9 +148,29 @@ public class AccountService extends QueueConsumer implements InitializingBean {
account.setCompanyId(req.getCompanyId());
account.setAccount(req.getAccount());
if (AccountType.Info.equalsByKey(req.getAccountType())) {
Long infoSequenceId = informationAccountService.accountNextId(currencyCode, currencyCodeId);
Account anltAccount;
{
ImdgPredicateBuilder pb = accountMap.predicateBuilder();
ImdgPredicate andPredicate = pb.and(
pb.equals("accountType", AccountType.Anlt.getKey()),
pb.equals("currency", currency.getCurrencyCode())
);
Collection<Account> accountsAnlt = accountMap.getCollectionObjectsByPredicate(andPredicate);
if (accountsAnlt.isEmpty()) {
log.warn("Account with {} not exist.", andPredicate);
} else if (accountsAnlt.size() > 1) {
log.warn("Account for companyId 1 and accountType=ANLT contains multiply elements, use first");
}
anltAccount = accountsAnlt.iterator().next();
}
String accountValue = informationAccountService.generateInfoAccount(currencyCodeId, infoSequenceId);
String specialAnltAccId = "7000";
if (anltAccount != null && StringUtils.isNotEmpty(anltAccount.getAccount()) && anltAccount.getAccount().length() >= 4) {
specialAnltAccId = anltAccount.getAccount().substring(anltAccount.getAccount().length() - 4);
}
Long infoSequenceId = informationAccountService.accountNextId(currencyCode, currencyCodeId);
String accountValue = informationAccountService.generateInfoAccount(currencyCodeId, infoSequenceId, specialAnltAccId);
log.trace("New info-account SequenceId={} account={}", infoSequenceId, accountValue);
account.setAccount(accountValue);
}

View file

@ -119,9 +119,6 @@ public class InformationAccountService extends QueueConsumer implements Initiali
String currency = req.getCurrency() == null ? CurrencyCode.RUB.getKey() : req.getCurrency(); //userRequest.getRequestPayload().getCurrency();
Long newId = informationAccountImdg.nextIDSequenceFor();
Long infoSequenceId = accountNextId(currency, 810L);
String accountValue = generateInfoAccount(810L, infoSequenceId);
log.trace("New info-account id={}, sequenceId={}, account={}", newId, infoSequenceId, accountValue);
ImdgPredicateBuilder accountPredicateBuilder = accountImdg.predicateBuilder();
ImdgPredicate companyIdPredicate = accountPredicateBuilder.equals("companyId", 1L);
@ -215,15 +212,11 @@ public class InformationAccountService extends QueueConsumer implements Initiali
String currency = userRequest.getRequestPayload().getCurrency();
if (currency == null)
currency = CurrencyCode.RUB.getKey();
Long newId = informationAccountImdg.nextIDSequenceFor();
Long infoSequenceId = accountNextId(currency, 810L); // требуется последовательность n+1
String accountValue = generateInfoAccount(810L, infoSequenceId);
log.trace("New info-account id={}, sequenceId={}, account={}", newId, infoSequenceId, accountValue);
Long anltAccountId = null;
Account anltAccount;
{
ImdgPredicate andPredicate = pb.and(
pb.equals("companyId", 1L),
pb.equals("accountType", AccountType.Anlt.getKey()),
pb.equals("currency", currency)
);
@ -234,10 +227,20 @@ public class InformationAccountService extends QueueConsumer implements Initiali
} else if (accountsAnlt.size() > 1) {
log.warn("Account for companyId 1 and accountType=ANLT contains multiply elements, use first");
}
Account anltAccount = accountsAnlt.iterator().next();
anltAccount = accountsAnlt.iterator().next();
anltAccountId = anltAccount.getId();
}
String specialAnltAccId = "7000";
if (anltAccount != null && StringUtils.isNotEmpty(anltAccount.getAccount()) && anltAccount.getAccount().length() >= 4) {
specialAnltAccId = anltAccount.getAccount().substring(anltAccount.getAccount().length() - 4);
}
Long newId = informationAccountImdg.nextIDSequenceFor();
Long infoSequenceId = accountNextId(currency, 810L); // требуется последовательность n+1
String accountValue = generateInfoAccount(810L, infoSequenceId, specialAnltAccId);
log.trace("New info-account id={}, sequenceId={}, account={}", newId, infoSequenceId, accountValue);
Instant now = Instant.now();
Account account = new Account();
account.setAccount(accountValue);
@ -301,8 +304,8 @@ public class InformationAccountService extends QueueConsumer implements Initiali
kafkaSender.sendRequestToQueue(Consts.CREATE_NOTIFICATION_NCMP, request);
}
public String generateInfoAccount(Long currencyCodeId, Long id) {
return "%d%03d%08d%d".formatted(39911, currencyCodeId, id, 7000);
public String generateInfoAccount(Long currencyCodeId, Long id, String specialAnltAccId) {
return "%d%03d%08d%s".formatted(39911, currencyCodeId, id, specialAnltAccId);
}
public synchronized Long accountNextId(String currency) {

View file

@ -27,6 +27,7 @@ import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistryList;
import ru.spcex.clearing.account.config.settings.AccountServiceSettings;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
@ -93,6 +94,7 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
private final IMessageResolver messageResolver;
private final Producer<String, Object> kafkaProducer;
private final KafkaSender kafkaSender;
private final AccountServiceSettings accountServiceSettings;
public TradingClearingRegistryService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
@ -107,7 +109,7 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
@Qualifier("tradingClearingRegistryUpdateRequest")
Function<TradingClearingRegistryUpdateRequest, IValidator> tradingClearingRegistryUpdateRequestValidator,
@Qualifier("tradingClearingRegistryBlockRequest")
Function<CommonIdRequest, IValidator> tradingClearingRegistryBlockRequestValidator) {
Function<CommonIdRequest, IValidator> tradingClearingRegistryBlockRequestValidator, AccountServiceSettings accountServiceSettings) {
super(kafkaQueue, kafkaProducer);
this.kafkaProducer = kafkaProducer;
this.kafkaSender = kafkaSender;
@ -131,6 +133,7 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
this.tradingClearingRegistryUpdateRequestValidator = tradingClearingRegistryUpdateRequestValidator;
this.tradingClearingRegistryBlockRequestValidator = tradingClearingRegistryBlockRequestValidator;
this.messageResolver = messageResolver;
this.accountServiceSettings = accountServiceSettings;
}
@Override
@ -444,7 +447,8 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
code = "%4s".formatted(code).replace(' ', '0');
// code += registryPurpose.getKey(); // C / M / ...
code += "C";//пока ставим всегда С, возможно придется откатить
String trType = tradingRegistryType + "T"; // 2 символа
String registryUnit = accountServiceSettings.getApp() != null ? accountServiceSettings.getApp().getRegistryUnit() : "T";
String trType = tradingRegistryType + registryUnit; // 2 символа
code += trType;
String sId = "%5s".formatted(id).replace(' ', '0');
if (sId.length() > 5)

View file

@ -16,4 +16,6 @@ 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
account-service.kafka-producer.buffer-memory=33554432
account-service.app.registry-unit=L

View file

@ -3,6 +3,7 @@ package ru.spcex.clearing.backendapi.config.element;
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.JsConfigSettings;
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;
@ -17,6 +18,7 @@ public class BackendApiSettings {
private KafkaProducerSettings kafkaProducer;
private KafkaConsumerSettings kafkaConsumer;
private SecuritySettings security;
private JsConfigSettings jsConfig;
private String exampleSetting;
public HazelcastClientParams getHazelcast() {
@ -59,6 +61,14 @@ public class BackendApiSettings {
this.security = security;
}
public JsConfigSettings getJsConfig() {
return jsConfig;
}
public void setJsConfig(JsConfigSettings jsConfig) {
this.jsConfig = jsConfig;
}
public HazelcastClientParams getHazelcastSearch() {
return hazelcastSearch;
}

View file

@ -0,0 +1,39 @@
package ru.spcex.clearing.backendapi.controller.queue.misc;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
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.spcex.clearing.backendapi.config.element.BackendApiSettings;
import ru.spcex.clearing.backendapi.controller.response.entity.CommonGetAllResponse;
import ru.spcex.clearing.backendapi.security.element.JsConfigSettings;
@Controller
@RequestMapping("/")
public class JsConfigController {
private final BackendApiSettings backendApiSettings;
public JsConfigController(BackendApiSettings backendApiSettings) {
this.backendApiSettings = backendApiSettings;
}
@ApiOperation(value = "get js config.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CommonGetAllResponse.class)})
@RequestMapping(path = "/spcex.config.js", method = RequestMethod.GET)
@ResponseBody
public Map<String, Object> getJsConfig() {
Map<String, Object> result = new HashMap<>();
String title = new String(backendApiSettings.getJsConfig().getServerTitle().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
result.put(JsConfigSettings.SERVER_TITLE_PARAM_NAME, title);
result.put(JsConfigSettings.IS_CENTRAL_COUNTER_PARTY_PARAM_NAME, backendApiSettings.getJsConfig().getCentralCounterPartyEnable());
return result;
}
}

View file

@ -1,4 +1,4 @@
package ru.spcex.clearing.backendapi.controller.queue.misc;
package ru.spcex.clearing.backendapi.controller.queue.securities;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

View file

@ -1,4 +1,4 @@
package ru.spcex.clearing.backendapi.controller.queue.misc;
package ru.spcex.clearing.backendapi.controller.queue.securities;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

View file

@ -1,12 +1,16 @@
package ru.spcex.clearing.backendapi.controller.request.cud.securities;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.annotations.ApiModelProperty;
import java.math.BigDecimal;
import java.time.LocalDate;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.security.RatesNewRequest;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
public class RatesNewAction implements IAction<RatesNewRequest> {
@ -14,6 +18,8 @@ public class RatesNewAction implements IAction<RatesNewRequest> {
@JsonProperty
private BigDecimal value;
@ApiModelProperty(value = "Дата.", example = "1234")
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate valueDate;
@ApiModelProperty(value = "Валюта.", example = "1234")

View file

@ -65,6 +65,7 @@ public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
.antMatchers("/login").permitAll()
.antMatchers("/error").permitAll()
.antMatchers("/backend-api-login/**").permitAll()
.antMatchers("/spcex.config.js").permitAll()
.anyRequest();
if (securityDisabled) {
anyReq.permitAll();

View file

@ -0,0 +1,24 @@
package ru.spcex.clearing.backendapi.security.element;
public class JsConfigSettings {
public final static String SERVER_TITLE_PARAM_NAME = "serverTitle";
public final static String IS_CENTRAL_COUNTER_PARTY_PARAM_NAME = "isCentralCounterparty";
private String serverTitle;
private Boolean centralCounterPartyEnable;
public String getServerTitle() {
return serverTitle;
}
public void setServerTitle(String serverTitle) {
this.serverTitle = serverTitle;
}
public Boolean getCentralCounterPartyEnable() {
return centralCounterPartyEnable;
}
public void setCentralCounterPartyEnable(Boolean centralCounterPartyEnable) {
this.centralCounterPartyEnable = centralCounterPartyEnable;
}
}

View file

@ -26,6 +26,9 @@ 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
backend-api.js-config.server-title=?????? 183
backend-api.js-config.central-counter-party-enable=true
#access logs, sample
#server.tomcat.accesslog.directory=logs
#server.tomcat.accesslog.enabled=true

View file

@ -1,6 +1,6 @@
{
"version": "3.15.206.106",
"version": "3.15.206.111",
"enums": {
@ -6217,6 +6217,17 @@
"fields": []
}
,
{"method":"post",
"destination": "GREC",
"group": "Формирование отчетности",
"name": "Формирование отчетности ЦК",
"fields": []
}
,
{"method":"post",
"destination": "FDFF",
@ -10557,14 +10568,6 @@
{"code": "id",
"type": 1,"name": "Идентификатор записи","shortname": "ID","searchable": true,"sortable": true,"visible": true
}
,
{"code": "value",
"name": "Ставка","shortname": "Ставка","type": 10
}
,
{"code": "settlementType",
"name": "Код расчета","shortname": "Код расчета","type": 2,"length": 4
}
,
{"code": "currencyPair",
"name": "Код валютной пары","shortname": "Код валютной пары","type": 2,"length": 12
@ -10573,9 +10576,17 @@
{"code": "currencyPairId",
"name": "Идентификатор валютной пары","shortname": "Валютная пара","type": 1
}
,
{"code": "settlementType",
"name": "Код расчета","shortname": "Код расчета","type": 2,"length": 4
}
,
{"code": "value",
"name": "Ставка","shortname": "Ставка","type": 10
}
,
{"code": "workflowStatus",
"name": "Статус","shortname": "Секция","type": 2,"length": 4
"name": "Статус","shortname": "Статус","type": 2,"length": 4,"link": "workflowStatus"
}
]
,"actions":[
@ -10588,20 +10599,20 @@
"class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction",
"fields": [
{"code": "currencyPairId",
"name": "Идентификатор валютной пары","shortname": "Валютная пара","type": 1,"link": "currencyPair","linkCode": "code","linkKeyCode": "id"
}
,
{"code": "settlementType",
"name": "Код расчёта","shortname": "Код расчёта","type": 12,"link": "currencySettlementType","linkCode": "code"
}
,
{"code": "value",
"name": "Ставка","shortname": "Ставка","type": 10
}
,
{"code": "settlementType",
"name": "Дата, на которую расчетный курс","shortname": "Дата","type": 6
}
,
{"code": "currencyPairId",
"name": "Идентификатор валюты","shortname": "Валюта","type": 1
}
,
{"code": "status",
"name": "Статус","shortname": "Секция","type": 2,"length": 4
"name": "Статус","shortname": "Статус","type": 2,"length": 4,"link": "workflowStatus"
}
]
}
@ -10624,7 +10635,7 @@
}
,
{"code": "status",
"name": "Статус","shortname": "Секция","type": 2,"length": 4
"name": "Статус","shortname": "Статус","type": 2,"length": 4,"link": "workflowStatus"
}
]
}
@ -10646,24 +10657,24 @@
"type": 1,"name": "Идентификатор записи","shortname": "ID","searchable": true,"sortable": true,"visible": true
}
,
{"code": "value",
"name": "Расчетный курс","shortname": "Расчетный курс","type": 10
}
,
{"code": "valueDate",
"name": "Дата, на которую расчетный курс","shortname": "Дата","type": 6
{"code": "currencyId",
"name": "Идентификатор валюты","shortname": "Валюта","type": 1
}
,
{"code": "currency",
"name": "Код валюты","shortname": "Код валюты","type": 2,"length": 4
}
,
{"code": "currencyId",
"name": "Идентификатор валюты","shortname": "Валюта","type": 1
{"code": "valueDate",
"name": "Дата, на которую расчетный курс","shortname": "Дата","type": 6
}
,
{"code": "value",
"name": "Расчетный курс","shortname": "Расчетный курс","type": 10
}
,
{"code": "workflowStatus",
"name": "Статус","shortname": "Секция","type": 2,"length": 4
"name": "Статус","shortname": "Статус","type": 2,"length": 4,"link": "workflowStatus"
}
]
,"actions":[
@ -10676,20 +10687,20 @@
"class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RatesNewAction",
"fields": [
{"code": "value",
"name": "Расчетный курс","shortname": "Расчетный курс","type": 10
{"code": "currencyId",
"name": "Идентификатор валюты","shortname": "Валюта","type": 1,"link": "currencyCode","linkCode": "code","linkKeyCode": "id"
}
,
{"code": "valueDate",
"name": "Дата, на которую расчетный курс","shortname": "Дата","type": 6
}
,
{"code": "currencyId",
"name": "Идентификатор валюты","shortname": "Валюта","type": 1
{"code": "value",
"name": "Расчетный курс","shortname": "Расчетный курс","type": 10
}
,
{"code": "status",
"name": "Статус","shortname": "Секция","type": 2,"length": 4
"name": "Статус","shortname": "Статус","type": 2,"length": 4,"link": "workflowStatus"
}
]
}
@ -10712,7 +10723,7 @@
}
,
{"code": "status",
"name": "Статус","shortname": "Секция","type": 2,"length": 4
"name": "Статус","shortname": "Статус","type": 2,"length": 4,"link": "workflowStatus"
}
]
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--?xml-stylesheet type="text/xsl" href="\..\corp-reports\src\data\meta\meta.server.xslt"?-->
<meta version="3.15.206.106">
<meta version="3.15.206.111">
<!-- _xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _xsi:noNamespaceSchemaLocation="file:///E:/d/projects/meta/from/meta.xsd" -->
<!--Здесь словари-->
<enums>
@ -1443,6 +1443,8 @@
</post>
<post destination="GREF" group="Формирование отчетности" name="Формирование итоговой отчетности">
</post>
<post destination="GREC" group="Формирование отчетности" name="Формирование отчетности ЦК">
</post>
<post destination="FDFF" group="Обмен с расчетной организацией" name="Формирование ДФ-05 с кодом 9 (финальный)">
</post>
<post destination="CHDF" group="Общее" name="Проверка наличия пары ДФ-01/ДФ-57 и ДФ-08/ДФ-21">
@ -2444,43 +2446,43 @@
</blacklistMarket>
<riskParameter name="Параметры риска" destination="risk-parameter" class="ru.clearing.classes.statics.data.security.RiskParameter" table="risk-parameter">
<id type="1" name="Идентификатор записи" shortname="ID" searchable="true" sortable="true" visible="true"/>
<value name="Ставка" shortname="Ставка" type="10"/>
<settlementType name="Код расчета" shortname="Код расчета" type="2" length="4"/>
<currencyPair name="Код валютной пары" shortname="Код валютной пары" type="2" length="12"/>
<currencyPairId name="Идентификатор валютной пары" shortname="Валютная пара" type="1"/>
<workflowStatus name="Статус" shortname="Секция" type="2" length="4"/>
<settlementType name="Код расчета" shortname="Код расчета" type="2" length="4"/>
<value name="Ставка" shortname="Ставка" type="10"/>
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
<actions>
<post name="Добавление параметров риска" confirmation="value,settlementType,currencyPairId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction">
<currencyPairId name="Идентификатор валютной пары" shortname="Валютная пара" type="1" link="currencyPair" linkCode="code" linkKeyCode="id"/>
<settlementType name="Код расчёта" shortname="Код расчёта" type="12" link="currencySettlementType" linkCode="code"/>
<value name="Ставка" shortname="Ставка" type="10"/>
<settlementType name="Дата, на которую расчетный курс" shortname="Дата" type="6"/>
<currencyPairId name="Идентификатор валюты" shortname="Валюта" type="1"/>
<status name="Статус" shortname="Секция" type="2" length="4"/>
<status name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
</post>
<put name="Изменение параметров риска" confirmation="value,status" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterUpdateAction">
<id type="1" name="Идентификатор записи" shortname="ID" link="riskParameter" linkCode="id" required="true"/>
<value name="Ставка" shortname="Ставка" type="10"/>
<status name="Статус" shortname="Секция" type="2" length="4"/>
<status name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
</put>
</actions>
</riskParameter>
<rates name="Расчетные курсы" destination="rates" class="ru.clearing.classes.statics.data.security.Rates" table="rates">
<id type="1" name="Идентификатор записи" shortname="ID" searchable="true" sortable="true" visible="true"/>
<value name="Расчетный курс" shortname="Расчетный курс" type="10"/>
<valueDate name="Дата, на которую расчетный курс" shortname="Дата" type="6"/>
<currency name="Код валюты" shortname="Код валюты" type="2" length="4"/>
<currencyId name="Идентификатор валюты" shortname="Валюта" type="1"/>
<workflowStatus name="Статус" shortname="Секция" type="2" length="4"/>
<currency name="Код валюты" shortname="Код валюты" type="2" length="4"/>
<valueDate name="Дата, на которую расчетный курс" shortname="Дата" type="6"/>
<value name="Расчетный курс" shortname="Расчетный курс" type="10"/>
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
<actions>
<post name="Добавление расчетного курса" confirmation="value,valueDate,currencyId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RatesNewAction">
<value name="Расчетный курс" shortname="Расчетный курс" type="10"/>
<currencyId name="Идентификатор валюты" shortname="Валюта" type="1" link="currencyCode" linkCode="code" linkKeyCode="id"/>
<valueDate name="Дата, на которую расчетный курс" shortname="Дата" type="6"/>
<currencyId name="Идентификатор валюты" shortname="Валюта" type="1"/>
<status name="Статус" shortname="Секция" type="2" length="4"/>
<value name="Расчетный курс" shortname="Расчетный курс" type="10"/>
<status name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
</post>
<put name="Изменение расчетного курса" confirmation="value,status" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RatesUpdateAction">
<id type="1" name="Идентификатор записи" shortname="ID" link="rates" linkCode="id" required="true"/>
<value name="Расчетный курс" shortname="Расчетный курс" type="10"/>
<status name="Статус" shortname="Секция" type="2" length="4"/>
<status name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
</put>
</actions>
</rates>

View file

@ -4565,7 +4565,7 @@ GRANT ALL PRIVILEGES ON TABLE S_DF52 TO clearing;
-- sDf53 - ДФ-53 Квитанция о получении информации о состоянии счета (блокировка/разблокировка/закрытие/открытие)
DROP TABLE IF EXISTS S_DF53;
CREATE TABLE S_DF53(ID bigint PRIMARY KEY, ACC_NAME varchar(30), ACCOUNT varchar(25), DEAL varchar(4), DATE varchar(8), STATUS bigint, RESULT varchar(255), FILE_NAME varchar(255), GENERATION_TIME timestamp, GENERATION_ID bigint, IN_S_DF_ID bigint, ACC_TYPE bigint);
CREATE TABLE S_DF53(ID bigint PRIMARY KEY, ACC_NAME varchar(30), ACCOUNT varchar(25), DEAL varchar(4), DATE varchar(8), STATUS bigint, RESULT varchar(255), FILE_NAME varchar(255), GENERATION_TIME timestamp, GENERATION_ID bigint, IN_S_DF_ID bigint, ACC_TYPE varchar(3));
COMMENT ON TABLE S_DF53 IS 'ДФ-53 Квитанция о получении информации о состоянии счета (блокировка/разблокировка/закрытие/открытие)';
COMMENT ON COLUMN S_DF53.ID IS 'Идентификатор записи';
@ -5179,7 +5179,7 @@ GRANT ALL PRIVILEGES ON TABLE BLACKLIST_MARKET TO clearing;
CREATE TABLE RISK_PARAMETER
(
ID BIGINT,
ID BIGINT PRIMARY KEY,
VALUE numeric(72,18),
SETTLEMENT_TYPE VARCHAR(4),
CURRENCY_PAIR VARCHAR(12),
@ -5201,7 +5201,7 @@ GRANT ALL PRIVILEGES ON TABLE RISK_PARAMETER TO clearing;
CREATE TABLE RATES
(
ID BIGINT,
ID BIGINT PRIMARY KEY,
VALUE numeric(72, 18),
VALUE_DATE date,
CURRENCY VARCHAR(4),

View file

@ -485,6 +485,7 @@ INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (30, 'CBRR', 'Загрузк
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (31, 'MTCR', 'Формирование файлов с МТКР') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (32, 'LIMC', 'Выгрузка в Торговую систему остатков по валюте (отправка lim)') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (33, 'GREC', 'Формирование отчетности ЦК') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_STATUS_DICTIONARY(ID, CODE, NAME) values (1, 'ACTV', 'Активна') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;

View file

@ -36,7 +36,7 @@ COMMENT ON COLUMN BANK_ACCOUNT.OKTMO IS '
DROP TABLE IF EXISTS RISK_PARAMETER;
CREATE TABLE RISK_PARAMETER
(
ID BIGINT,
ID BIGINT PRIMARY KEY,
VALUE numeric(72,18),
SETTLEMENT_TYPE VARCHAR(4),
CURRENCY_PAIR VARCHAR(12),
@ -59,7 +59,7 @@ GRANT ALL PRIVILEGES ON TABLE RISK_PARAMETER TO clearing;
DROP TABLE IF EXISTS RATES;
CREATE TABLE RATES
(
ID BIGINT,
ID BIGINT PRIMARY KEY,
VALUE numeric(72, 18),
VALUE_DATE date,
CURRENCY VARCHAR(4),

View file

@ -16,6 +16,7 @@ public class GatewayApiSettings {
private KafkaConsumerSettings kafkaConsumer;
private InboundServerSettings inboundServer;
private InboundExternalServerSettings inboundExternalServer;
private String clearingSystem;
public HazelcastClientParams getHazelcast() {
return hazelcast;
@ -56,4 +57,12 @@ public class GatewayApiSettings {
public void setInboundExternalServer(InboundExternalServerSettings inboundExternalServer) {
this.inboundExternalServer = inboundExternalServer;
}
public String getClearingSystem() {
return clearingSystem;
}
public void setClearingSystem(String clearingSystem) {
this.clearingSystem = clearingSystem;
}
}

View file

@ -48,6 +48,10 @@ public class OutboundRequest {
)
private String section = "";
@JsonProperty("clearing_system")
@ApiModelProperty(value = "Клиринговая система", example = "SPVB/LCC")
private String clearingSystem;
// todo Пока так, чтобы отсылал null, в дальнейшем тип надо заменить на используемый в запросе. Возможно с помощью параметризации
@JsonProperty("content")
@ApiModelProperty(
@ -88,6 +92,14 @@ public class OutboundRequest {
this.section = section;
}
public String getClearingSystem() {
return clearingSystem;
}
public void setClearingSystem(String clearingSystem) {
this.clearingSystem = clearingSystem;
}
public Map<String, Object> getContent() {
return content;
}

View file

@ -0,0 +1,15 @@
package ru.spcex.clearing.gatewayapi.enums;
public enum ClearingSystems {
SPVB("SPVB"),
LCC("LCC");
private final String name;
ClearingSystems(final String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View file

@ -9,6 +9,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
@ -62,6 +63,7 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
private final RestTemplate restTemplate;
private final InboundServerSettings inboundServerSettings;
private final InboundExternalServerSettings inboundExternalServerSettings;
private final GatewayApiSettings gatewayApiSettings;
private final Map<Long, List<SentAsset>> sentAssets;
private final Map<UUID, OutboundRequest> outboundRequestByUuid;
protected final Imdg<GatewayResult> gatewayResultImdg;
@ -78,6 +80,7 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
super(kafkaQueue, kafkaProducer);
this.restTemplate = restTemplate;
this.userRoleVerification = userRoleVerification;
this.gatewayApiSettings = gatewayApiSettings;
this.inboundServerSettings = gatewayApiSettings.getInboundServer();
this.inboundExternalServerSettings = gatewayApiSettings.getInboundExternalServer();
this.sentAssets = sentAssets;
@ -274,6 +277,8 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
case KS_REP_FIRM_DETAILS -> paramName = "ks_rep_firm_details";
case KS_SESSION_LIST -> paramName = "ks_session_list";
case KS_COMMISSION_TRADES -> paramName = "ks_commission_trades";
case KS_REP_LCC_TRADES_REPORT -> paramName = "ks_rep_lcc_trades";
case KS_REP_LCC_NETTO_REPORT -> paramName = "ks_rep_lcc_netto";
}
if (paramName != null) {
content.put(paramName, reportPart.getFileName());
@ -281,8 +286,12 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
}
private void sendRequest(OutboundRequest request) {
if (inboundServerSettings.getAllowedTypes().isEmpty() ||
inboundServerSettings.getAllowedTypes().contains(request.getType())) {
String clearingSystem = StringUtils.isNotEmpty(gatewayApiSettings.getClearingSystem()) ?
gatewayApiSettings.getClearingSystem() : "SPVB";
request.setClearingSystem(clearingSystem);
if (inboundServerSettings != null &&
(inboundServerSettings.getAllowedTypes().isEmpty() ||
inboundServerSettings.getAllowedTypes().contains(request.getType()))) {
String url = formingInboundUrl(inboundServerSettings.getEnableSsl(),
inboundServerSettings.getHost(),
inboundServerSettings.getPort(),
@ -290,8 +299,9 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
exchange(request, url);
}
if (inboundExternalServerSettings.getAllowedTypes().isEmpty() ||
inboundExternalServerSettings.getAllowedTypes().contains(request.getType())) {
if (inboundExternalServerSettings != null &&
(inboundExternalServerSettings.getAllowedTypes().isEmpty() ||
inboundExternalServerSettings.getAllowedTypes().contains(request.getType()))) {
String url = formingInboundUrl(inboundExternalServerSettings.getEnableSsl(),
inboundExternalServerSettings.getHost(),
inboundExternalServerSettings.getPort(),
@ -300,7 +310,7 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
}
}
private void exchange(OutboundRequest request, String url){
private void exchange(OutboundRequest request, String url) {
HttpEntity<OutboundRequest> r = makeDefaultRequest(request);
ResponseEntity<SuccessResponse> response = restTemplate.exchange(url, HttpMethod.POST, r, SuccessResponse.class);
SuccessResponse bodyResponse = response.getBody();

View file

@ -25,6 +25,8 @@ gateway-api.kafka-consumer.auto-offset-reset=latest
gateway-api.kafka-consumer.linger-ms=1
gateway-api.kafka-consumer.buffer-memory=33554432
gateway-api.clearing-system=LCC
gateway-api.inbound-server.enable-ssl=false
gateway-api.inbound-server.host=10.200.200.183
gateway-api.inbound-server.port=8084

View file

@ -118,6 +118,18 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.20.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.20.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>

View file

@ -17,6 +17,7 @@ import org.springframework.jdbc.core.SqlTypeValue;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.lang.NonNull;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanyHistory;
@ -52,7 +53,7 @@ import static ru.spcex.clearing.imdg.utils.DbDataUtils.generatingRandomString;
TestConfiguration.class,
DbTestConnectionConfig.class})
@ExtendWith(SpringExtension.class)
//@TestPropertySource(properties = "spring.config.location=D:/repo/mfd/clearing/clearing-parent/imdg/src/main/resources") @TestPropertySource(locations = "/AllMapStoreTest.properties")
@TestPropertySource(locations="classpath:application.properties")
public class AllMapStoreTest {
private static final Long ID = 1000000L;
private final Logger log = LoggerFactory.getLogger(this.getClass());

View file

@ -0,0 +1,155 @@
package ru.spcex.clearing.imdg;
import static org.assertj.core.api.Assertions.assertThat;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.testcontainers.containers.PostgreSQLContainer;
import ru.spcex.clearing.imdg.config.ImdgSettings;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
ImdgSettings.class
})
public class DbUpdateCompareTest {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private static final File DB_SCRIPTS_LOCATION = new File("D:\\Projects\\MFD\\clearing\\clearing-parent\\db-scripts\\src\\main\\resources\\db\\");
@Test
public void compareCompleteDDLWithUpdatedDDL() {
// Creating docker containers
try (PostgreSQLContainer<?> dbWithCompleteDDL = new PostgreSQLContainer<>(PostgreSQLContainer.IMAGE);
PostgreSQLContainer<?> dbWithUpdatedDDL = new PostgreSQLContainer<>(PostgreSQLContainer.IMAGE)) {
// Starting docker containers
dbWithCompleteDDL.start();
dbWithUpdatedDDL.start();
// Acquiring JdbcTemplate through data source
JdbcTemplate dbWithCompleteDDLJdbc = new JdbcTemplate(getDataSource(dbWithCompleteDDL));
JdbcTemplate dbWithUpdatedDDLJdbc = new JdbcTemplate(getDataSource(dbWithUpdatedDDL));
// Creating clearing role
dbWithCompleteDDLJdbc.execute("CREATE ROLE clearing");
dbWithUpdatedDDLJdbc.execute("CREATE ROLE clearing");
// Executing DDL.sql (self-sufficient sql script containing all current updates)
new ResourceDatabasePopulator(new FileSystemResource(DB_SCRIPTS_LOCATION.toPath().resolve("DDL.sql").toString()))
.execute(Objects.requireNonNull(dbWithCompleteDDLJdbc.getDataSource()));
// Executing DDL_first.sql (template sql script for creating base tables)
new ResourceDatabasePopulator(new FileSystemResource(DB_SCRIPTS_LOCATION.toPath().resolve("DDL_first.sql").toString()))
.execute(Objects.requireNonNull(dbWithUpdatedDDLJdbc.getDataSource()));
// Executing all updateDDL_*.sql script in order
getUpdateScripts().forEach(us -> new ResourceDatabasePopulator(new FileSystemResource(us.getPath()))
.execute(Objects.requireNonNull(dbWithUpdatedDDLJdbc.getDataSource())));
// Get all table names
String getAllTablesSql = "SELECT table_name FROM information_schema.tables WHERE table_schema='public';";
List<String> dbWithCompleteDDLTables = dbWithCompleteDDLJdbc.queryForList(getAllTablesSql)
.stream()
.map(t -> t.get("table_name").toString())
.sorted()
.toList();
List<String> dbWithUpdatedDDLTables = dbWithUpdatedDDLJdbc.queryForList(getAllTablesSql)
.stream()
.map(t -> t.get("table_name").toString())
.sorted()
.toList();
assertThat(dbWithCompleteDDLTables.size()).isEqualTo(dbWithUpdatedDDLTables.size());
assertThat(dbWithCompleteDDLTables).usingRecursiveComparison().isEqualTo(dbWithUpdatedDDLTables);
// Comparing column names, data types, char max length, nullability, default values and comments
dbWithCompleteDDLTables.forEach(t -> {
String sql = """
SELECT cols.column_name,
(SELECT pg_catalog.col_description(c.oid, cols.ordinal_position::int)
FROM pg_catalog.pg_class c
WHERE c.oid = (SELECT ('"' || cols.table_name || '"')::regclass::oid)
AND c.relname = cols.table_name) AS column_comment,
cols.data_type,
cols.character_maximum_length,
cols.is_nullable
FROM information_schema.columns cols
WHERE cols.table_name = '""" + t + "';";
List<Map<String, Object>> firstTableResult = dbWithCompleteDDLJdbc.queryForList(sql)
.stream()
.sorted((Comparator.comparing(o -> ((String) o.get("column_name")))))
.toList();
List<Map<String, Object>> secondTableResult = dbWithUpdatedDDLJdbc.queryForList(sql)
.stream()
.sorted((Comparator.comparing(o -> ((String) o.get("column_name")))))
.toList();
assertThat(firstTableResult.size()).as("Checking columns quantity on table %s", t).isEqualTo(secondTableResult.size());
for (int i = 0; i < firstTableResult.size(); i++) {
Map<String, Object> first = firstTableResult.get(i);
Map<String, Object> second = secondTableResult.get(i);
assertThat(first.get("column_name")).as("Checking column's name on table %s", t).isEqualTo(second.get("column_name"));
// assertThat(first.get("column_comment")).as("Checking column's comment on table %s", t).isEqualTo(second.get("column_comment"));
assertThat(first.get("data_type")).as("Checking column's %s data type on table %s", first.get("column_name"), t).isEqualTo(second.get("data_type"));
assertThat(first.get("character_maximum_length")).as("Checking column's %s character maximum length on table %s", first.get("column_name"), t).isEqualTo(second.get("character_maximum_length"));
assertThat(first.get("is_nullable")).as("Checking column's %s nullability on table %s", first.get("column_name"), t).isEqualTo(second.get("is_nullable"));
}
});
}
}
private List<File> getUpdateScripts() {
return Stream.of(Objects.requireNonNull(DB_SCRIPTS_LOCATION.listFiles(File::isFile)))
.filter(f -> f.getName().startsWith("updateDDL"))
.sorted((o1, o2) -> versionCompare(o1.getName(), o2.getName()))
.toList();
}
private int versionCompare(String o1, String o2) {
List<Integer> o1Version = Arrays.stream(o1.substring(0, o1.lastIndexOf(".")).split("_")[1].split("\\.")).map(Integer::parseInt).toList();
List<Integer> o2Version = Arrays.stream(o2.substring(0, o2.lastIndexOf(".")).split("_")[1].split("\\.")).map(Integer::parseInt).toList();
for (int i = 0; i < Math.min(o1Version.size(), o2Version.size()); i++) {
if (!o1Version.get(i).equals(o2Version.get(i))) {
return o1Version.get(i).compareTo(o2Version.get(i));
}
}
return Integer.compare(o1Version.size(), o2Version.size());
}
private DataSource getDataSource(PostgreSQLContainer<?> container) {
ComboPooledDataSource cpds = new ComboPooledDataSource();
try {
cpds.setDriverClass(container.getDriverClassName());
cpds.setJdbcUrl(container.getJdbcUrl());
cpds.setUser(container.getUsername());
cpds.setPassword(container.getPassword());
cpds.setMaxPoolSize(100);
cpds.setMinPoolSize(50);
cpds.setAcquireIncrement(5);
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
return cpds;
}
}

View file

@ -1,24 +1,28 @@
package ru.spcex.clearing.imdg.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import ru.spcex.clearing.imdg.error.ModuleInitializeException;
import javax.sql.DataSource;
import java.sql.Connection;
@SuppressWarnings("UnnecessaryLocalVariable")
@Configuration
public class DbTestConnectionConfig {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final ImdgSettings settings;
public DbTestConnectionConfig(@Qualifier("imdgSettingsTest") ImdgSettings settings) {
this.settings = settings;
}
private DatabasePopulator createDatabasePopulator() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
@ -30,10 +34,10 @@ public class DbTestConnectionConfig {
@Bean
public DataSource dataSource() {
DataSource result;
String login = "clearing";
String password = "Aa111111";
String login = settings.getDatabase().getLogin();
String password = settings.getDatabase().getPassword();
String logTimeoutPart = "";
String dbPath = "jdbc:postgresql://10.200.200.133:5432/postgres?currentSchema=clearing_tester";
String dbPath = settings.getDatabase().getUrl();
int timeoutSec = 30;
ComboPooledDataSource cpds = new ComboPooledDataSource();

View file

@ -0,0 +1,31 @@
package ru.spcex.clearing.imdg.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.test.context.TestPropertySource;
import ru.spcex.clearing.imdg.config.element.DatabaseSettings;
import ru.spcex.clearing.imdg.config.element.HazelcastServerSettings;
@Component("imdgSettingsTest")
@TestPropertySource(locations="classpath:application.properties")
@ConfigurationProperties("imdg")
public class ImdgSettings {
private HazelcastServerSettings hazelcast;
private DatabaseSettings database;
public HazelcastServerSettings getHazelcast() {
return hazelcast;
}
public void setHazelcast(HazelcastServerSettings hazelcast) {
this.hazelcast = hazelcast;
}
public DatabaseSettings getDatabase() {
return database;
}
public void setDatabase(DatabaseSettings database) {
this.database = database;
}
}

View file

@ -56,7 +56,23 @@ public class RunnableMapNamesForTesting {
//business event
// businessObjectAndBusinessEventForCheckMapStores.add(new BusinessObjectAndBusinessEventForCheckMapStore<>(IMDGDistributedNames.Map_AccountBalanceHistory, AccountBalanceHistory.class));
checkerBusinessMapStores.add(new CheckerBusinessMapStore<>(IMDGDistributedNames.Map_AccountHistory, AccountHistory.class));
checkerBusinessMapStores.add(new CheckerBusinessMapStore<>(IMDGDistributedNames.Map_BankAccountHistory, BankAccountHistory.class));
checkerBusinessMapStores.add(new CheckerBusinessMapStore<>(IMDGDistributedNames.Map_BankAccountHistory, BankAccountHistory.class, usingIgnoringFieldsComparator(
"object.address",
"object.bankAccount",
"object.bankAccount1",
"object.bankAccount2",
"object.bankAddress",
"object.bankAddress1",
"object.bankAddress2",
"object.bankName1",
"object.bankName2",
"object.bankSwiftCode",
"object.budgetClassificationCode",
"object.intermediarySwiftCode2",
"object.name",
"object.oktmo",
"object.personalAccount"
)));
checkerBusinessMapStores.add(new CheckerBusinessMapStore<>(IMDGDistributedNames.Map_CompanyHistory, CompanyHistory.class,
usingIgnoringFieldsComparator("object.profile.clearingCode", "object.profile.fullName", "object.profile.registrationCode", "object.profile.shortName", "object.profile.tradingCode")));
checkerBusinessMapStores.add(new CheckerBusinessMapStore<>(IMDGDistributedNames.Map_ExecutionDepositHistory, ExecutionDepositHistory.class,

File diff suppressed because it is too large Load diff

View file

@ -1,35 +1,40 @@
package ru.spcex.clearing.lim.exporter.services;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.lim.exporter.config.LimFormat;
import ru.spcex.clearing.lim.exporter.config.SFTPConfig;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.enumeration.RegistryStatus;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
import ru.spcex.platform.enumeration.Section;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
@Service
public class CurrencyExporterService extends AbstractExporterService {
private final Logger log = LoggerFactory.getLogger(getClass());
private boolean includeCK;
public CurrencyExporterService(SFTPConfig.LimGateway gateway,
KafkaSender kafkaSender,
ImdgProvider imdgProvider) {
ImdgProvider imdgProvider,
@Value("${export-lim-service.include-ck:false}") String includeCKStrValue) {
super(gateway, kafkaSender, imdgProvider);
includeCK = Boolean.parseBoolean(includeCKStrValue);
}
@Override
@ -56,23 +61,79 @@ public class CurrencyExporterService extends AbstractExporterService {
pb.equals("tradingClearingRegistry", registry.getTradingClearingRegistry()),
pb.equals("securityId", registry.getSecurityId())
);
BiFunction<Registry, LocalDate, ImdgPredicate> prdctOM_T = (registry, date) -> pb.and(
pb.sql(RegistryCodeSqlBuilder.getInstance(OM_T).build()),
pb.in("registryStatus", RegistryStatus.PROC.getKey(), RegistryStatus.MNG.getKey()),
pb.equals("tradingClearingRegistry", registry.getTradingClearingRegistry()),
pb.equals("securityId", registry.getSecurityId()),
pb.equals("settlementDate", date)
);
BiFunction<Registry, LocalDate, ImdgPredicate> prdctTM_T = (registry, date) -> pb.and(
pb.sql(RegistryCodeSqlBuilder.getInstance(TM_T).build()),
pb.in("registryStatus", RegistryStatus.PROC.getKey(), RegistryStatus.MNG.getKey()),
pb.equals("tradingClearingRegistry", registry.getTradingClearingRegistry()),
pb.equals("securityId", registry.getSecurityId()),
pb.equals("settlementDate", date)
);
for (Registry registry : registriesA) {
if (checkNotBlocked(registry)) {
BigDecimal sumPositive = BigDecimal.ZERO;
BigDecimal dmtSumElement = BigDecimal.ZERO;
BigDecimal omtSumElementToday = BigDecimal.ZERO;
BigDecimal tmtSumElementToday = BigDecimal.ZERO;
BigDecimal omtSumElementTomorrow = BigDecimal.ZERO;
BigDecimal tmtSumElementTomorrow = BigDecimal.ZERO;
if (registry.getTradingClearingRegistry() != null && registry.getSecurityId() != null) {
ImdgPredicate query = prdctDM_T.apply(registry);
Collection<Registry> regsDMT = registryImdg.getCollectionObjectsByPredicate(query);
log.trace("Found {} DM_T registries for registry AM_F {}", regsDMT.size(), query);
sumPositive = sumPositive.add(sum(regsDMT));
ImdgPredicate queryDM_T = prdctDM_T.apply(registry);
Collection<Registry> regsDMT = registryImdg.getCollectionObjectsByPredicate(queryDM_T);
log.trace("Found {} DM_T registries for registry AM_F {}", regsDMT.size(), queryDM_T);
dmtSumElement = dmtSumElement.add(sum(regsDMT)).negate();
if (includeCK) {
ImdgPredicate queryOM_T_today = prdctOM_T.apply(registry, LocalDate.now());
Collection<Registry> regsOMT_today = registryImdg.getCollectionObjectsByPredicate(queryOM_T_today);
log.trace("Found {} OM_T today registries for registry AM_F {}", regsOMT_today.size(), queryOM_T_today);
omtSumElementToday = omtSumElementToday.add(sum(regsOMT_today)).negate();
ImdgPredicate queryTM_T_today = prdctTM_T.apply(registry, LocalDate.now());
Collection<Registry> regsTMT_today = registryImdg.getCollectionObjectsByPredicate(queryTM_T_today);
log.trace("Found {} TM_T today registries for registry AM_F {}", regsTMT_today.size(), queryTM_T_today);
tmtSumElementToday = tmtSumElementToday.add(sum(regsTMT_today));
ImdgPredicate queryOM_T_tomorrow = prdctOM_T.apply(registry, LocalDate.now().plusDays(1));
Collection<Registry> regsOMT_tomorrow = registryImdg.getCollectionObjectsByPredicate(queryOM_T_tomorrow);
log.trace("Found {} OM_T tomorrow registries for registry AM_F {}", regsOMT_tomorrow.size(), queryOM_T_tomorrow);
omtSumElementTomorrow = omtSumElementTomorrow.add(sum(regsOMT_tomorrow)).negate();
ImdgPredicate queryTM_T_tomorrow = prdctTM_T.apply(registry, LocalDate.now().plusDays(1));
Collection<Registry> regsTMT_tomorrow = registryImdg.getCollectionObjectsByPredicate(queryTM_T_tomorrow);
log.trace("Found {} TM_T tomorrow registries for registry AM_F {}", regsTMT_tomorrow.size(), queryTM_T_tomorrow);
tmtSumElementTomorrow = tmtSumElementTomorrow.add(sum(regsTMT_tomorrow));
}
}
limFileRows.add(getRow(registry, sumPositive));
limFileRows.add(
getRow(registry,
0,
dmtSumElement,
omtSumElementToday,
tmtSumElementToday)
);
limFileRows.add(
getRow(registry,
1,
dmtSumElement,
omtSumElementToday,
tmtSumElementToday,
omtSumElementTomorrow,
tmtSumElementTomorrow)
);
}
}
log.debug("Successfully completed the formation of rows: {} for export currency(money)", limFileRows.size());
return limFileRows;
}
public String getRow(Registry registryA, BigDecimal sumPositive) {
public String getRow(Registry registryA, int limitKind, BigDecimal ... sumElements) {
assert limitKind == 0 || limitKind == 1;
StringBuilder row = new StringBuilder();
row.append("MONEY: FIRM_ID = ");
@ -87,12 +148,16 @@ public class CurrencyExporterService extends AbstractExporterService {
row.append(registryA.getTradingClearingRegistry());
row.append("; OPEN_BALANCE = ");
BigDecimal balance = registryA.getBalance() != null ? registryA.getBalance().subtract(sumPositive) : BigDecimal.ZERO;
BigDecimal balance = registryA.getBalance() != null ? registryA.getBalance() : BigDecimal.ZERO;
for (BigDecimal sumElement : sumElements) {
if (sumElement == null) continue;
balance = balance.add(sumElement);
}
row.append(LimFormat.toStringD2(balance));
row.append("; OPEN_LIMIT = 0.00");
row.append("; LIMIT_KIND = 0;");
row.append("; LIMIT_KIND = %d;".formatted(limitKind));
return row.toString();
}
}

View file

@ -1,36 +1,40 @@
package ru.spcex.clearing.lim.exporter.services;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.lim.exporter.config.LimFormat;
import ru.spcex.clearing.lim.exporter.config.SFTPConfig;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.enumeration.RegistryStatus;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
import ru.spcex.platform.enumeration.Section;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import static ru.spcex.platform.enumeration.RegistryTradingParams.AM_F;
import static ru.spcex.platform.enumeration.RegistryTradingParams.DM_T;
@Service
public class MoneyExporterService extends AbstractExporterService {
private final Logger log = LoggerFactory.getLogger(getClass());
private boolean includeCK;
public MoneyExporterService(SFTPConfig.LimGateway gateway,
KafkaSender kafkaSender,
ImdgProvider imdgProvider) {
ImdgProvider imdgProvider,
@Value("${export-lim-service.include-ck:false}") String includeCKStrValue) {
super(gateway, kafkaSender, imdgProvider);
includeCK = Boolean.parseBoolean(includeCKStrValue);
}
@Override
@ -57,23 +61,79 @@ public class MoneyExporterService extends AbstractExporterService {
pb.equals("tradingClearingRegistry", registry.getTradingClearingRegistry()),
pb.equals("securityId", registry.getSecurityId())
);
BiFunction<Registry, LocalDate, ImdgPredicate> prdctOM_T = (registry, date) -> pb.and(
pb.sql(RegistryCodeSqlBuilder.getInstance(OM_T).build()),
pb.in("registryStatus", RegistryStatus.PROC.getKey(), RegistryStatus.MNG.getKey()),
pb.equals("tradingClearingRegistry", registry.getTradingClearingRegistry()),
pb.equals("securityId", registry.getSecurityId()),
pb.equals("settlementDate", date)
);
BiFunction<Registry, LocalDate, ImdgPredicate> prdctTM_T = (registry, date) -> pb.and(
pb.sql(RegistryCodeSqlBuilder.getInstance(TM_T).build()),
pb.in("registryStatus", RegistryStatus.PROC.getKey(), RegistryStatus.MNG.getKey()),
pb.equals("tradingClearingRegistry", registry.getTradingClearingRegistry()),
pb.equals("securityId", registry.getSecurityId()),
pb.equals("settlementDate", date)
);
for (Registry registry : registriesA) {
if (checkNotBlocked(registry)) {
BigDecimal sumPositive = BigDecimal.ZERO;
BigDecimal dmtSumElement = BigDecimal.ZERO;
BigDecimal omtSumElementToday = BigDecimal.ZERO;
BigDecimal tmtSumElementToday = BigDecimal.ZERO;
BigDecimal omtSumElementTomorrow = BigDecimal.ZERO;
BigDecimal tmtSumElementTomorrow = BigDecimal.ZERO;
if (registry.getTradingClearingRegistry() != null && registry.getSecurityId() != null) {
ImdgPredicate query = prdctDM_T.apply(registry);
Collection<Registry> regsDMT = registryImdg.getCollectionObjectsByPredicate(query);
log.trace("Found {} DM_T registries for registry AM_F {}", regsDMT.size(), query);
sumPositive = sumPositive.add(sum(regsDMT));
ImdgPredicate dmtQuery = prdctDM_T.apply(registry);
Collection<Registry> regsDMT = registryImdg.getCollectionObjectsByPredicate(dmtQuery);
log.trace("Found {} DM_T registries for registry AM_F {}", regsDMT.size(), dmtQuery);
dmtSumElement = dmtSumElement.add(sum(regsDMT)).negate();
if (includeCK) {
ImdgPredicate queryOM_T_today = prdctOM_T.apply(registry, LocalDate.now());
Collection<Registry> regsOMT_today = registryImdg.getCollectionObjectsByPredicate(queryOM_T_today);
log.trace("Found {} OM_T today registries for registry AM_F {}", regsOMT_today.size(), queryOM_T_today);
omtSumElementToday = omtSumElementToday.add(sum(regsOMT_today)).negate();
ImdgPredicate queryTM_T_today = prdctTM_T.apply(registry, LocalDate.now());
Collection<Registry> regsTMT_today = registryImdg.getCollectionObjectsByPredicate(queryTM_T_today);
log.trace("Found {} TM_T today registries for registry AM_F {}", regsTMT_today.size(), queryTM_T_today);
tmtSumElementToday = tmtSumElementToday.add(sum(regsTMT_today));
ImdgPredicate queryOM_T_tomorrow = prdctOM_T.apply(registry, LocalDate.now().plusDays(1));
Collection<Registry> regsOMT_tomorrow = registryImdg.getCollectionObjectsByPredicate(queryOM_T_tomorrow);
log.trace("Found {} OM_T tomorrow registries for registry AM_F {}", regsOMT_tomorrow.size(), queryOM_T_tomorrow);
omtSumElementTomorrow = omtSumElementTomorrow.add(sum(regsOMT_tomorrow)).negate();
ImdgPredicate queryTM_T_tomorrow = prdctTM_T.apply(registry, LocalDate.now().plusDays(1));
Collection<Registry> regsTMT_tomorrow = registryImdg.getCollectionObjectsByPredicate(queryTM_T_tomorrow);
log.trace("Found {} TM_T tomorrow registries for registry AM_F {}", regsTMT_tomorrow.size(), queryTM_T_tomorrow);
tmtSumElementTomorrow = tmtSumElementTomorrow.add(sum(regsTMT_tomorrow));
}
}
limFileRows.add(getRow(registry, sumPositive));
limFileRows.add(
getRow(registry,
0,
dmtSumElement,
omtSumElementToday,
tmtSumElementToday)
);
limFileRows.add(
getRow(registry,
1,
dmtSumElement,
omtSumElementToday,
tmtSumElementToday,
omtSumElementTomorrow,
tmtSumElementTomorrow)
);
}
}
log.debug("Successfully completed the formation of rows: {} for export money", limFileRows.size());
return limFileRows;
}
public String getRow(Registry registryA, BigDecimal sumPositive) {
public String getRow(Registry registryA, int limitKind, BigDecimal ... sumElements) {
assert limitKind == 0 || limitKind == 1;
StringBuilder row = new StringBuilder();
row.append("MONEY: FIRM_ID = ");
@ -88,12 +148,16 @@ public class MoneyExporterService extends AbstractExporterService {
row.append(registryA.getTradingClearingRegistry());
row.append("; OPEN_BALANCE = ");
BigDecimal balance = registryA.getBalance() != null ? registryA.getBalance().subtract(sumPositive) : BigDecimal.ZERO;
BigDecimal balance = registryA.getBalance() != null ? registryA.getBalance() : BigDecimal.ZERO;
for (BigDecimal sumElement : sumElements) {
if (sumElement == null) continue;
balance = balance.add(sumElement);
}
row.append(LimFormat.toStringD2(balance));
row.append("; OPEN_LIMIT = 0.00");
row.append("; LIMIT_KIND = 0;");
row.append("; LIMIT_KIND = %d;".formatted(limitKind));
return row.toString();
}
}

View file

@ -26,4 +26,6 @@ export-lim-service.kafka-producer.acks=all
export-lim-service.kafka-producer.retries=0
export-lim-service.kafka-producer.batch-size=16384
export-lim-service.kafka-producer.linger-ms=1
export-lim-service.kafka-producer.buffer-memory=33554432
export-lim-service.kafka-producer.buffer-memory=33554432
export-lim-service.include-ck=true

View file

@ -1,5 +1,8 @@
package ru.spcex.clearing.lim.exporter;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Objects;
import org.apache.kafka.clients.producer.Producer;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -12,6 +15,8 @@ import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.test.config.ImdgTestConfig;
import static ru.spcex.clearing.test.config.ImdgTestConfig.currentID;
import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId;
import ru.spcex.clearing.test.config.KafkaTestConfig;
import ru.spcex.platform.enumeration.RegistryDesignation;
import ru.spcex.platform.enumeration.RegistryStatus;
@ -19,12 +24,6 @@ import ru.spcex.platform.enumeration.RegistryUnit;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.math.BigDecimal;
import java.time.LocalDate;
import static ru.spcex.clearing.test.config.ImdgTestConfig.currentID;
import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
ImdgTestConfig.class,
@ -93,6 +92,32 @@ public abstract class AbstractServiceTest {
return registry;
}
protected Registry getRegistry(String tradingClearingRegistry,
Long securityId,
String registryDesignation,
String registryInstrumentType,
String registryUnit,
LocalDate settlementDate,
BigDecimal balance) {
Registry registry = new Registry();
registry.setTradingCode("1A12323");
registry.setBalance(balance);
registry.setTradingClearingRegistry(tradingClearingRegistry);
registry.setRegistryDesignation(registryDesignation);
registry.setRegistryInstrumentType(registryInstrumentType);
registry.setRegistryUnit(registryUnit);
registry.setClearingCode(clearingCode(registry));
registry.setClearingDate(currentDate);
registry.setSettlementDate(currentDate);
registry.setSecuritySymbol("RUB");
registry.setSecurityId(securityId);
registry.setTradingClearingRegistryId(securityId);
registry.setCompanyId(securityId);
registry.setRegistryStatus(RegistryStatus.PROC.getKey());
registry.setSettlementDate(Objects.requireNonNullElseGet(settlementDate, LocalDate::now));
return registry;
}
protected Registry getRegistryNegativeD(String tradingClearingRegistry, Long securityId, String registryInstrumentType, String registryUnit) {
Registry registry = getRegistryD(tradingClearingRegistry, securityId, registryInstrumentType, registryUnit);
registry.setBalance(registry.getBalance().negate());

View file

@ -1,18 +1,8 @@
package ru.spcex.clearing.lim.exporter.services;
import javax.annotation.PostConstruct;
import org.junit.jupiter.api.Test;
import ru.spcex.clearing.lim.exporter.AbstractServiceTest;
import ru.spcex.clearing.lim.exporter.config.KafkaConfig;
import ru.spcex.clearing.lim.exporter.config.settings.ExportLimServiceSettings;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSenderBuilderImpl;
import ru.spcex.clearing.test.TestUtils;
import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import static org.junit.jupiter.api.Assertions.*;
class AbstractExporterServiceTest extends AbstractServiceTest {
@PostConstruct
@ -22,7 +12,7 @@ class AbstractExporterServiceTest extends AbstractServiceTest {
@Test
void sendLimExportedNotification() {
AbstractExporterService moneyExporterService = new MoneyExporterService(null, kafkaSender, imdgProvider);
AbstractExporterService moneyExporterService = new MoneyExporterService(null, kafkaSender, imdgProvider, "true");
String fileName = "limits_money_202305241832.lim";
moneyExporterService.sendLimExportedNotification(fileName);

View file

@ -1,21 +1,21 @@
package ru.spcex.clearing.lim.exporter.services;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import javax.annotation.PostConstruct;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.lim.exporter.AbstractServiceTest;
import static ru.spcex.clearing.test.TestUtils.clearAllInImdg;
import ru.spcex.platform.enumeration.RegistryDesignation;
import ru.spcex.platform.enumeration.RegistryInstrumentType;
import ru.spcex.platform.enumeration.RegistryUnit;
import ru.spcex.platform.enumeration.ServiceStatus;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.Collection;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static ru.spcex.clearing.test.TestUtils.clearAllInImdg;
class MoneyExporterServiceTest extends AbstractServiceTest {
@PostConstruct
public void init() {
@ -33,17 +33,37 @@ class MoneyExporterServiceTest extends AbstractServiceTest {
Registry registryD = getRegistryD(tcrFirst, securityIdFirst, RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey());
registryImdg.insert(registryA);
registryImdg.insert(registryD);
registryD = getRegistryNegativeD(tcrFirst, securityIdFirst, RegistryInstrumentType.M.getKey(), RegistryUnit.I.getKey());
registryImdg.insert(registryD);
Registry registryD_negate = getRegistryNegativeD(tcrFirst, securityIdFirst, RegistryInstrumentType.M.getKey(), RegistryUnit.I.getKey());
registryImdg.insert(registryD_negate);
registryA = getRegistryA(tcrSecond, securityIdSecond, RegistryInstrumentType.M.getKey());
registryD = getRegistryD(tcrSecond, securityIdSecond, RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey());
registryImdg.insert(registryA);
registryImdg.insert(registryD);
registryD = getRegistryNegativeD(tcrFirst, securityIdFirst, RegistryInstrumentType.M.getKey(), RegistryUnit.I.getKey());
registryImdg.insert(registryD);
registryD_negate = getRegistryNegativeD(tcrFirst, securityIdFirst, RegistryInstrumentType.M.getKey(), RegistryUnit.I.getKey());
registryImdg.insert(registryD_negate);
Registry registryO_1 = getRegistry(tcrFirst, securityIdFirst, RegistryDesignation.O.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now(), BigDecimal.valueOf(5));
Registry registryO_2 = getRegistry(tcrFirst, securityIdFirst, RegistryDesignation.O.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now().plusDays(1), BigDecimal.valueOf(10));
registryImdg.insert(registryO_1);
registryImdg.insert(registryO_2);
Registry registryT_1 = getRegistry(tcrFirst, securityIdFirst, RegistryDesignation.T.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now(), BigDecimal.valueOf(5));
Registry registryT_2 = getRegistry(tcrFirst, securityIdFirst, RegistryDesignation.T.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now().plusDays(1), BigDecimal.valueOf(10));
registryImdg.insert(registryT_1);
registryImdg.insert(registryT_2);
registryO_1 = getRegistry(tcrSecond, securityIdSecond, RegistryDesignation.O.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now(), BigDecimal.valueOf(5));
registryO_2 = getRegistry(tcrSecond, securityIdSecond, RegistryDesignation.O.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now().plusDays(1), BigDecimal.valueOf(10));
registryImdg.insert(registryO_1);
registryImdg.insert(registryO_2);
registryT_1 = getRegistry(tcrSecond, securityIdSecond, RegistryDesignation.T.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now(), BigDecimal.valueOf(5));
registryT_2 = getRegistry(tcrSecond, securityIdSecond, RegistryDesignation.T.getKey(), RegistryInstrumentType.M.getKey(), RegistryUnit.T.getKey(), LocalDate.now().plusDays(1), BigDecimal.valueOf(10));
registryImdg.insert(registryT_1);
registryImdg.insert(registryT_2);
MoneyExporterService moneyExporterService = new MoneyExporterService(null, kafkaSender, imdgProvider);
MoneyExporterService moneyExporterService = new MoneyExporterService(null, kafkaSender, imdgProvider, "true");
Collection<String> limFileRows = moneyExporterService.getLimFileRows();
assertEquals(0, limFileRows.size());
@ -55,7 +75,18 @@ class MoneyExporterServiceTest extends AbstractServiceTest {
tradingClearingRegistryImdg.insert(tradingClearingRegistry);
limFileRows = moneyExporterService.getLimFileRows();
assertEquals(2, limFileRows.size());
assertTrue(limFileRows.contains(moneyExporterService.getRow(registryA, new BigDecimal("5.00"))));
assertEquals(4, limFileRows.size());
assertTrue(limFileRows.contains(moneyExporterService.getRow(registryA,
0,
registryD.getBalance().negate(),
registryO_1.getBalance().negate(),
registryT_1.getBalance())));
assertTrue(limFileRows.contains(moneyExporterService.getRow(registryA,
1,
registryD.getBalance().negate(),
registryO_1.getBalance().negate(),
registryT_1.getBalance(),
registryO_2.getBalance().negate(),
registryT_2.getBalance())));
}
}

View file

@ -0,0 +1,111 @@
package ru.spcex.clearing.reports.builders.bean;
import java.math.BigDecimal;
import java.time.LocalDate;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.CsvBindByPosition;
import com.opencsv.bean.CsvDate;
import com.opencsv.bean.CsvNumber;
public class KSRepLccNettoReport {
@CsvBindByName(column = "FIRM_ID")
@CsvBindByPosition(position = 0)
private String firmId;
@CsvBindByName(column = "TKR")
@CsvBindByPosition(position = 1)
private String tkr;
@CsvBindByName(column = "CURRENCYID")
@CsvBindByPosition(position = 2)
private String currencyId;
@CsvBindByName(column = "DATE")
@CsvBindByPosition(position = 3)
@CsvDate(value = "yyyy-MM-dd")
private LocalDate date;
@CsvBindByName(column = "NETTO_SUM")
@CsvBindByPosition(position = 4)
@CsvNumber(value = "#0", writeFormat = "#0")
private BigDecimal nettoSum;
@CsvBindByName(column = "DATA_TYPE")
@CsvBindByPosition(position = 5)
private String dataType;
@CsvBindByName(column = "DEBIT")
@CsvBindByPosition(position = 6)
@CsvNumber(value = "#0.00", writeFormat = "#0.00")
private BigDecimal debit;
@CsvBindByName(column = "CREDIT")
@CsvBindByPosition(position = 7)
@CsvNumber(value = "#0.00", writeFormat = "#0.00")
private BigDecimal credit;
public String getFirmId() {
return firmId;
}
public void setFirmId(String firmId) {
this.firmId = firmId;
}
public String getTkr() {
return tkr;
}
public void setTkr(String tkr) {
this.tkr = tkr;
}
public String getCurrencyId() {
return currencyId;
}
public void setCurrencyId(String currencyId) {
this.currencyId = currencyId;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public BigDecimal getNettoSum() {
return nettoSum;
}
public void setNettoSum(BigDecimal nettoSum) {
this.nettoSum = nettoSum;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public BigDecimal getDebit() {
return debit;
}
public void setDebit(BigDecimal debit) {
this.debit = debit;
}
public BigDecimal getCredit() {
return credit;
}
public void setCredit(BigDecimal credit) {
this.credit = credit;
}
}

View file

@ -0,0 +1,181 @@
package ru.spcex.clearing.reports.builders.bean;
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.CsvBindByPosition;
import com.opencsv.bean.CsvDate;
public class KSRepLccTradesReport {
@CsvBindByName(column = "SESSION_ID")
@CsvBindByPosition(position = 0)
private Long sessionId;
@CsvBindByName(column = "SESSION_DATE")
@CsvBindByPosition(position = 1)
@CsvDate(value = "dd.MM.yyyy'T'HH:mm:ss")
private LocalDateTime sessionDate;
@CsvBindByName(column = "TRADE_NUM")
@CsvBindByPosition(position = 2)
private Long tradeNum;
@CsvBindByName(column = "SECCODE")
@CsvBindByPosition(position = 3)
private String secCode;
@CsvBindByName(column = "FIRM_ID")
@CsvBindByPosition(position = 4)
private String firmId;
@CsvBindByName(column = "TKR")
@CsvBindByPosition(position = 5)
private String tkr;
@CsvBindByName(column = "ACCOUNT")
@CsvBindByPosition(position = 6)
private String account;
@CsvBindByName(column = "CLASS_CODE")
@CsvBindByPosition(position = 7)
private String classCode;
@CsvBindByName(column = "TRADE_DATE")
@CsvBindByPosition(position = 8)
@CsvDate(value = "dd.MM.yyyy'T'HH:mm:ss")
private LocalDateTime tradeDate;
@CsvBindByName(column = "TRADE_GROUP")
@CsvBindByPosition(position = 9)
private String tradeGroup;
@CsvBindByName(column = "BUY_SELL")
@CsvBindByPosition(position = 10)
private String buySell;
@CsvBindByName(column = "LOT_CURRENCY")
@CsvBindByPosition(position = 11)
private String lotCurrency;
@CsvBindByName(column = "CO_CURRENCY")
@CsvBindByPosition(position = 12)
private String coCurrency;
@CsvBindByName(column = "SETTLEDATE")
@CsvBindByPosition(position = 13)
@CsvDate(value = "yyyy-MM-dd")
private LocalDate settleDate;
public Long getSessionId() {
return sessionId;
}
public void setSessionId(Long sessionId) {
this.sessionId = sessionId;
}
public LocalDateTime getSessionDate() {
return sessionDate;
}
public void setSessionDate(LocalDateTime sessionDate) {
this.sessionDate = sessionDate;
}
public Long getTradeNum() {
return tradeNum;
}
public void setTradeNum(Long tradeNum) {
this.tradeNum = tradeNum;
}
public String getSecCode() {
return secCode;
}
public void setSecCode(String secCode) {
this.secCode = secCode;
}
public String getFirmId() {
return firmId;
}
public void setFirmId(String firmId) {
this.firmId = firmId;
}
public String getTkr() {
return tkr;
}
public void setTkr(String tkr) {
this.tkr = tkr;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getClassCode() {
return classCode;
}
public void setClassCode(String classCode) {
this.classCode = classCode;
}
public LocalDateTime getTradeDate() {
return tradeDate;
}
public void setTradeDate(LocalDateTime tradeDate) {
this.tradeDate = tradeDate;
}
public String getTradeGroup() {
return tradeGroup;
}
public void setTradeGroup(String tradeGroup) {
this.tradeGroup = tradeGroup;
}
public String getBuySell() {
return buySell;
}
public void setBuySell(String buySell) {
this.buySell = buySell;
}
public String getLotCurrency() {
return lotCurrency;
}
public void setLotCurrency(String lotCurrency) {
this.lotCurrency = lotCurrency;
}
public String getCoCurrency() {
return coCurrency;
}
public void setCoCurrency(String coCurrency) {
this.coCurrency = coCurrency;
}
public LocalDate getSettleDate() {
return settleDate;
}
public void setSettleDate(LocalDate settleDate) {
this.settleDate = settleDate;
}
}

View file

@ -0,0 +1,126 @@
package ru.spcex.clearing.reports.builders.ks;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.stereotype.Component;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.reports.builders.CSVReportBuilder;
import ru.spcex.clearing.reports.builders.EmptyParams;
import ru.spcex.clearing.reports.builders.bean.KSRepLccNettoReport;
import ru.spcex.platform.enumeration.RegistryDesignation;
import ru.spcex.platform.enumeration.RegistryStatus;
import ru.spcex.platform.enumeration.RegistryTradingParams;
import ru.spcex.platform.enumeration.ReportBuilderType;
import ru.spcex.platform.enumeration.ReportKeys;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
import ru.spcex.platform.utils.enumeration.IEnumKey;
@Component
public class KSRepLccNettoReportBuilder extends CSVReportBuilder<EmptyParams, KSRepLccNettoReport> {
private final Imdg<Registry> registryImdg;
private List<KSRepLccNettoReport> rows = null;
public KSRepLccNettoReportBuilder(ImdgProvider imdgProvider) {
registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
}
@Override
protected List<KSRepLccNettoReport> getRows() {
return rows;
}
@Override
public ReportBuilderType getReportType() {
return ReportBuilderType.KS_REP_LCC_NETTO;
}
@Override
public ReportKeys getReportKey() {
return ReportKeys.KS_REP_LCC_NETTO_REPORT;
}
@Override
public Class<EmptyParams> getParamsClass() {
return EmptyParams.class;
}
@Override
public Class<KSRepLccNettoReport> getReportClass() {
return KSRepLccNettoReport.class;
}
@Override
protected void collect(EmptyParams params) {
rows = new ArrayList<>();
LocalDate now = LocalDate.now();
ImdgPredicateBuilder pb = registryImdg.predicateBuilder();
ImdgPredicate registryPredicate = RegistryCodeSqlBuilder.getInstance(
RegistryTradingParams.AM_T, RegistryTradingParams.OM_T, RegistryTradingParams.TM_T
).buildPredicate(pb);
Collection<Registry> registries = registryImdg.getCollectionObjectsByPredicate(
pb.and(
registryPredicate,
pb.equals("settlementDate", now)
)
);
for (Registry registry : registries) {
for (DataTypes dataType : DataTypes.values()) {
KSRepLccNettoReport ksRepLccNettoReport = new KSRepLccNettoReport();
ksRepLccNettoReport.setFirmId(registry.getTradingCode());
ksRepLccNettoReport.setTkr(registry.getTradingClearingRegistry());
ksRepLccNettoReport.setCurrencyId(registry.getSecuritySymbol());
ksRepLccNettoReport.setDate(now);
RegistryStatus status = IEnumKey.getEnumByKey(RegistryStatus.class, registry.getRegistryStatus());
RegistryDesignation designation = IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation());
BigDecimal debit = BigDecimal.ZERO;
BigDecimal credit = BigDecimal.ZERO;
if (dataType == DataTypes.FX_OBLIG) {
if (status == RegistryStatus.PROC || status == RegistryStatus.MNG) {
if (designation == RegistryDesignation.O)
debit = registry.getBalance() != null ? registry.getBalance() : BigDecimal.ZERO;
if (designation == RegistryDesignation.T)
credit = registry.getBalance() != null ? registry.getBalance() : BigDecimal.ZERO;
}
} else if (dataType == DataTypes.PR_NETTOSUM) {
if (status == RegistryStatus.CLRD) {
if (designation == RegistryDesignation.O)
debit = registry.getBalance() != null ? registry.getBalance() : BigDecimal.ZERO;
if (designation == RegistryDesignation.T)
credit = registry.getBalance() != null ? registry.getBalance() : BigDecimal.ZERO;
}
} else if (dataType == DataTypes.FX_DEBT) {
if (designation == RegistryDesignation.A) {
if (registry.getBalance() != null && registry.getBalance().compareTo(BigDecimal.ZERO) < 0)
debit = registry.getBalance();
}
}
ksRepLccNettoReport.setDataType(dataType.value);
ksRepLccNettoReport.setDebit(debit);
ksRepLccNettoReport.setCredit(credit);
ksRepLccNettoReport.setNettoSum(credit.subtract(debit));
rows.add(ksRepLccNettoReport);
}
}
}
private enum DataTypes {
FX_OBLIG("FX_OBLIG"),
PR_NETTOSUM("PR_NETTOSUM"),
FX_DEBT("FX_DEBT")
;
private final String value;
DataTypes(String value) {
this.value = value;
}
}
}

View file

@ -0,0 +1,281 @@
package ru.spcex.clearing.reports.builders.ks;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.springframework.stereotype.Component;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.execution.ExecutionCurrency;
import ru.clearing.classes.statics.data.misc.Session;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.security.CurrencyPairSecurity;
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.reports.builders.CSVReportBuilder;
import ru.spcex.clearing.reports.builders.EmptyParams;
import ru.spcex.clearing.reports.builders.bean.KSRepLccTradesReport;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ReportBuilderType;
import ru.spcex.platform.enumeration.ReportKeys;
import ru.spcex.platform.enumeration.Side;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.IEnumKey;
@Component
public class KSRepLccTradesReportBuilder extends CSVReportBuilder<EmptyParams, KSRepLccTradesReport> {
private final Imdg<Session> sessionImdg;
private final Imdg<Company> companyImdg;
private final Imdg<Account> accountImdg;
private final Imdg<ExecutionCurrency> executionCurrencyImdg;
private final Imdg<CurrencyPairDictionary> currencyPairDictionaryImdg;
private final Imdg<CurrencyPairSecurity> currencyPairSecurityImdg;
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private List<KSRepLccTradesReport> rows = null;
public KSRepLccTradesReportBuilder(ImdgProvider imdgProvider) {
sessionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Session, Session.class);
companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
executionCurrencyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionCurrency, ExecutionCurrency.class);
currencyPairDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairDictionary, CurrencyPairDictionary.class);
currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class);
tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
}
@Override
protected List<KSRepLccTradesReport> getRows() {
return rows;
}
@Override
public ReportBuilderType getReportType() {
return ReportBuilderType.KS_REP_LCC_TRADES;
}
@Override
public ReportKeys getReportKey() {
return ReportKeys.KS_REP_LCC_TRADES_REPORT;
}
@Override
public Class<EmptyParams> getParamsClass() {
return EmptyParams.class;
}
@Override
public Class<KSRepLccTradesReport> getReportClass() {
return KSRepLccTradesReport.class;
}
@Override
protected void collect(EmptyParams params) {
LocalDate now = LocalDate.now();
ImdgPredicateBuilder pb = executionCurrencyImdg.predicateBuilder();
Collection<ExecutionCurrency> executions = executionCurrencyImdg.getCollectionObjectsByPredicate(
pb.or(
pb.equals("tradingDate", now),
pb.equals("settlementDate", now)
)
);
rows = new ArrayList<>(executions.size());
for (ExecutionCurrency execution : executions) {
try {
KSRepLccTradesReport ksRepLccTradesReport = new KSRepLccTradesReport();
if (execution.getPartyTradingClearingRegistryId() == null) {
log.warn("For execution id = {} field trading_clearing_registry is empty, skipped", execution.getId());
continue;
}
TradingClearingRegistry tkr = tradingClearingRegistryImdg.getSingleObjectByID(execution.getTradingClearingRegistryId());
if (tkr == null) {
log.warn(
"For execution id = {} not found trading clearing registry for " +
"execution.trading_clearing_registry_id = {}, execution was skipped",
execution.getId(),
execution.getTradingClearingRegistryId()
);
continue;
}
if (tkr.getCode() != null) {
ksRepLccTradesReport.setTkr(tkr.getCode());
} else {
log.warn(
"trading_clearing_registry.code is empty for execution id {} (execution.trading_clearing_registry_id = {}), skipped",
execution.getId(),
execution.getPartyTradingClearingRegistryId()
);
}
if (execution.getSessionId() != null) {
Session session = sessionImdg.getSingleObjectByID(execution.getSessionId());
ksRepLccTradesReport.setSessionId(execution.getSessionId());
if (session != null && session.getCreated() != null) {
ksRepLccTradesReport.setSessionDate(LocalDateTime.ofInstant(session.getCreated(), getReportZoneId()));
} else {
log.warn(
"Can't find session (or session.updated_at is empty) for execution.session_id = {}, execution id = {} skipped",
execution.getSessionId(),
execution.getId()
);
continue;
}
} else {
log.warn("For execution id = {} session_id is empty, skipped", execution.getId());
continue;
}
if (execution.getExchangeExecutionId() == null) {
log.warn("For execution id = {} exchange_execution_id is empty, skipped", execution.getId());
continue;
}
ksRepLccTradesReport.setTradeNum(execution.getExchangeExecutionId());
if (execution.getSecuritySymbol() == null) {
log.warn("For execution id = {} security_symbol is empty, skipped", execution.getId());
continue;
}
ksRepLccTradesReport.setSecCode(execution.getSecuritySymbol());
if (execution.getCompanyId() != null) {
Company company = companyImdg.getSingleObjectByID(execution.getCompanyId());
if (company != null) {
ksRepLccTradesReport.setFirmId(company.getTradingCode());
} else {
log.warn(
"Can't find company for execution.company_id = {}, execution id = {}, skipped",
execution.getCompanyId(),
execution.getId()
);
continue;
}
} else {
log.warn("For execution id = {} company_id is empty, skipped", execution.getId());
continue;
}
Account account = accountImdg.getSingleObjectByID(tkr.getMoneyAccountId());
if (account != null) {
AccountType accountType = IEnumKey.getEnumByKey(AccountType.class, account.getAccountType());
if (accountType == AccountType.Info) {
pb = accountImdg.predicateBuilder();
ImdgPredicate finalPredicate = pb.and(
pb.equals("accountType", AccountType.Anlt.getKey()),
pb.equals("companyId", 5L)
);
if (execution.getSecuritySymbol() != null)
finalPredicate = pb.and(finalPredicate, pb.equals("currency", execution.getSecuritySymbol()));
account = accountImdg.getFirstObjectByPredicate(finalPredicate);
}
if (account != null) {
ksRepLccTradesReport.setAccount(account.getAccount());
} else {
log.warn(
"For trading_clearing_registry.money_account_id = {} account with company_id = 5 not found, skipped",
tkr.getMoneyAccountId()
);
continue;
}
} else {
log.warn(
"For trading_clearing_registry.money_account_id = {} account not found, execution id = {}, skipped",
tkr.getMoneyAccountId(),
execution.getId()
);
continue;
}
if (execution.getMarket() == null) {
log.warn("For execution id = {} market is empty, skipped", execution.getId());
continue;
}
ksRepLccTradesReport.setClassCode(execution.getMarket());
if (execution.getExchangeExecutionTime() != null) {
ksRepLccTradesReport.setTradeDate(
LocalDateTime.ofInstant(execution.getExchangeExecutionTime(), getReportZoneId())
);
} else {
log.warn("For execution id = {} field exchange_execution_time is empty, skipped", execution.getId());
continue;
}
ksRepLccTradesReport.setTradeGroup("T");
if (Arrays.asList(Side.SELL.getKey(), "S", "SELL").contains(execution.getSide())) {
ksRepLccTradesReport.setBuySell("S");
} else if (Arrays.asList(Side.BUY.getKey(), "B", "BUY").contains(execution.getSide())) {
ksRepLccTradesReport.setBuySell("B");
} else {
log.warn(
"For execution id = {} unknown execution.side ({}) value, skipped",
execution.getId(),
execution.getSide()
);
continue;
}
if (execution.getSecurityId() != null) {
pb = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairSecurity currencyPairSecurity = currencyPairSecurityImdg.getFirstObjectByPredicate(
pb.equals("securityId", execution.getSecurityId())
);
if (currencyPairSecurity != null) {
if (currencyPairSecurity.getCurrencyPairId() != null) {
CurrencyPairDictionary currencyPairDictionary = currencyPairDictionaryImdg.getSingleObjectByID(
currencyPairSecurity.getCurrencyPairId()
);
if (currencyPairDictionary != null) {
ksRepLccTradesReport.setLotCurrency(currencyPairDictionary.getBaseCurrency());
ksRepLccTradesReport.setCoCurrency(currencyPairDictionary.getQuoteCurrency());
} else {
log.warn(
"For currency_pair_id = {} not found currency_pair_dictionary, execution id = {}, skipped",
currencyPairSecurity.getCurrencyPairId(),
execution.getId()
);
continue;
}
} else {
log.warn(
"For currency pair security (id = {}) empty field currency_pair_id, execution id = {}, skipped",
currencyPairSecurity.getId(),
execution.getId()
);
continue;
}
} else {
log.warn(
"For execution.security_id = {} (execution.id = {}) currency_pair_security not found, skipped",
execution.getSecurityId(),
execution.getId()
);
continue;
}
} else {
log.warn("For execution id = {} field security_id is empty, skipped", execution.getId());
continue;
}
if (execution.getSettlementDate() == null) {
log.warn("For execution id = {} empty settlement_date, skipped", execution.getId());
continue;
}
ksRepLccTradesReport.setSettleDate(execution.getSettlementDate());
rows.add(ksRepLccTradesReport);
} catch (Exception e) {
log.error("Can't create report row for execution (id = %d), skipped".formatted(execution.getId()), e);
}
}
}
}

View file

@ -1,19 +1,32 @@
package ru.spcex.clearing.reports.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.reports.builders.CSVReportBuilder;
import ru.spcex.clearing.reports.builders.EmptyParams;
import ru.spcex.clearing.reports.builders.SessionIdParam;
import ru.spcex.clearing.reports.builders.bp.*;
import ru.spcex.clearing.reports.builders.ks.*;
import ru.spcex.clearing.reports.builders.bp.ExecutedDealReportBuilder_INFTYPE_1;
import ru.spcex.clearing.reports.builders.bp.ExecutedDealReportBuilder_INFTYPE_2;
import ru.spcex.clearing.reports.builders.bp.ExecutedDealReportBuilder_INFTYPE_3;
import ru.spcex.clearing.reports.builders.bp.ExecutedDealReportBuilder_INFTYPE_4;
import ru.spcex.clearing.reports.builders.bp.UnfulfilledDealReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSCommissionTradesReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepCashNettoReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepCashRegisterSumsReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepCashRegistersReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepDepoNettoReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepDepoRegisterQuantitiesReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepDepoRegistersReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepLccNettoReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepLccTradesReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSRepTradesReportBuilder;
import ru.spcex.clearing.reports.builders.ks.KSSessionListReportBuilder;
import ru.spcex.platform.enumeration.ReportBuilderType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
@ComponentScan(basePackages = "ru.spcex.clearing.reports.builders")
public class ReportBuildersConfig {
@ -25,7 +38,9 @@ public class ReportBuildersConfig {
KSRepDepoRegisterQuantitiesReportBuilder ksRepDepoRegisterQuantitiesReportBuilder,
KSRepTradesReportBuilder ksRepTradesReportBuilder,
KSSessionListReportBuilder ksSessionListReportBuilder,
KSCommissionTradesReportBuilder ksCommissionTradesReportBuilder
KSCommissionTradesReportBuilder ksCommissionTradesReportBuilder,
KSRepLccTradesReportBuilder ksRepLccTradesReportBuilder,
KSRepLccNettoReportBuilder ksRepLccNettoReportBuilder
) {
Map<ReportBuilderType, List<CSVReportBuilder<EmptyParams, ?>>> resultMap = new HashMap<>();
resultMap.put(ReportBuilderType.KS_REP_CASH_REGISTERS, List.of(ksRepCashRegistersReportBuilder));
@ -35,6 +50,8 @@ public class ReportBuildersConfig {
resultMap.put(ReportBuilderType.KS_REP_TRADES, List.of(ksRepTradesReportBuilder));
resultMap.put(ReportBuilderType.KS_SESSION_LIST, List.of(ksSessionListReportBuilder));
resultMap.put(ReportBuilderType.KS_COMMISSION_TRADES, List.of(ksCommissionTradesReportBuilder));
resultMap.put(ReportBuilderType.KS_REP_LCC_TRADES, List.of(ksRepLccTradesReportBuilder));
resultMap.put(ReportBuilderType.KS_REP_LCC_NETTO, List.of(ksRepLccNettoReportBuilder));
return resultMap;
}
@ -134,4 +151,15 @@ public class ReportBuildersConfig {
return resultMap;
}
@Bean("reportBuildersForGREC")
public Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGRET(
KSRepLccTradesReportBuilder ksRepLccTradesReportBuilder,
KSRepLccNettoReportBuilder ksRepLccNettoReportBuilder
) {
Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> resultMap = new HashMap<>();
resultMap.put(ReportBuilderType.KS_REP_LCC_TRADES, List.of(ksRepLccTradesReportBuilder));
resultMap.put(ReportBuilderType.KS_REP_LCC_NETTO, List.of(ksRepLccNettoReportBuilder));
return resultMap;
}
}

View file

@ -1,6 +1,10 @@
package ru.spcex.clearing.reports.config.validation;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.company.Company;
@ -22,11 +26,6 @@ import ru.spcex.platform.utils.enumeration.IMessageResolver;
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.Function;
@Configuration
public class ValidationConfig {
@ -63,7 +62,9 @@ public class ValidationConfig {
ReportBuilderType.KS_REP_TRADES,
ReportBuilderType.KS_REP_FIRM_DETAILS,
ReportBuilderType.KS_SESSION_LIST,
ReportBuilderType.KS_COMMISSION_TRADES
ReportBuilderType.KS_COMMISSION_TRADES,
ReportBuilderType.KS_REP_LCC_TRADES,
ReportBuilderType.KS_REP_LCC_NETTO,
},
ReportError.WrongFieldValue,
ReportError.RequiredFieldEmpty)
@ -154,6 +155,24 @@ public class ValidationConfig {
};
}
// todo оставил бин валидатора на будущее, если в дальнейшем придется проверять запрос. в текущей версии, по факту,
// запрос не проверяется: в случае если sessionId не указан отчеты не строятся
@Bean("reportRequestGRECValidator")
public Function<LauncherCommandRequest, IValidator> reportRequestGRECValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return launcherCommandRequest -> {
ImdgValidationContext<LauncherCommandRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(launcherCommandRequest);
return new ValidatorImpl<>(context,
FieldRequiredRule.instance(
"sessionId",
LauncherCommandRequest::getSessionId,
ReportError.RequiredFieldEmpty,
false)
);
};
}
}

View file

@ -24,7 +24,6 @@ import ru.spcex.clearing.platform.messaging.domain.cud.gateway.SendReportRequest
import ru.spcex.clearing.platform.messaging.domain.cud.reports.ReportRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.reports.ReportRequestWithSessionId;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.QueueConsumerV2;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
@ -55,12 +54,14 @@ public class ReportService extends QueueConsumerV2 implements InitializingBean {
private final Function<LauncherCommandRequest, IValidator> reportRequestGREPValidator;
private final Function<LauncherCommandRequest, IValidator> reportRequestGRETValidator;
private final Function<LauncherCommandRequest, IValidator> reportRequestGREFValidator;
private final Function<LauncherCommandRequest, IValidator> reportRequestGRECValidator;
private final Map<ReportBuilderType, List<CSVReportBuilder<EmptyParams, ?>>> reportBuildersWithoutParams;
private final Map<ReportBuilderType, List<CSVReportBuilder<SessionIdParam, ?>>> reportBuildersWithSessionIdParam;
private final Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGREP;
private final Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGREF;
private final Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGRET;
private final Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGREC;
private final Imdg<Session> sessionImdg;
@ -85,6 +86,8 @@ public class ReportService extends QueueConsumerV2 implements InitializingBean {
Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGREF,
@Qualifier("reportBuildersForGRET")
Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGRET,
@Qualifier("reportBuildersForGREC")
Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> reportBuildersForGREC,
@Qualifier("reportRequestValidator")
Function<ReportRequest, IValidator> reportRequestValidator,
@ -97,6 +100,8 @@ public class ReportService extends QueueConsumerV2 implements InitializingBean {
Function<LauncherCommandRequest, IValidator> reportRequestGRETValidator,
@Qualifier("reportRequestGREFValidator")
Function<LauncherCommandRequest, IValidator> reportRequestGREFValidator,
@Qualifier("reportRequestGREFValidator")
Function<LauncherCommandRequest, IValidator> reportRequestGRECValidator,
ImdgProvider imdgProvider,
SFTPReportsConfig.ReportsGateway reportsSftpGateway
@ -111,9 +116,11 @@ public class ReportService extends QueueConsumerV2 implements InitializingBean {
this.reportRequestGREPValidator = reportRequestGREPValidator;
this.reportRequestGRETValidator = reportRequestGRETValidator;
this.reportRequestGREFValidator = reportRequestGREFValidator;
this.reportRequestGRECValidator = reportRequestGRECValidator;
this.reportBuildersForGREP = reportBuildersForGREP;
this.reportBuildersForGREF = reportBuildersForGREF;
this.reportBuildersForGRET = reportBuildersForGRET;
this.reportBuildersForGREC = reportBuildersForGREC;
this.reportsSftpGateway = reportsSftpGateway;
this.sessionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Session, Session.class);
this.outFolder = new File(reportsServiceSettings.getReportsStore().getLocalTempDir());
@ -144,6 +151,9 @@ public class ReportService extends QueueConsumerV2 implements InitializingBean {
callback(LauncherCommandRequest.class)
.setFunction(this::createReportForGREF)
.forDestination(Task.createDealsReport_GREF.topic(), callbacks::put);
callback(LauncherCommandRequest.class)
.setFunction(this::createReportForGREC)
.forDestination(Task.createReport_GREC.topic(), callbacks::put);
init();
}
@ -314,6 +324,24 @@ public class ReportService extends QueueConsumerV2 implements InitializingBean {
return null;
}
public RequestInfoUpdate createReportForGREC(BaseRequest<LauncherCommandRequest> userRequest) {
log.debug("GREC task received");
try {
RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, reportRequestGRECValidator);
if (requestInfoUpdate != null) return null;
logUnknownProperties(userRequest);
Map<File, ReportInfo> outFiles = createReportsForTask(List.of(), reportBuildersForGREC.values());
sendReportsToGateway(List.of(), outFiles, ReportType.REPORT_KS_FINAL.getKey());
sendFilesToSftp(outFiles.keySet());
} catch (Exception e) {
log.error("Unexpected exception", e);
}
return null;
}
private Map<File, ReportInfo> createReportsForTask(List<Long> sessionIds, Collection<List<CSVReportBuilder<?, ?>>> buildersForTask) {
Map<File, ReportInfo> outFiles = new HashMap<>();
int cntErrors = 0;

View file

@ -46,6 +46,7 @@ import ru.clearing.classes.statics.data.account.AccountSymbols;
import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.execution.ExecutionCurrency;
import ru.clearing.classes.statics.data.execution.ExecutionDeposit;
import ru.clearing.classes.statics.data.execution.ExecutionFond;
import ru.clearing.classes.statics.data.instrument.issue.EquitySecurity;
@ -55,7 +56,9 @@ import ru.clearing.classes.statics.data.misc.Session;
import ru.clearing.classes.statics.data.profile.ProfileDocument;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.security.CurrencyPairSecurity;
import ru.clearing.classes.statics.data.statement.Statement;
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
import ru.clearing.platform.dictionary.RegistryCodeDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.Consts;
@ -116,6 +119,7 @@ public class ReportServiceTest_KS {
private Imdg<RegistryCodeDictionary> registryCodeDictionaryImdg;
private Imdg<ExecutionDeposit> executionDepositImdg;
private Imdg<ExecutionFond> executionFondImdg;
private Imdg<ExecutionCurrency> executionCurrencyImdg;
private Imdg<Session> sessionImdg;
private Imdg<CompanySymbols> companySymbolsImdg;
private Imdg<ProfileDocument> profileDocumentImdg;
@ -124,6 +128,8 @@ public class ReportServiceTest_KS {
private Imdg<STrades> sTradesImdg;
private Imdg<AccountSymbols> accountSymbolsImdg;
private Imdg<ClearingMemberCategory> clearingMemberCategoryImdg;
private Imdg<CurrencyPairSecurity> currencyPairSecurityImdg;
private Imdg<CurrencyPairDictionary> currencyPairDictionaryImdg;
private Long COMPANY_ID;
@Autowired
@ -1275,6 +1281,273 @@ public class ReportServiceTest_KS {
sessionImdg.delete(session);
}
@Test
@Order(12)
public void createReportTest_KSRepLccNettoReport() throws IOException, CsvValidationException {
clearTestDir();
Long SESSION_ID_1 = 32121L;
Long SESSION_ID_2 = 32125L;
Long CURRENCY_PAIR_ID_1 = 7896L;
Long CURRENCY_PAIR_ID_2 = 7821L;
Long SECURITY_ID_1 = 56465L;
Long SECURITY_ID_2 = 5645L;
Long COMPANY_ID_1 = 3215L;
Long COMPANY_ID_2 = 3216L;
Long TKR_ID_1 = 578439L;
Long TKR_ID_2 = 57842L;
Long MONEY_ACCOUNT_ID_1 = 321312L;
Long MONEY_ACCOUNT_ID_2 = 321311L;
ReportRequest reportRequest = new ReportRequest();
reportRequest.setReportId(ReportBuilderType.KS_REP_LCC_TRADES.getKey());
TradingClearingRegistry tkr_1 = new TradingClearingRegistry();
tkr_1.setId(TKR_ID_1);
tkr_1.setCode("TKR_CODE_1");
tkr_1.setMoneyAccountId(MONEY_ACCOUNT_ID_1);
tradingClearingRegistryImdg.insert(tkr_1);
TradingClearingRegistry tkr_2 = new TradingClearingRegistry();
tkr_2.setId(TKR_ID_2);
tkr_2.setCode("TKR_CODE_2");
tkr_2.setMoneyAccountId(MONEY_ACCOUNT_ID_2);
tradingClearingRegistryImdg.insert(tkr_2);
Session session_1 = new Session();
session_1.setId(SESSION_ID_1);
session_1.setCreated(Instant.now());
Session session_2 = new Session();
session_2.setId(SESSION_ID_2);
session_2.setCreated(Instant.now());
sessionImdg.insert(session_1);
sessionImdg.insert(session_2);
Account account_11 = new Account();
account_11.setId(MONEY_ACCOUNT_ID_1);
account_11.setAccountType("INFO");
Account account_1 = new Account();
account_1.setCurrency("RUR");
account_1.setCompanyId(5L);
account_1.setAccountType("ANLT");
account_1.setAccount("ACCOUNT_1");
Account account_2 = new Account();
account_2.setId(MONEY_ACCOUNT_ID_2);
account_2.setAccountType("CLRN");
account_2.setAccount("ACCOUNT_2");
accountImdg.insert(account_1);
accountImdg.insert(account_11);
accountImdg.insert(account_2);
Company company_1 = new Company();
company_1.setId(COMPANY_ID_1);
company_1.setTradingCode("TRADING_CODE_1");
Company company_2 = new Company();
company_2.setId(COMPANY_ID_2);
company_2.setTradingCode("TRADING_CODE_2");
companyImdg.insert(company_1);
companyImdg.insert(company_2);
CurrencyPairSecurity currencyPairSecurity_1 = new CurrencyPairSecurity();
currencyPairSecurity_1.setSecurityId(SECURITY_ID_1);
currencyPairSecurity_1.setCurrencyPairId(CURRENCY_PAIR_ID_1);
CurrencyPairSecurity currencyPairSecurity_2 = new CurrencyPairSecurity();
currencyPairSecurity_2.setSecurityId(SECURITY_ID_2);
currencyPairSecurity_2.setCurrencyPairId(CURRENCY_PAIR_ID_2);
currencyPairSecurityImdg.insert(currencyPairSecurity_1);
currencyPairSecurityImdg.insert(currencyPairSecurity_2);
CurrencyPairDictionary currencyPairDictionary_1 = new CurrencyPairDictionary();
currencyPairDictionary_1.setId(CURRENCY_PAIR_ID_1);
currencyPairDictionary_1.setBaseCurrency("BASE_CURRENCY_1");
currencyPairDictionary_1.setQuoteCurrency("QUOTE_CURRENCY_1");
CurrencyPairDictionary currencyPairDictionary_2 = new CurrencyPairDictionary();
currencyPairDictionary_2.setId(CURRENCY_PAIR_ID_2);
currencyPairDictionary_2.setBaseCurrency("BASE_CURRENCY_2");
currencyPairDictionary_2.setQuoteCurrency("QUOTE_CURRENCY_2");
currencyPairDictionaryImdg.insert(currencyPairDictionary_1);
currencyPairDictionaryImdg.insert(currencyPairDictionary_2);
ExecutionCurrency executionCurrency_1 = new ExecutionCurrency();
executionCurrency_1.setSessionId(session_1.getId());
executionCurrency_1.setSettlementDate(LocalDate.now());
executionCurrency_1.setTradingDate(LocalDate.now());
executionCurrency_1.setSessionId(SESSION_ID_1);
executionCurrency_1.setExchangeExecutionId(321L);
executionCurrency_1.setSecuritySymbol("RUR");
executionCurrency_1.setTradingClearingRegistryId(TKR_ID_1);
executionCurrency_1.setMarket("MARKET_1");
executionCurrency_1.setExchangeExecutionTime(Instant.now());
executionCurrency_1.setSide("SELL");
executionCurrency_1.setSecurityId(SECURITY_ID_1);
executionCurrency_1.setCompanyId(COMPANY_ID_1);
ExecutionCurrency executionCurrency_2 = new ExecutionCurrency();
executionCurrency_2.setSessionId(session_2.getId());
executionCurrency_2.setSettlementDate(LocalDate.now());
executionCurrency_2.setSessionId(SESSION_ID_2);
executionCurrency_2.setExchangeExecutionId(123L);
executionCurrency_2.setSecuritySymbol("EUR");
executionCurrency_2.setTradingClearingRegistryId(TKR_ID_2);
executionCurrency_2.setMarket("MARKET_2");
executionCurrency_2.setExchangeExecutionTime(Instant.now());
executionCurrency_2.setSide("BUY");
executionCurrency_2.setSecurityId(SECURITY_ID_2);
executionCurrency_2.setCompanyId(COMPANY_ID_2);
executionCurrencyImdg.insert(executionCurrency_1);
executionCurrencyImdg.insert(executionCurrency_2);
String jsonString = TestUtils.getJsonStringForSystem(reportRequest, 0L);
TestUtils.addRecordToKafka((MockConsumer) reportService.getConsumer(),
Consts.CREATE_REPORT,
reportRequestCnt++,
0,
jsonString);
TestUtils.waitingSendAndCheckRecord(0L, producer);
File outFile = outFolder.listFiles()[0];
File expectedFile = new File(getClass().getClassLoader().getResource("expected_reports_csv/ks/KS_REP_LCC_TRADES_expected.csv").getFile());
compareCSVFiles(expectedFile, outFile, Arrays.asList("SESSION_DATE", "TRADE_DATE", "SETTLEDATE"));
accountImdg.delete(account_11);
accountImdg.delete(account_1);
accountImdg.delete(account_2);
companyImdg.delete(company_1);
companyImdg.delete(company_2);
tradingClearingRegistryImdg.delete(tkr_1);
tradingClearingRegistryImdg.delete(tkr_2);
sessionImdg.delete(session_1);
executionCurrencyImdg.delete(executionCurrency_1);
executionCurrencyImdg.delete(executionCurrency_2);
currencyPairSecurityImdg.delete(currencyPairSecurity_1);
currencyPairSecurityImdg.delete(currencyPairSecurity_2);
currencyPairDictionaryImdg.delete(currencyPairDictionary_1);
currencyPairDictionaryImdg.delete(currencyPairDictionary_2);
}
@Test
@Order(13)
public void createReportTest_KSRepLccTradesReport() throws IOException, CsvValidationException {
clearTestDir();
ReportRequest reportRequest = new ReportRequest();
reportRequest.setReportId(ReportBuilderType.KS_REP_LCC_NETTO.getKey());
Registry registry_AMT_1 = new Registry();
registry_AMT_1.setTradingCode("AMT_1_TRADING_CODE");
registry_AMT_1.setTradingClearingRegistry("TKR_AMT_1");
registry_AMT_1.setSecuritySymbol("SEC_SYMBOL_AMT_1");
registry_AMT_1.setSettlementDate(LocalDate.now());
registry_AMT_1.setRegistryCode("AM_T");
registry_AMT_1.setRegistryDesignation(RegistryDesignation.A.getKey());
registry_AMT_1.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
registry_AMT_1.setRegistryUnit(RegistryUnit.T.getKey());
registry_AMT_1.setBalance(BigDecimal.TEN);
Registry registry_AMT_2 = new Registry();
registry_AMT_2.setTradingCode("AMT_2_TRADING_CODE");
registry_AMT_2.setTradingClearingRegistry("TKR_AMT_2");
registry_AMT_2.setSecuritySymbol("SEC_SYMBOL_AMT_2");
registry_AMT_2.setSettlementDate(LocalDate.now());
registry_AMT_2.setRegistryCode("AM_T");
registry_AMT_2.setRegistryDesignation(RegistryDesignation.A.getKey());
registry_AMT_2.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
registry_AMT_2.setRegistryUnit(RegistryUnit.T.getKey());
registry_AMT_1.setBalance(BigDecimal.TEN.negate());
Registry registry_OMT_1 = new Registry();
registry_OMT_1.setTradingCode("OMT_1_TRADING_CODE");
registry_OMT_1.setTradingClearingRegistry("TKR_OMT_1");
registry_OMT_1.setSecuritySymbol("SEC_SYMBOL_OMT_1");
registry_OMT_1.setSettlementDate(LocalDate.now());
registry_OMT_1.setRegistryCode("OM_T");
registry_OMT_1.setRegistryDesignation(RegistryDesignation.O.getKey());
registry_OMT_1.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
registry_OMT_1.setRegistryUnit(RegistryUnit.T.getKey());
registry_OMT_1.setRegistryStatus(RegistryStatus.PROC.getKey());
registry_OMT_1.setBalance(BigDecimal.valueOf(321321));
Registry registry_OMT_2 = new Registry();
registry_OMT_2.setTradingCode("OMT_2_TRADING_CODE");
registry_OMT_2.setTradingClearingRegistry("TKR_OMT_2");
registry_OMT_2.setSecuritySymbol("SEC_SYMBOL_OMT_2");
registry_OMT_2.setSettlementDate(LocalDate.now());
registry_OMT_2.setRegistryCode("OM_T");
registry_OMT_2.setRegistryDesignation(RegistryDesignation.O.getKey());
registry_OMT_2.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
registry_OMT_2.setRegistryUnit(RegistryUnit.T.getKey());
registry_OMT_2.setRegistryStatus(RegistryStatus.CLRD.getKey());
registry_OMT_2.setBalance(BigDecimal.valueOf(547893));
Registry registry_TMT_1 = new Registry();
registry_TMT_1.setTradingCode("TMT_1_TRADING_CODE");
registry_TMT_1.setTradingClearingRegistry("TKR_TMT_1");
registry_TMT_1.setSecuritySymbol("SEC_SYMBOL_TMT_1");
registry_TMT_1.setSettlementDate(LocalDate.now());
registry_TMT_1.setRegistryCode("TM_T");
registry_TMT_1.setRegistryDesignation(RegistryDesignation.T.getKey());
registry_TMT_1.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
registry_TMT_1.setRegistryUnit(RegistryUnit.T.getKey());
registry_TMT_1.setRegistryStatus(RegistryStatus.MNG.getKey());
registry_TMT_1.setBalance(BigDecimal.valueOf(5783949));
Registry registry_TMT_2 = new Registry();
registry_TMT_2.setTradingCode("TMT_2_TRADING_CODE");
registry_TMT_2.setTradingClearingRegistry("TKR_TMT_2");
registry_TMT_2.setSecuritySymbol("SEC_SYMBOL_TMT_2");
registry_TMT_2.setSettlementDate(LocalDate.now());
registry_TMT_2.setRegistryCode("TM_T");
registry_TMT_2.setRegistryDesignation(RegistryDesignation.T.getKey());
registry_TMT_2.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
registry_TMT_2.setRegistryUnit(RegistryUnit.T.getKey());
registry_TMT_2.setRegistryStatus(RegistryStatus.CLRD.getKey());
registry_TMT_2.setBalance(BigDecimal.valueOf(434213));
registryImdg.insert(registry_AMT_1);
registryImdg.insert(registry_AMT_2);
registryImdg.insert(registry_TMT_1);
registryImdg.insert(registry_TMT_2);
registryImdg.insert(registry_OMT_1);
registryImdg.insert(registry_OMT_2);
String jsonString = TestUtils.getJsonStringForSystem(reportRequest, 0L);
TestUtils.addRecordToKafka((MockConsumer) reportService.getConsumer(),
Consts.CREATE_REPORT,
reportRequestCnt++,
0,
jsonString);
TestUtils.waitingSendAndCheckRecord(0L, producer);
File outFile = outFolder.listFiles()[0];
File expectedFile = new File(getClass().getClassLoader().getResource("expected_reports_csv/ks/KS_REP_LCC_NETTO_expected.csv").getFile());
compareCSVFiles(expectedFile, outFile, Arrays.asList("DATE"));
registryImdg.delete(registry_AMT_1);
registryImdg.delete(registry_TMT_1);
registryImdg.delete(registry_OMT_1);
registryImdg.delete(registry_AMT_2);
registryImdg.delete(registry_TMT_2);
registryImdg.delete(registry_OMT_2);
}
private void compareCSVFiles(File expectedFile, File actualFile, List<String> columnsForSkip) throws IOException, CsvValidationException {
if (columnsForSkip == null) columnsForSkip = Collections.emptyList();
@ -1373,6 +1646,7 @@ public class ReportServiceTest_KS {
executionDepositImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionDeposit, ExecutionDeposit.class);
executionFondImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionFond, ExecutionFond.class);
executionCurrencyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionCurrency, ExecutionCurrency.class);
sessionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Session, Session.class);
companySymbolsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
profileDocumentImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class);
@ -1384,6 +1658,8 @@ public class ReportServiceTest_KS {
sTradesImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_STrades, STrades.class);
accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
clearingMemberCategoryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class);
currencyPairDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairDictionary, CurrencyPairDictionary.class);
}
private void clearTestDir() throws IOException {

View file

@ -0,0 +1,19 @@
"FIRM_ID","TKR","CURRENCYID","DATE","NETTO_SUM","DATA_TYPE","DEBIT","CREDIT"
"AMT_1_TRADING_CODE","TKR_AMT_1","SEC_SYMBOL_AMT_1","2024-10-02","0","FX_OBLIG","0.00","0.00"
"AMT_1_TRADING_CODE","TKR_AMT_1","SEC_SYMBOL_AMT_1","2024-10-02","0","PR_NETTOSUM","0.00","0.00"
"AMT_1_TRADING_CODE","TKR_AMT_1","SEC_SYMBOL_AMT_1","2024-10-02","10","FX_DEBT","-10.00","0.00"
"TMT_2_TRADING_CODE","TKR_TMT_2","SEC_SYMBOL_TMT_2","2024-10-02","0","FX_OBLIG","0.00","0.00"
"TMT_2_TRADING_CODE","TKR_TMT_2","SEC_SYMBOL_TMT_2","2024-10-02","434213","PR_NETTOSUM","0.00","434213.00"
"TMT_2_TRADING_CODE","TKR_TMT_2","SEC_SYMBOL_TMT_2","2024-10-02","0","FX_DEBT","0.00","0.00"
"TMT_1_TRADING_CODE","TKR_TMT_1","SEC_SYMBOL_TMT_1","2024-10-02","5783949","FX_OBLIG","0.00","5783949.00"
"TMT_1_TRADING_CODE","TKR_TMT_1","SEC_SYMBOL_TMT_1","2024-10-02","0","PR_NETTOSUM","0.00","0.00"
"TMT_1_TRADING_CODE","TKR_TMT_1","SEC_SYMBOL_TMT_1","2024-10-02","0","FX_DEBT","0.00","0.00"
"OMT_1_TRADING_CODE","TKR_OMT_1","SEC_SYMBOL_OMT_1","2024-10-02","-321321","FX_OBLIG","321321.00","0.00"
"OMT_1_TRADING_CODE","TKR_OMT_1","SEC_SYMBOL_OMT_1","2024-10-02","0","PR_NETTOSUM","0.00","0.00"
"OMT_1_TRADING_CODE","TKR_OMT_1","SEC_SYMBOL_OMT_1","2024-10-02","0","FX_DEBT","0.00","0.00"
"AMT_2_TRADING_CODE","TKR_AMT_2","SEC_SYMBOL_AMT_2","2024-10-02","0","FX_OBLIG","0.00","0.00"
"AMT_2_TRADING_CODE","TKR_AMT_2","SEC_SYMBOL_AMT_2","2024-10-02","0","PR_NETTOSUM","0.00","0.00"
"AMT_2_TRADING_CODE","TKR_AMT_2","SEC_SYMBOL_AMT_2","2024-10-02","0","FX_DEBT","0.00","0.00"
"OMT_2_TRADING_CODE","TKR_OMT_2","SEC_SYMBOL_OMT_2","2024-10-02","0","FX_OBLIG","0.00","0.00"
"OMT_2_TRADING_CODE","TKR_OMT_2","SEC_SYMBOL_OMT_2","2024-10-02","-547893","PR_NETTOSUM","547893.00","0.00"
"OMT_2_TRADING_CODE","TKR_OMT_2","SEC_SYMBOL_OMT_2","2024-10-02","0","FX_DEBT","0.00","0.00"
1 FIRM_ID TKR CURRENCYID DATE NETTO_SUM DATA_TYPE DEBIT CREDIT
2 AMT_1_TRADING_CODE TKR_AMT_1 SEC_SYMBOL_AMT_1 2024-10-02 0 FX_OBLIG 0.00 0.00
3 AMT_1_TRADING_CODE TKR_AMT_1 SEC_SYMBOL_AMT_1 2024-10-02 0 PR_NETTOSUM 0.00 0.00
4 AMT_1_TRADING_CODE TKR_AMT_1 SEC_SYMBOL_AMT_1 2024-10-02 10 FX_DEBT -10.00 0.00
5 TMT_2_TRADING_CODE TKR_TMT_2 SEC_SYMBOL_TMT_2 2024-10-02 0 FX_OBLIG 0.00 0.00
6 TMT_2_TRADING_CODE TKR_TMT_2 SEC_SYMBOL_TMT_2 2024-10-02 434213 PR_NETTOSUM 0.00 434213.00
7 TMT_2_TRADING_CODE TKR_TMT_2 SEC_SYMBOL_TMT_2 2024-10-02 0 FX_DEBT 0.00 0.00
8 TMT_1_TRADING_CODE TKR_TMT_1 SEC_SYMBOL_TMT_1 2024-10-02 5783949 FX_OBLIG 0.00 5783949.00
9 TMT_1_TRADING_CODE TKR_TMT_1 SEC_SYMBOL_TMT_1 2024-10-02 0 PR_NETTOSUM 0.00 0.00
10 TMT_1_TRADING_CODE TKR_TMT_1 SEC_SYMBOL_TMT_1 2024-10-02 0 FX_DEBT 0.00 0.00
11 OMT_1_TRADING_CODE TKR_OMT_1 SEC_SYMBOL_OMT_1 2024-10-02 -321321 FX_OBLIG 321321.00 0.00
12 OMT_1_TRADING_CODE TKR_OMT_1 SEC_SYMBOL_OMT_1 2024-10-02 0 PR_NETTOSUM 0.00 0.00
13 OMT_1_TRADING_CODE TKR_OMT_1 SEC_SYMBOL_OMT_1 2024-10-02 0 FX_DEBT 0.00 0.00
14 AMT_2_TRADING_CODE TKR_AMT_2 SEC_SYMBOL_AMT_2 2024-10-02 0 FX_OBLIG 0.00 0.00
15 AMT_2_TRADING_CODE TKR_AMT_2 SEC_SYMBOL_AMT_2 2024-10-02 0 PR_NETTOSUM 0.00 0.00
16 AMT_2_TRADING_CODE TKR_AMT_2 SEC_SYMBOL_AMT_2 2024-10-02 0 FX_DEBT 0.00 0.00
17 OMT_2_TRADING_CODE TKR_OMT_2 SEC_SYMBOL_OMT_2 2024-10-02 0 FX_OBLIG 0.00 0.00
18 OMT_2_TRADING_CODE TKR_OMT_2 SEC_SYMBOL_OMT_2 2024-10-02 -547893 PR_NETTOSUM 547893.00 0.00
19 OMT_2_TRADING_CODE TKR_OMT_2 SEC_SYMBOL_OMT_2 2024-10-02 0 FX_DEBT 0.00 0.00

View file

@ -0,0 +1,3 @@
"SESSION_ID","SESSION_DATE","TRADE_NUM","SECCODE","FIRM_ID","TKR","ACCOUNT","CLASS_CODE","TRADE_DATE","TRADE_GROUP","BUY_SELL","LOT_CURRENCY","CO_CURRENCY","SETTLEDATE"
"32121","02.10.2024T15:54:33","321","RUR","TRADING_CODE_1","TKR_CODE_1","ACCOUNT_1","MARKET_1","02.10.2024T15:54:33","T","S","BASE_CURRENCY_1","QUOTE_CURRENCY_1","2024-10-02"
"32125","02.10.2024T15:54:33","123","EUR","TRADING_CODE_2","TKR_CODE_2","ACCOUNT_2","MARKET_2","02.10.2024T15:54:33","T","B","BASE_CURRENCY_2","QUOTE_CURRENCY_2","2024-10-02"
1 SESSION_ID SESSION_DATE TRADE_NUM SECCODE FIRM_ID TKR ACCOUNT CLASS_CODE TRADE_DATE TRADE_GROUP BUY_SELL LOT_CURRENCY CO_CURRENCY SETTLEDATE
2 32121 02.10.2024T15:54:33 321 RUR TRADING_CODE_1 TKR_CODE_1 ACCOUNT_1 MARKET_1 02.10.2024T15:54:33 T S BASE_CURRENCY_1 QUOTE_CURRENCY_1 2024-10-02
3 32125 02.10.2024T15:54:33 123 EUR TRADING_CODE_2 TKR_CODE_2 ACCOUNT_2 MARKET_2 02.10.2024T15:54:33 T B BASE_CURRENCY_2 QUOTE_CURRENCY_2 2024-10-02

View file

@ -4,6 +4,8 @@ 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.clearing.classes.statics.data.security.Rates;
import ru.clearing.classes.statics.data.security.RiskParameter;
import ru.clearing.platform.dictionary.CountryCodeDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.securities.errors.SecuritiesError;
@ -29,6 +31,8 @@ public class ValidationConfig {
BiConsumer<String, Class<? extends SpcexObjectBase>> addImdg = (s, aClass) -> imdg.put(s, imdgProvider.getImdg(s, aClass));
addImdg.accept(IMDGDistributedNames.Map_FixedIncomeCashFlow, CountryCodeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_Rates, Rates.class);
addImdg.accept(IMDGDistributedNames.Map_RiskParameter, RiskParameter.class);
return imdg;
}

View file

@ -30,9 +30,9 @@ public class RatesValidationConfig {
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Rates);
return new ValidatorImpl<>(context,
FieldRequiredRule.instance("currencyPairUd", RatesNewRequest::getCurrencyId, SecuritiesError.RequiredFieldIsEmpty),
FieldRequiredRule.instance("currencyPairId", RatesNewRequest::getCurrencyId, SecuritiesError.RequiredFieldIsEmpty),
FieldRequiredRule.instance("value", RatesNewRequest::getValue, SecuritiesError.RequiredFieldIsEmpty),
FieldRequiredRule.instance("settlementType", RatesNewRequest::getValueDate, SecuritiesError.RequiredFieldIsEmpty),
FieldRequiredRule.instance("valueDate", RatesNewRequest::getValueDate, SecuritiesError.RequiredFieldIsEmpty),
RatesValidationRule.CHECK_ON_EXIST
);
};

View file

@ -5,6 +5,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.security.Rates;
import ru.clearing.platform.dictionary.CurrencyCodeDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.security.RatesNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.security.RatesUpdateRequest;
@ -19,11 +20,13 @@ public class RatesFacade implements IClearingFacade {
private final ImdgId idGenerator;
private final ImdgProvider imdgProvider;
private final Imdg<Rates> ratesImdg;
private final Imdg<CurrencyCodeDictionary> currencyCodeDictionaryImdg;
public RatesFacade(ImdgProvider imdgProvider) {
this.idGenerator = imdgProvider.getImdgIdGenerator();
this.imdgProvider = imdgProvider;
this.ratesImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Rates, Rates.class);
this.currencyCodeDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyCodeDictionary, CurrencyCodeDictionary.class);
}
/**
@ -33,7 +36,9 @@ public class RatesFacade implements IClearingFacade {
log.trace("Start process creating new rates");
Rates rates = new Rates();
CurrencyCodeDictionary currencyCodeDictionary = currencyCodeDictionaryImdg.getSingleObjectByID(request.getCurrencyId());
rates.setCurrencyId(request.getCurrencyId());
rates.setCurrency(currencyCodeDictionary.getCode());
rates.setValue(request.getValue());
rates.setValueDate(request.getValueDate());
rates.setWorkflowStatus(request.getStatus());

View file

@ -5,6 +5,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.security.RiskParameter;
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.security.RiskParameterNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.security.RiskParameterUpdateRequest;
@ -19,11 +20,13 @@ public class RiskParameterFacade implements IClearingFacade {
private final ImdgId idGenerator;
private final ImdgProvider imdgProvider;
private final Imdg<RiskParameter> riskParameterImdg;
private final Imdg<CurrencyPairDictionary> currencyPairDictionaryImdg;
public RiskParameterFacade(ImdgProvider imdgProvider) {
this.idGenerator = imdgProvider.getImdgIdGenerator();
this.imdgProvider = imdgProvider;
this.riskParameterImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RiskParameter, RiskParameter.class);
this.currencyPairDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairDictionary, CurrencyPairDictionary.class);
}
/**
@ -33,7 +36,9 @@ public class RiskParameterFacade implements IClearingFacade {
log.trace("Start process creating new risk_parameter");
RiskParameter riskParameter = new RiskParameter();
CurrencyPairDictionary currencyPairDictionary = currencyPairDictionaryImdg.getSingleObjectByID(request.getCurrencyPairId());
riskParameter.setCurrencyPairId(request.getCurrencyPairId());
riskParameter.setCurrencyPair(currencyPairDictionary.getCode());
riskParameter.setSettlementType(request.getSettlementType());
riskParameter.setValue(request.getValue());
riskParameter.setWorkflowStatus(request.getStatus());

View file

@ -22,7 +22,7 @@ public enum RatesValidationRule implements IValidationRule<ImdgValidationContext
ImdgPredicateBuilder predicateBuilder = imdgDictionary.predicateBuilder();
Rates rates = imdgDictionary.getFirstObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("currencyPairId", action.getCurrencyId()),
predicateBuilder.equals("currencyId", action.getCurrencyId()),
predicateBuilder.equals("valueDate", action.getValueDate()),
predicateBuilder.equals("workflowStatus", Status.Active.getKey())
)

View file

@ -19,6 +19,8 @@ public enum ReportBuilderType implements IEnumKey {
KS_REP_FIRM_DETAILS("ks_rep_firm_details"),
KS_SESSION_LIST("ks_session_list"),
KS_COMMISSION_TRADES("ks_commission_trades"),
KS_REP_LCC_TRADES("ks_rep_lcc_trades"),
KS_REP_LCC_NETTO("ks_rep_lcc_netto")
;
private final String key;

View file

@ -18,6 +18,8 @@ public enum ReportKeys implements IEnumKey {
KS_REP_FIRM_DETAILS("KS_REP_FIRM_DETAILS"),
KS_SESSION_LIST("KS_SESSION_LIST"),
KS_COMMISSION_TRADES("KS_COMMISSION_TRADES"),
KS_REP_LCC_TRADES_REPORT("KS_REP_LCC_TRADES_REPORT"),
KS_REP_LCC_NETTO_REPORT("KS_REP_LCC_NETTO_REPORT")
;
private final String key;

View file

@ -1,13 +1,19 @@
package ru.spcex.clearing.platform.messaging.domain.cud.security;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.math.BigDecimal;
import java.time.LocalDate;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
public class RatesNewRequest {
@JsonProperty
private BigDecimal value;
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate valueDate;
@JsonProperty