Merge branch 'dev' into dev_xml-test
This commit is contained in:
commit
c6eb287095
43 changed files with 837 additions and 224 deletions
|
|
@ -72,7 +72,7 @@ public class BankAccountValidationConfig {
|
|||
AccountError.DictionaryNotFound,
|
||||
false),
|
||||
ValidateSymbolsRule.notRequired("БИК",
|
||||
BankAccountUpdateRequest::getBankIdentificationCode,
|
||||
BankAccountNewRequest::getBankIdentificationCode,
|
||||
AccountError.BadSymbol),
|
||||
ValidateSymbolsRule.required("Наименование компании",
|
||||
BankAccountNewRequest::getBankName,
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ public class RegistryController extends AbstractQueueController {
|
|||
|
||||
@ApiOperation(value = "Вывод средств с регистра невыясненных активов")
|
||||
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
|
||||
@RequestMapping(value = "/withdrawalFunds", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequestMapping(value = "/withdrawalFunds", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public CudResponse dmauRegistryNew(
|
||||
@ApiParam(value = "Параметры команды в JSON формате.", required = true)
|
||||
|
|
|
|||
|
|
@ -12,9 +12,12 @@ public class RiskParameterNewAction implements IAction<RiskParameterNewRequest>
|
|||
@ApiModelProperty(value = "Курс.", example = "1234")
|
||||
@JsonProperty
|
||||
private BigDecimal value;
|
||||
@ApiModelProperty(value = "Ставка сопряженной валюты.", example = "1234")
|
||||
@ApiModelProperty(value = "Ставка переноса при нехватке рублей.", example = "1234")
|
||||
@JsonProperty
|
||||
private BigDecimal quoteValue;
|
||||
@ApiModelProperty(value = "Ставка переноса при нехватке валюты.", example = "1234")
|
||||
@JsonProperty
|
||||
private BigDecimal penaltyValue;
|
||||
@ApiModelProperty(value = "Код расчёта.", example = "1234")
|
||||
@JsonProperty
|
||||
private String settlementType;
|
||||
|
|
@ -30,6 +33,7 @@ public class RiskParameterNewAction implements IAction<RiskParameterNewRequest>
|
|||
RiskParameterNewRequest request = new RiskParameterNewRequest();
|
||||
request.setValue(this.value);
|
||||
request.setQuoteValue(this.quoteValue);
|
||||
request.setPenaltyValue(this.penaltyValue);
|
||||
request.setSettlementType(this.settlementType);
|
||||
request.setCurrencyPairId(this.currencyPairId);
|
||||
request.setWorkflowStatus(this.workflowStatus);
|
||||
|
|
@ -73,4 +77,8 @@ public class RiskParameterNewAction implements IAction<RiskParameterNewRequest>
|
|||
public void setWorkflowStatus(String workflowStatus) {
|
||||
this.workflowStatus = workflowStatus;
|
||||
}
|
||||
|
||||
public void setPenaltyValue(BigDecimal penaltyValue) {
|
||||
this.penaltyValue = penaltyValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,12 @@ public class RiskParameterUpdateAction implements IAction<RiskParameterUpdateReq
|
|||
@ApiModelProperty(value = "Курс.", example = "1234")
|
||||
@JsonProperty
|
||||
private BigDecimal value;
|
||||
@ApiModelProperty(value = "Ставка сопряженной валюты.", example = "1234")
|
||||
@ApiModelProperty(value = "Ставка переноса при нехватке рублей.", example = "1234")
|
||||
@JsonProperty
|
||||
private BigDecimal quoteValue;
|
||||
@ApiModelProperty(value = "Ставка переноса при нехватке валюты.", example = "1234")
|
||||
@JsonProperty
|
||||
private BigDecimal penaltyValue;
|
||||
@ApiModelProperty(value = "Статус.", example = "1234")
|
||||
@JsonProperty
|
||||
private String workflowStatus;
|
||||
|
|
@ -28,6 +31,7 @@ public class RiskParameterUpdateAction implements IAction<RiskParameterUpdateReq
|
|||
request.setId(this.id);
|
||||
request.setValue(this.value);
|
||||
request.setQuoteValue(this.quoteValue);
|
||||
request.setPenaltyValue(this.penaltyValue);
|
||||
request.setWorkflowStatus(this.workflowStatus);
|
||||
return request;
|
||||
}
|
||||
|
|
@ -61,4 +65,12 @@ public class RiskParameterUpdateAction implements IAction<RiskParameterUpdateReq
|
|||
public void setWorkflowStatus(String workflowStatus) {
|
||||
this.workflowStatus = workflowStatus;
|
||||
}
|
||||
|
||||
public void setQuoteValue(BigDecimal quoteValue) {
|
||||
this.quoteValue = quoteValue;
|
||||
}
|
||||
|
||||
public void setPenaltyValue(BigDecimal penaltyValue) {
|
||||
this.penaltyValue = penaltyValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
{
|
||||
"version": "3.23.295.165",
|
||||
"version": "3.23.295.169",
|
||||
|
||||
"enums": {
|
||||
|
||||
|
|
@ -6389,17 +6389,6 @@
|
|||
|
||||
"name": "Отправка заявок в Торговую систему",
|
||||
|
||||
"fields": []
|
||||
}
|
||||
,
|
||||
{"method":"post",
|
||||
|
||||
"destination": "ORST",
|
||||
|
||||
"group": "Обмен с Торговой системой",
|
||||
|
||||
"name": "Получение статуса заявок из Торговой системы",
|
||||
|
||||
"fields": []
|
||||
}
|
||||
]
|
||||
|
|
@ -11089,9 +11078,13 @@
|
|||
{"code": "value",
|
||||
"name": "Ставка","shortname": "Ставка","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "penaltyValue",
|
||||
"name": "Ставка переноса при нехватке валюты","shortname": "Ставка переноса при нехватке валюты","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "quoteValue",
|
||||
"name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10
|
||||
"name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "workflowStatus",
|
||||
|
|
@ -11103,7 +11096,7 @@
|
|||
|
||||
"name": "Добавление параметров риска",
|
||||
|
||||
"confirmation": "value,quoteValue,settlementType,currencyPairId,workflowStatus",
|
||||
"confirmation": "value,penaltyValue,quoteValue,settlementType,currencyPairId,workflowStatus",
|
||||
|
||||
"class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction",
|
||||
|
||||
|
|
@ -11119,9 +11112,13 @@
|
|||
{"code": "value",
|
||||
"name": "Ставка","shortname": "Ставка","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "penaltyValue",
|
||||
"name": "Ставка переноса при нехватке валюты","shortname": "Ставка переноса при нехватке валюты","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "quoteValue",
|
||||
"name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10
|
||||
"name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "workflowStatus",
|
||||
|
|
@ -11134,7 +11131,7 @@
|
|||
|
||||
"name": "Изменение параметров риска",
|
||||
|
||||
"confirmation": "value,quoteValue,workflowStatus",
|
||||
"confirmation": "value,penaltyValue,quoteValue,workflowStatus",
|
||||
|
||||
"class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterUpdateAction",
|
||||
|
||||
|
|
@ -11146,9 +11143,13 @@
|
|||
{"code": "value",
|
||||
"name": "Ставка","shortname": "Ставка","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "penaltyValue",
|
||||
"name": "Ставка переноса при нехватке валюты","shortname": "Ставка переноса при нехватке валюты","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "quoteValue",
|
||||
"name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10
|
||||
"name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10
|
||||
}
|
||||
,
|
||||
{"code": "workflowStatus",
|
||||
|
|
@ -11743,7 +11744,7 @@
|
|||
}
|
||||
,
|
||||
{"code": "market",
|
||||
"type": 12,"name": "Код режима торгов","shortname": "Режим торгов","visible": true,"searchable": true,"sortable": true,"link": "market","linkCode": "code"
|
||||
"type": 12,"name": "Код режима торгов","shortname": "Режим торгов","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
,
|
||||
{"code": "status",
|
||||
|
|
@ -11831,7 +11832,7 @@
|
|||
}
|
||||
,
|
||||
{"code": "market",
|
||||
"type": 12,"name": "Код режима торгов","shortname": "Режим торгов","link": "market","linkCode": "code","enabled": false,"required": true
|
||||
"type": 12,"name": "Код режима торгов","shortname": "Режим торгов","enabled": false,"required": true
|
||||
}
|
||||
,
|
||||
{"code": "price",
|
||||
|
|
|
|||
|
|
@ -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.23.295.165">
|
||||
<meta version="3.23.295.169">
|
||||
<!-- _xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _xsi:noNamespaceSchemaLocation="file:///E:/d/projects/meta/from/meta.xsd" -->
|
||||
<!--Здесь словари-->
|
||||
<enums>
|
||||
|
|
@ -1478,8 +1478,6 @@
|
|||
</post>
|
||||
<post destination="SDOR" group="Обмен с Торговой системой" name="Отправка заявок в Торговую систему">
|
||||
</post>
|
||||
<post destination="ORST" group="Обмен с Торговой системой" name="Получение статуса заявок из Торговой системы">
|
||||
</post>
|
||||
</actions>
|
||||
</launcher>
|
||||
<session name="Клиринговые сессии" destination="sessions" historyDestination="history" class="ru.clearing.classes.statics.data.misc.Session" logUpdates="true" table="session">
|
||||
|
|
@ -2570,20 +2568,23 @@
|
|||
<currencyPairId name="Идентификатор валютной пары" shortname="Валютная пара" type="1"/>
|
||||
<settlementType name="Код расчета" shortname="Код расчета" type="2" length="4"/>
|
||||
<value name="Ставка" shortname="Ставка" type="10"/>
|
||||
<quoteValue name="Ставка сопряженной валюты" shortname="Ставка сопряженной валюты" type="10"/>
|
||||
<penaltyValue name="Ставка переноса при нехватке валюты" shortname="Ставка переноса при нехватке валюты" type="10"/>
|
||||
<quoteValue name="Ставка переноса при нехватке рублей" shortname="Ставка переноса при нехватке рублей" type="10"/>
|
||||
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
|
||||
<actions>
|
||||
<post name="Добавление параметров риска" confirmation="value,quoteValue,settlementType,currencyPairId,workflowStatus" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction">
|
||||
<post name="Добавление параметров риска" confirmation="value,penaltyValue,quoteValue,settlementType,currencyPairId,workflowStatus" 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"/>
|
||||
<quoteValue name="Ставка сопряженной валюты" shortname="Ставка сопряженной валюты" type="10"/>
|
||||
<penaltyValue name="Ставка переноса при нехватке валюты" shortname="Ставка переноса при нехватке валюты" type="10"/>
|
||||
<quoteValue name="Ставка переноса при нехватке рублей" shortname="Ставка переноса при нехватке рублей" type="10"/>
|
||||
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
|
||||
</post>
|
||||
<put name="Изменение параметров риска" confirmation="value,quoteValue,workflowStatus" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterUpdateAction">
|
||||
<put name="Изменение параметров риска" confirmation="value,penaltyValue,quoteValue,workflowStatus" 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"/>
|
||||
<quoteValue name="Ставка сопряженной валюты" shortname="Ставка сопряженной валюты" type="10"/>
|
||||
<penaltyValue name="Ставка переноса при нехватке валюты" shortname="Ставка переноса при нехватке валюты" type="10"/>
|
||||
<quoteValue name="Ставка переноса при нехватке рублей" shortname="Ставка переноса при нехватке рублей" type="10"/>
|
||||
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
|
||||
</put>
|
||||
</actions>
|
||||
|
|
@ -2726,7 +2727,7 @@
|
|||
<account type="2" length="50" name="Торговый счет" shortname="Счет" searchable="true" sortable="true" visible="true"/>
|
||||
<companyId type="1" dbname="Идентификатор участника" name="Наименование участника" shortname="Участник" searchable="true" sortable="true" visible="true" link="company" linkCode="shortName"/>
|
||||
<tradingCode type="2" length="255" name="Код участника торгов" shortname="Код УТ" searchable="true" sortable="true" visible="true"/>
|
||||
<market type="12" name="Код режима торгов" shortname="Режим торгов" visible="true" searchable="true" sortable="true" link="market" linkCode="code"/>
|
||||
<market type="12" name="Код режима торгов" shortname="Режим торгов" visible="true" searchable="true" sortable="true"/>
|
||||
<status type="2" length="4" name="Статус заявки" shortname="Статус" link="orderStatus" searchable="true" sortable="true" visible="true"/>
|
||||
<price type="10" name="Цена заявки" shortname="Цена" searchable="true" sortable="true" visible="true"/>
|
||||
<quantityLot type="3" name="Объем заявки в лотах" shortname="Объем заявки в лотах" searchable="true" sortable="true" visible="false"/>
|
||||
|
|
@ -2748,7 +2749,7 @@
|
|||
<put name="Изменение заявки" class="ru.spcex.clearing.backendapi.controller.request.cud.order.OrderCurrencyUpdateAction">
|
||||
<id type="1" name="Идентификатор записи" shortname="ID" link="orderCurrency" linkCode="id" required="true"/>
|
||||
<securityId type="1" name="Наименование инструмента" shortname="Инструмент" link="security" linkCode="shortName" enabled="false" required="true"/>
|
||||
<market type="12" name="Код режима торгов" shortname="Режим торгов" link="market" linkCode="code" enabled="false" required="true"/>
|
||||
<market type="12" name="Код режима торгов" shortname="Режим торгов" enabled="false" required="true"/>
|
||||
<price type="10" name="Цена заявки" shortname="Цена" required="true"/>
|
||||
<quantityLot type="3" name="Объем заявки в лотах" shortname="Объем заявки" required="true"/>
|
||||
<side type="12" name="Направление заявки" shortname="Направление" required="true" link="side"/>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public class RiskParameter extends BusinessObject {
|
|||
private Long currencyPairId;
|
||||
private String workflowStatus;
|
||||
private BigDecimal quoteValue;
|
||||
private BigDecimal penaltyValue;
|
||||
|
||||
public BigDecimal getValue() {
|
||||
return value;
|
||||
|
|
@ -58,4 +59,12 @@ public class RiskParameter extends BusinessObject {
|
|||
public void setQuoteValue(BigDecimal quoteValue) {
|
||||
this.quoteValue = quoteValue;
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyValue() {
|
||||
return penaltyValue;
|
||||
}
|
||||
|
||||
public void setPenaltyValue(BigDecimal penaltyValue) {
|
||||
this.penaltyValue = penaltyValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ru.spcex.clearing.config;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -41,11 +42,14 @@ import ru.spcex.clearing.error.ClearingError;
|
|||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.IdentificationFundsRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeRefundDateRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeStatusExtractRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryReturnDepositRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest;
|
||||
import ru.spcex.clearing.service.AssetTrio;
|
||||
import ru.spcex.clearing.service.registry.AssetTBFProcessing;
|
||||
import ru.spcex.clearing.service.validation.AnltAccLoad;
|
||||
import ru.spcex.clearing.service.validation.ClrngValidationStored;
|
||||
import ru.spcex.clearing.service.validation.CompanyByTradingCodeValidationRule;
|
||||
|
|
@ -68,18 +72,27 @@ import ru.spcex.clearing.service.validation.SecurityBySecurityCodeValidationRule
|
|||
import ru.spcex.clearing.service.validation.SessionTerminationValidationRule;
|
||||
import ru.spcex.clearing.service.validation.SplitDepositRequestValidationRule;
|
||||
import ru.spcex.clearing.service.validation.StatusExtractValidationRule;
|
||||
import ru.spcex.clearing.service.validation.WithdrawalFundsValidationRule;
|
||||
import ru.spcex.clearing.service.validation.WithdrawalFundsValidationStore;
|
||||
import ru.spcex.clearing.util.security.UserRoleVerification;
|
||||
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
|
||||
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
|
||||
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
|
||||
import ru.spcex.platform.enumeration.ClearingCategory;
|
||||
import ru.spcex.platform.enumeration.CompanySymbol;
|
||||
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.IdEqualPredicate;
|
||||
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
|
||||
import ru.spcex.platform.imdg.validation.LogPrefixId;
|
||||
import ru.spcex.platform.imdg.validation.rule.CurrencyCodeValidationRule;
|
||||
import ru.spcex.platform.imdg.validation.rule.PresentById;
|
||||
import ru.spcex.platform.imdg.validation.rule.PresentByPredicate;
|
||||
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||
import ru.spcex.platform.utils.enumeration.IMessageResolver;
|
||||
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||
import ru.spcex.platform.utils.validation.IValidator;
|
||||
import ru.spcex.platform.utils.validation.ValidatorImpl;
|
||||
|
||||
|
|
@ -113,8 +126,9 @@ public class ValidationConfig {
|
|||
Imdg<PaymentInstruction> pmtImdg;
|
||||
Imdg<ClearingMemberCategory> ctgrImdg;
|
||||
ImdgProvider imdgProvider;
|
||||
AssetTBFProcessing assetsMng;
|
||||
|
||||
public ValidationConfig(ImdgProvider imdgProvider) {
|
||||
public ValidationConfig(ImdgProvider imdgProvider, AssetTBFProcessing assetsMng) {
|
||||
this.imdgRelation = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
|
||||
this.imdgCompany = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
|
||||
this.imdgCurrency = imdgProvider.getImdg(IMDGDistributedNames.Map_Currency, Currency.class);
|
||||
|
|
@ -142,6 +156,7 @@ public class ValidationConfig {
|
|||
this.currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class);
|
||||
this.digitalCertificateSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_DigitalCertificateSecurity, DigitalCertificateSecurity.class);
|
||||
this.imdgProvider = imdgProvider;
|
||||
this.assetsMng = assetsMng;
|
||||
}
|
||||
|
||||
//@Bean("adminRoleVerification")
|
||||
|
|
@ -399,6 +414,80 @@ public class ValidationConfig {
|
|||
};
|
||||
}
|
||||
|
||||
@Bean("withdrawalFundsValidator")
|
||||
public Function<DmauRegistryRequest, IValidator> withdrawalFundsValidator() {
|
||||
return identificationFundsRequest -> {
|
||||
ImdgValidationContext<DmauRegistryRequest> context = new ImdgValidationContext<>();
|
||||
context.setValidatedObject(identificationFundsRequest);
|
||||
context.addImdg(IMDGDistributedNames.Map_Account, imdgAccount);
|
||||
context.addImdg(IMDGDistributedNames.Map_Company, imdgCompany);
|
||||
context.addImdg(IMDGDistributedNames.Map_CompanySymbols, imdgCompanySymbols);
|
||||
context.addImdg(IMDGDistributedNames.Map_TradingClearingRegistry, imdgTradingClearingRegistry);
|
||||
context.addImdg(IMDGDistributedNames.Map_TradingClearingRegistryList, imdgTradingClearingRegistryList);
|
||||
|
||||
context.setLogPrefix(dmauRegistryRequest ->
|
||||
"[debitCorrAccount:%s]".formatted(dmauRegistryRequest.getDebitCorrAccount()
|
||||
));
|
||||
|
||||
ImdgPredicateBuilder cmpSymbPb = imdgCompanySymbols.predicateBuilder();
|
||||
var cmpSymbCheck = PresentByPredicate.builder(
|
||||
(Function<DmauRegistryRequest, ImdgPredicate>) req -> cmpSymbPb.and(
|
||||
cmpSymbPb.equals("companyId", req.getSenderId()),
|
||||
cmpSymbPb.equals("companySymbol", CompanySymbol.BIC.getKey())
|
||||
))
|
||||
.mapName(IMDGDistributedNames.Map_CompanySymbols)
|
||||
.errorProvider(req -> new EnumMessage(ClearingError.RecordNotFound, "companySymbol"))
|
||||
.store(WithdrawalFundsValidationStore.CompanySymbol)
|
||||
.build()
|
||||
;
|
||||
|
||||
ImdgPredicateBuilder cmpPb = imdgCompany.predicateBuilder();
|
||||
var cmpCheck = PresentByPredicate.builder(new IdEqualPredicate<>(
|
||||
cmpPb, DmauRegistryRequest::getSenderId
|
||||
))
|
||||
.mapName(IMDGDistributedNames.Map_Company)
|
||||
.errorProvider(req -> new EnumMessage(ClearingError.RecordNotFound, "company"))
|
||||
.store(WithdrawalFundsValidationStore.Company)
|
||||
.build();
|
||||
|
||||
ImdgPredicateBuilder accPb = imdgAccount.predicateBuilder();
|
||||
var accCheck = PresentByPredicate.builder(new IdEqualPredicate<>(
|
||||
accPb, DmauRegistryRequest::getCreditLegAccountId
|
||||
))
|
||||
.mapName(IMDGDistributedNames.Map_Account)
|
||||
.errorProvider(req -> new EnumMessage(ClearingError.RecordNotFound, "account"))
|
||||
.store(WithdrawalFundsValidationStore.Account)
|
||||
.build();
|
||||
|
||||
var assetPresent = new IValidationRule<ImdgValidationContext<DmauRegistryRequest>>() {
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<DmauRegistryRequest> ctx) {
|
||||
Company cmp = ctx.getStoredObject(WithdrawalFundsValidationStore.Company);
|
||||
Account acc = ctx.getStoredObject(WithdrawalFundsValidationStore.Account);
|
||||
Optional<AssetTrio> assetsTrio = assetsMng.searchMoneyByAccAndCompany(cmp.getId(), acc.getId());
|
||||
if (assetsTrio.isEmpty()) {
|
||||
return of(ClearingError.RecordNotFound, "AM_F/AM_B/AM_T");
|
||||
}
|
||||
ctx.storeObject(WithdrawalFundsValidationStore.AssetTrio, assetsTrio.get());
|
||||
return empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ruleName() {
|
||||
return "assets-present";
|
||||
}
|
||||
};
|
||||
|
||||
return new ValidatorImpl<>(context,
|
||||
WithdrawalFundsValidationRule.Fields,
|
||||
cmpSymbCheck,
|
||||
cmpCheck,
|
||||
accCheck,
|
||||
assetPresent
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean("splitDepositValidator")
|
||||
public Function<RegistrySplitDepositActionRequest, IValidator> splitDepositValidator() {
|
||||
return refundDateRequest -> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ public enum ClearingMessage implements IEnumKey {
|
|||
WithdrawalFreeFromTkr("payment-instruction.purpose.withdrawal.tcr"),
|
||||
WithdrawalOfFunds("payment-instruction.purpose.withdrawal"),
|
||||
urgent("sdf54.urgent"),
|
||||
withdrawalOfFundsDmau("withdrawal.funds.dmau"),
|
||||
;
|
||||
private final String key;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.clearing.SessionContinueE
|
|||
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.gateway.AssetOperationApprovalRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.IdentificationFundsRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeRefundDateRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeStatusExtractRequest;
|
||||
|
|
@ -40,6 +41,7 @@ import ru.spcex.clearing.service.execution.ExecutionFondComponent;
|
|||
import ru.spcex.clearing.service.executors.Sdf06Executor;
|
||||
import ru.spcex.clearing.service.executors.Sdf10Executor;
|
||||
import ru.spcex.clearing.service.payment.PaymentInstructionOutboundService;
|
||||
import ru.spcex.clearing.service.payment.WithdrawalFundsService;
|
||||
import ru.spcex.clearing.session.stage.SessionTerminator;
|
||||
import ru.spcex.clearing.session.stage.TaskType;
|
||||
import ru.spcex.clearing.session.stage.impl.BalanceRevise;
|
||||
|
|
@ -65,6 +67,7 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
|
|||
private final StatementServiceV2 statementService;
|
||||
private final SessionTerminator sessionTerminator;
|
||||
private final PaymentInstructionOutboundService pmtOutboundService;
|
||||
private final WithdrawalFundsService withdrawalFundsService;
|
||||
private final ExecutionCurrencyComponent execCurrUpload;
|
||||
private final ExecutionDepositComponent execDepUpload;
|
||||
private final ExecutionFondComponent execFondUpload;
|
||||
|
|
@ -81,7 +84,7 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
|
|||
Sdf05Sender sdf05Sender,
|
||||
StatementServiceV2 statementService,
|
||||
SessionTerminator sessionTerminator,
|
||||
PaymentInstructionOutboundService pmtOutboundService,
|
||||
PaymentInstructionOutboundService pmtOutboundService, WithdrawalFundsService withdrawalFundsService,
|
||||
ExecutionCurrencyComponent execCurrUpload,
|
||||
ExecutionDepositComponent execDepUpload,
|
||||
ExecutionFondComponent execFondUpload) {
|
||||
|
|
@ -98,6 +101,7 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
|
|||
this.statementService = statementService;
|
||||
this.sessionTerminator = sessionTerminator;
|
||||
this.pmtOutboundService = pmtOutboundService;
|
||||
this.withdrawalFundsService = withdrawalFundsService;
|
||||
this.execCurrUpload = execCurrUpload;
|
||||
this.execDepUpload = execDepUpload;
|
||||
this.execFondUpload = execFondUpload;
|
||||
|
|
@ -144,6 +148,9 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
|
|||
callback(PIClearingOutbondActionNewRequest.class)
|
||||
.setFunction(pmtOutboundService::sendOutBoundPayment)
|
||||
.forDestination(Consts.PAYMENT_INSTRUCTION_CLEARING_OUTBOUND_ACTION, callbacks::put);
|
||||
callback(DmauRegistryRequest.class)
|
||||
.setFunction(withdrawalFundsService::withdrawalFunds)
|
||||
.forDestination(Consts.REGISTRY_DMAU_CREATE_ACTION, callbacks::put);
|
||||
callback(StatementRequest.class)
|
||||
.setConsumer(statementService::processReq)
|
||||
.forDestination(Consts.STATEMENT_PROCESS, callbacks::put);
|
||||
|
|
|
|||
|
|
@ -124,9 +124,11 @@ public class Sdf54Creator {
|
|||
sDf54.setKpp_deb(kppDeb);
|
||||
}
|
||||
|
||||
Account accDebAcc = accountImdg.getSingleObjectByID(pmt.getDebitLeg_accountId());
|
||||
if (accDebAcc == null || !AccountStatus.ACTIVE.equalsByKey(accDebAcc.getStatus())) {
|
||||
log.warn("paymentInstruction[{}].DebitLeg_accountId={} account not exist or not active.", pmt.getId(), pmt.getDebitLeg_accountId());
|
||||
if (pmt.getDebitLeg_accountId() != null) {
|
||||
Account accDebAcc = accountImdg.getSingleObjectByID(pmt.getDebitLeg_accountId());
|
||||
if (accDebAcc == null || !AccountStatus.ACTIVE.equalsByKey(accDebAcc.getStatus())) {
|
||||
log.warn("paymentInstruction[{}].DebitLeg_accountId={} account not exist or not active.", pmt.getId(), pmt.getDebitLeg_accountId());
|
||||
}
|
||||
}
|
||||
BankAccount bnkAcc = bankAccountImdg.getFirstObjectBySQL("accountId = %d".formatted(pmt.getDebitLeg_accountId()));
|
||||
if (bnkAcc != null) {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,11 @@ public class Sdf55Executor {
|
|||
pmt.setUpdated(Instant.now());
|
||||
pmtImdg.update(pmt);
|
||||
String curr = TextUtil.isEmpty(sDf55.getPay_val()) ? CurrencyCode.RUB.getKey() : sDf55.getPay_val();
|
||||
dmiService.setContract(tcr.getId(), curr, sDf54.getDocnm_ref(), sDf55.getDocnmprev());
|
||||
if (tcr != null) {
|
||||
dmiService.setContract(tcr.getId(), curr, sDf54.getDocnm_ref(), sDf55.getDocnmprev());
|
||||
} else {
|
||||
dmiService.setContractByAcc(pmt.getCreditLeg_accountId(), curr, sDf54.getDocnm_ref(), sDf55.getDocnmprev());
|
||||
}
|
||||
assets.process(assetTrio.a__b(),
|
||||
assetTrio.a__t(),
|
||||
assetTrio.a__f(),
|
||||
|
|
|
|||
|
|
@ -453,6 +453,7 @@ public class Sdf57Executor extends AbstractExecutor<SDf57> {
|
|||
Company cmp = stmtCmpAcc.company();
|
||||
Account acc = stmtCmpAcc.account();
|
||||
Optional<AssetTrio> asts = createRegistryIfNeeded.apply(stmtCmpAcc);
|
||||
InOutDirection direction = IEnumKey.getEnumByKey(InOutDirection.class, stmt.getInOutDirection());
|
||||
if (accountIsAnlt(acc)) {
|
||||
AnltSearcher.AnltSearch searchResult = anltSearcher.loadByAnlt(stmt.getComment(), sdf57.getPay_val());
|
||||
if (searchResult.isFound()) {
|
||||
|
|
@ -475,7 +476,7 @@ public class Sdf57Executor extends AbstractExecutor<SDf57> {
|
|||
assets.process(trio.a__b(), trio.a__t(), trio.a__f(), BigDecimal.ZERO);
|
||||
});
|
||||
}
|
||||
} else if (InOutDirection.in.equals(IEnumKey.getEnumByKey(InOutDirection.class, stmt.getInOutDirection()))) {
|
||||
} else {
|
||||
log.debug("stmt.id={} comment='{}' error: {}. Operating through DMAU registry",
|
||||
stmt.getId(),
|
||||
stmt.getComment(),
|
||||
|
|
@ -499,17 +500,14 @@ public class Sdf57Executor extends AbstractExecutor<SDf57> {
|
|||
.build();
|
||||
newDmau.setRegistryUnit(RegistryUnit.U.getKey());
|
||||
newDmau.setRegistryCode(RegistryUtil.clearingCode(newDmau));
|
||||
newDmau.setBalance(safeBD(stmt.getAmount()));
|
||||
updateDmauReg(stmt, newDmau);
|
||||
registryImdg.insert(newDmau);
|
||||
log.debug("stmt.id={} created DMAU.id={}", stmt.getId(), newDmau.getId());
|
||||
});
|
||||
//DMAU подразумевает увеличение остатка поля balance и credit registry.code=DMAU
|
||||
String genTime = formatInstant(sdf57.getGenerationTime(), readableDateTime);
|
||||
notification.sendNotification(ObjectType.rgst,
|
||||
("Зачисление средств на регистр невыясненных денежных средств. "
|
||||
+ "Дата и время поступления: %s. "
|
||||
+ "ID платежного поручения: %d").formatted(genTime, sdf57.getDbfId()),
|
||||
Priority.HIGH);
|
||||
String ntfMsg = dmauNotificationText(direction, genTime, sdf57);
|
||||
notification.sendNotification(ObjectType.rgst, ntfMsg, Priority.HIGH);
|
||||
}
|
||||
} else if (OperationStatus.Executed.equalsByKey(stmt.getOperationStatus())) {
|
||||
if (asts.isPresent()) {
|
||||
|
|
@ -555,6 +553,25 @@ public class Sdf57Executor extends AbstractExecutor<SDf57> {
|
|||
return result;
|
||||
}
|
||||
|
||||
private String dmauNotificationText(InOutDirection direction, String genTime, SDf57 sdf57) {
|
||||
if (direction == null) return "notification error: unknown direction null";
|
||||
switch (direction) {
|
||||
case in -> {
|
||||
return ("Зачисление средств на регистр невыясненных денежных средств. "
|
||||
+ "Дата и время поступления: %s. "
|
||||
+ "ID платежного поручения: %d").formatted(genTime, sdf57.getDbfId());
|
||||
}
|
||||
case out -> {
|
||||
return ("Списание средств с регистра невыясненных денежных средств %s. " +
|
||||
"Дата и время списания: %s. " +
|
||||
"Объем списания: %s").formatted(
|
||||
sdf57.getAcc_deb(), genTime, sdf57.getSum_deb()
|
||||
);
|
||||
}
|
||||
default -> {return "notification error: unknown direction " + direction;}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean accountIsAnlt(Account account) {
|
||||
if (account == null) return false;
|
||||
boolean anlt = AccountType.Anlt.getKey().equals(account.getAccountType());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
package ru.spcex.clearing.service.payment;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.account.Account;
|
||||
import ru.clearing.classes.statics.data.company.Company;
|
||||
import ru.clearing.classes.statics.data.company.CompanySymbols;
|
||||
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.clearing.classes.statics.data.sdf.SDf54;
|
||||
import ru.spcex.clearing.error.ClearingError;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.messages.ClearingMessage;
|
||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.Consts;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.SdfClearingRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
|
||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||
import ru.spcex.clearing.service.AssetTrio;
|
||||
import ru.spcex.clearing.service.Sdf54Creator;
|
||||
import ru.spcex.clearing.service.SpecifUtil;
|
||||
import ru.spcex.clearing.service.registry.AssetTBFProcessing;
|
||||
import ru.spcex.clearing.service.registry.DmiService;
|
||||
import ru.spcex.clearing.service.validation.WithdrawalFundsValidationStore;
|
||||
import ru.spcex.clearing.util.LocaleUtil;
|
||||
import ru.spcex.clearing.util.security.UserRoleVerification;
|
||||
import ru.spcex.clearing.util.services.RequestHelper;
|
||||
import ru.spcex.platform.enumeration.CurrencyCode;
|
||||
import ru.spcex.platform.enumeration.InOutDirection;
|
||||
import ru.spcex.platform.enumeration.TransactionStatus;
|
||||
import ru.spcex.platform.enumeration.UserRole;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgId;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||
import ru.spcex.platform.utils.enumeration.IMessageResolver;
|
||||
import ru.spcex.platform.utils.localization.SpringPropertiesLocalizer;
|
||||
import ru.spcex.platform.utils.log.ExceptionUtils;
|
||||
import ru.spcex.platform.utils.text.TextUtil;
|
||||
import ru.spcex.platform.utils.time.TimeUtil;
|
||||
import ru.spcex.platform.utils.validation.IValidator;
|
||||
|
||||
@Service
|
||||
public class WithdrawalFundsService {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Function<DmauRegistryRequest, IValidator> withdrawalFundsVal;
|
||||
private final Sdf54Creator sdf54Creator;
|
||||
private final Imdg<SDf54> sdf54Imdg;
|
||||
private final Imdg<PaymentInstruction> pmtImdg;
|
||||
private final Imdg<Registry> rgsImdg;
|
||||
private final KafkaSender kafkaSender;
|
||||
private final ImdgId idGen;
|
||||
private final RequestHelper reqHelp;
|
||||
private final UserRoleVerification rights;
|
||||
private final IMessageResolver msgResolver;
|
||||
private final SpringPropertiesLocalizer localizer;
|
||||
private final AssetTBFProcessing assetsMng;
|
||||
private final DmiService dmiService;
|
||||
|
||||
public WithdrawalFundsService(Function<DmauRegistryRequest, IValidator> withdrawalFundsVal, Sdf54Creator sdf54Creator, ImdgProvider imdgProvider, KafkaSender kafkaSender, RequestHelper reqHelp, UserRoleVerification rights, IMessageResolver msgResolver, SpringPropertiesLocalizer localizer, AssetTBFProcessing assetsMng, DmiService dmiService) {
|
||||
this.withdrawalFundsVal = withdrawalFundsVal;
|
||||
this.sdf54Creator = sdf54Creator;
|
||||
this.kafkaSender = kafkaSender;
|
||||
this.sdf54Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf54, SDf54.class);
|
||||
this.pmtImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class);
|
||||
this.rgsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||
this.idGen = imdgProvider.getImdgIdGenerator();
|
||||
this.reqHelp = reqHelp;
|
||||
this.rights = rights;
|
||||
this.msgResolver = msgResolver;
|
||||
this.localizer = localizer;
|
||||
this.assetsMng = assetsMng;
|
||||
this.dmiService = dmiService;
|
||||
}
|
||||
|
||||
public RequestInfoUpdate withdrawalFunds(BaseRequest<DmauRegistryRequest> req) {
|
||||
if (!rights.userHasRole(req.getUserId(), UserRole.Admin)) {
|
||||
return reqHelp.error(req.getId(), ClearingError.UserVerifyDenial);
|
||||
}
|
||||
DmauRegistryRequest payload = req.getRequestPayload();
|
||||
IValidator validator = withdrawalFundsVal.apply(payload);
|
||||
Optional<EnumMessage> err = validator.tillFirstError();
|
||||
if (err.isPresent()) {
|
||||
log.error("DmauRegistryRequest.id={} debitCorrAccount={} validation error: {}",
|
||||
req.getId(),
|
||||
payload != null ? payload.getDebitCorrAccount() : null,
|
||||
msgResolver.resolve(err.get()));
|
||||
return reqHelp.error(req.getId(), err.get());
|
||||
}
|
||||
log.info("DmauRegistryRequest.id={} debitCorrAccount={} validation passed", req.getId(), payload.getDebitCorrAccount());
|
||||
CompanySymbols cmpSymb = validator.getStored(WithdrawalFundsValidationStore.CompanySymbol);
|
||||
Company cmp = validator.getStored(WithdrawalFundsValidationStore.Company);
|
||||
Account acc = validator.getStored(WithdrawalFundsValidationStore.Account);
|
||||
AssetTrio assets = validator.getStored(WithdrawalFundsValidationStore.AssetTrio);
|
||||
String curr = TextUtil.isEmpty(payload.getSecuritySymbol()) ? CurrencyCode.RUB.getKey() : payload.getSecuritySymbol();
|
||||
|
||||
Instant now = Instant.now();
|
||||
LocalDate nowDate = TimeUtil.toLocalDate(now);
|
||||
PaymentInstruction pmtIns = new PaymentInstruction();
|
||||
pmtIns.setSenderId(payload.getSenderId());
|
||||
pmtIns.setPayeeBic(cmpSymb.getCompanySymbolValue());
|
||||
pmtIns.setAdresseeBic(payload.getDebitBIC());
|
||||
pmtIns.setPayeeBankName(cmp.getShortName());
|
||||
pmtIns.setAddresseeBankName(payload.getDebitBankName());
|
||||
pmtIns.setPaymentDate(now);
|
||||
pmtIns.setPaymentPurpose(extractPaymentPurpose(payload));
|
||||
pmtIns.setSettlementDate(nowDate);
|
||||
pmtIns.setCreditLeg_amount(payload.getAmount());
|
||||
pmtIns.setDebitLeg_amount(payload.getAmount());
|
||||
pmtIns.setCreditLeg_accountId(payload.getCreditLegAccountId());
|
||||
pmtIns.setCreditLeg_account(acc.getAccount());
|
||||
pmtIns.setDebit_csAccount(payload.getDebitCorrAccount());
|
||||
pmtIns.setDebitLeg_account(payload.getDebitLegAccount());
|
||||
pmtIns.setCreditLeg_direction(InOutDirection.out.getKey());
|
||||
pmtIns.setDebitLeg_direction(InOutDirection.in.getKey());
|
||||
pmtIns.setCreditLeg_currencyCode(payload.getSecuritySymbol());
|
||||
pmtIns.setDebitLeg_currencyCode(payload.getSecuritySymbol());
|
||||
pmtIns.setCreditLeg_securityId(payload.getSecurityId());
|
||||
pmtIns.setDebitLeg_securityId(payload.getSecurityId());
|
||||
pmtIns.setTransactionStatus(TransactionStatus.stld.getKey());
|
||||
pmtIns.setCreated(now);
|
||||
pmtIns.setClearingDate(nowDate);
|
||||
pmtImdg.insert(pmtIns);
|
||||
log.info("created PaymentInstruction.id={}", pmtIns.getId());
|
||||
SDf54 sDf54;
|
||||
try {
|
||||
sDf54 = sdf54Creator.create(pmtIns);
|
||||
} catch (IllegalStateException e) {
|
||||
log.error(ExceptionUtils.getStackTrace(e));
|
||||
return failedResponse(req, now, pmtIns);
|
||||
}
|
||||
sDf54.setId(idGen.nextId());
|
||||
sDf54.setGenerationId(pmtIns.getId());
|
||||
sDf54.setRbankcode(pmtIns.getAdresseeBic());
|
||||
sDf54.setC_acc_cred(pmtIns.getDebit_csAccount());
|
||||
SpecifUtil.fillSegmentsBy35Symbols(pmtIns.getAddresseeBankName(),
|
||||
sDf54::setRbanknam1,
|
||||
sDf54::setRbanknam2,
|
||||
sDf54::setRbanknam3,
|
||||
sDf54::setRbanknam4,
|
||||
sDf54::setRbanknam5);
|
||||
SpecifUtil.fillSegmentsBy35Symbols(payload.getDebitCompanyName(),
|
||||
sDf54::setRclientn1,
|
||||
sDf54::setRclientn2,
|
||||
sDf54::setRclientn3,
|
||||
sDf54::setRclientn4
|
||||
);
|
||||
sDf54.setInn_cred(payload.getDebitINN());
|
||||
sDf54.setKpp_cred(payload.getDebitKPP());
|
||||
sdf54Imdg.insert(sDf54);
|
||||
log.info("created sdf54.id={}", sDf54.getId());
|
||||
|
||||
Registry d__i = dmiService.createDmi(payload.getAmount().negate(), assets.a__t());
|
||||
d__i.setComment(sDf54.getDocnm_ref());
|
||||
rgsImdg.insert(d__i);
|
||||
log.debug("created {}.id={}; recalculating assests...", d__i.getRegistryCode(), d__i.getId());
|
||||
assetsMng.process(assets.a__b(), assets.a__t(), assets.a__f(), BigDecimal.ZERO);
|
||||
|
||||
SdfClearingRequest exp = new SdfClearingRequest();
|
||||
exp.setGroupId(sDf54.getGenerationId());
|
||||
kafkaSender.sendRequestToQueue(Consts.SDF54_PROCESS, exp);
|
||||
|
||||
return reqHelp.success(req.getId());
|
||||
}
|
||||
|
||||
private RequestInfoUpdate failedResponse(BaseRequest<DmauRegistryRequest> req,
|
||||
Instant now,
|
||||
PaymentInstruction pmtIns) {
|
||||
pmtIns.setTransactionStatus(TransactionStatus.fail.getKey());
|
||||
pmtIns.setUpdated(now);
|
||||
pmtImdg.update(pmtIns);
|
||||
return reqHelp.error(req.getId(), ClearingError.GeneralError);
|
||||
}
|
||||
|
||||
private String extractPaymentPurpose(DmauRegistryRequest payload) {
|
||||
if (!TextUtil.isEmpty(payload.getPaymentPurpose())) {
|
||||
return payload.getPaymentPurpose();
|
||||
}
|
||||
if (CurrencyCode.RUB.equalsByKey(payload.getSecuritySymbol())) {
|
||||
return localizer.resolve(ClearingMessage.withdrawalOfFundsDmau, LocaleUtil.ru, payload.getSecuritySymbol());
|
||||
} else {
|
||||
return localizer.resolve(ClearingMessage.withdrawalOfFundsDmau, LocaleUtil.eng, payload.getSecuritySymbol());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -92,42 +92,55 @@ public class DmiService {
|
|||
String securitySymbol,
|
||||
String comment,
|
||||
String contract) {
|
||||
findDmiByComment(tcrId, securitySymbol, comment).ifPresentOrElse(d__i -> {
|
||||
d__i.setContract(contract);
|
||||
d__i.setUpdated(Instant.now());
|
||||
try {
|
||||
Long dbfId = Long.valueOf(contract);
|
||||
SDf57 sdf57 = sDf57Imdg.getFirstObjectBySQL("dbfId=%d".formatted(dbfId));
|
||||
if (sdf57 != null) {
|
||||
ImdgPredicateBuilder pb = statementImdg.predicateBuilder();
|
||||
ImdgPredicate stmtPrdct = pb.and(
|
||||
pb.equals("inSDfId", sdf57.getId()),
|
||||
pb.equals("inOutSDfType", InOutSDfType.type57.getKey())
|
||||
);
|
||||
Statement stmt = statementImdg.getFirstObjectByPredicate(stmtPrdct);
|
||||
if (stmt != null && OperationStatus.Executed.equalsByKey(stmt.getOperationStatus())) {
|
||||
d__i.setRegistryStatus(RegistryStatus.OK.getKey());
|
||||
} else {
|
||||
log.warn("tcrId={} securitySymbol={} comment={} sdf57 dbfId={} found, stmt.id={} status {}. d**i status will not be updated",
|
||||
tcrId,
|
||||
securitySymbol,
|
||||
comment,
|
||||
dbfId,
|
||||
stmt != null ? stmt.getId() : null,
|
||||
stmt != null ? stmt.getOperationStatus() : null);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("sdf57 search by {}: error {}",
|
||||
contract,
|
||||
ExceptionUtils.getStackTrace(e));
|
||||
}
|
||||
rgsImdg.update(d__i);
|
||||
log.trace("set {}.id={} contract {}", d__i.getRegistryCode(), d__i.getId(), contract);
|
||||
}, () -> log.trace("didn't find DM*I by tcr.id={} securitySymbol={} comment={}",
|
||||
findDmiByComment(tcrId, securitySymbol, comment).ifPresentOrElse(
|
||||
(d__i) -> updateD__i(d__i, contract, securitySymbol, comment),
|
||||
() -> log.trace("didn't find DM*I by tcr.id={} securitySymbol={} comment={}",
|
||||
tcrId, securitySymbol, comment));
|
||||
}
|
||||
|
||||
public void setContractByAcc(Long accId,
|
||||
String securitySymbol,
|
||||
String comment,
|
||||
String contract) {
|
||||
findDmiByCommentAcc(accId, securitySymbol, comment).ifPresentOrElse(
|
||||
(d__i) -> updateD__i(d__i, contract, securitySymbol, comment),
|
||||
() -> log.trace("didn't find DM*I by acc.id={} securitySymbol={} comment={}",
|
||||
accId, securitySymbol, comment));
|
||||
}
|
||||
|
||||
private void updateD__i(Registry d__i, String contract, String securitySymbol, String comment) {
|
||||
d__i.setContract(contract);
|
||||
d__i.setUpdated(Instant.now());
|
||||
try {
|
||||
Long dbfId = Long.valueOf(contract);
|
||||
SDf57 sdf57 = sDf57Imdg.getFirstObjectBySQL("dbfId=%d".formatted(dbfId));
|
||||
if (sdf57 != null) {
|
||||
ImdgPredicateBuilder pb = statementImdg.predicateBuilder();
|
||||
ImdgPredicate stmtPrdct = pb.and(
|
||||
pb.equals("inSDfId", sdf57.getId()),
|
||||
pb.equals("inOutSDfType", InOutSDfType.type57.getKey())
|
||||
);
|
||||
Statement stmt = statementImdg.getFirstObjectByPredicate(stmtPrdct);
|
||||
if (stmt != null && OperationStatus.Executed.equalsByKey(stmt.getOperationStatus())) {
|
||||
d__i.setRegistryStatus(RegistryStatus.OK.getKey());
|
||||
} else {
|
||||
log.warn("securitySymbol={} comment={} sdf57 dbfId={} found, stmt.id={} status {}. d**i status will not be updated",
|
||||
securitySymbol,
|
||||
comment,
|
||||
dbfId,
|
||||
stmt != null ? stmt.getId() : null,
|
||||
stmt != null ? stmt.getOperationStatus() : null);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("sdf57 search by {}: error {}",
|
||||
contract,
|
||||
ExceptionUtils.getStackTrace(e));
|
||||
}
|
||||
rgsImdg.update(d__i);
|
||||
log.trace("set {}.id={} contract {}", d__i.getRegistryCode(), d__i.getId(), contract);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ищем D**I по tcrId/security/contract
|
||||
|
|
@ -178,6 +191,20 @@ public class DmiService {
|
|||
return Optional.ofNullable(d__i);
|
||||
}
|
||||
|
||||
private Optional<Registry> findDmiByCommentAcc(Long accId, String securitySymbol, String comment) {
|
||||
ImdgPredicateBuilder pb = rgsImdg.predicateBuilder();
|
||||
RegistryTradingParams rgsCde = RegistryTradingParams.D__I;
|
||||
ImdgPredicate prdct = pb.and(
|
||||
pb.sql(RegistryCodeSqlBuilder.getInstance(rgsCde).build()),
|
||||
pb.equals("accountId", accId),
|
||||
pb.equals("securitySymbol", securitySymbol),
|
||||
pb.equals("comment", comment)
|
||||
);
|
||||
log.trace("searching D**I by {}", prdct);
|
||||
Registry d__i = rgsImdg.getFirstObjectByPredicate(prdct);
|
||||
return Optional.ofNullable(d__i);
|
||||
}
|
||||
|
||||
public Optional<Registry> createDmi(Long tcrId,
|
||||
String securitySymbol,
|
||||
BigDecimal summ) {
|
||||
|
|
|
|||
|
|
@ -104,9 +104,10 @@ public enum Sdf55ValidationRule implements IValidationRule<ImdgValidationContext
|
|||
}
|
||||
|
||||
if (tcr == null) {
|
||||
return of(ClearingError.RecordNotFound, errMsg);
|
||||
log.debug("{}: TCR was not found; account will be used instead.", ruleName());
|
||||
} else {
|
||||
context.storeObject(ValidationStored.Sdf55Tcr, tcr);
|
||||
}
|
||||
context.storeObject(ValidationStored.Sdf55Tcr, tcr);
|
||||
return empty();
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package ru.spcex.clearing.service.validation;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.spcex.clearing.error.ClearingError;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
|
||||
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
|
||||
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||
|
||||
public enum WithdrawalFundsValidationRule implements IValidationRule<ImdgValidationContext<DmauRegistryRequest>> {
|
||||
Fields() {
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<DmauRegistryRequest> context) {
|
||||
DmauRegistryRequest validatedObject = context.getValidatedObject();
|
||||
if (validatedObject.getAmount() == null || validatedObject.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return of(ClearingError.WrongField, "amount");
|
||||
}
|
||||
if (validatedObject.getBalance() == null || validatedObject.getBalance().compareTo(validatedObject.getAmount()) < 0) {
|
||||
return of(ClearingError.WrongField, "balance");
|
||||
}
|
||||
if (validatedObject.getSenderId() == null) {
|
||||
return of(ClearingError.WrongField, "senderId");
|
||||
}
|
||||
return empty();
|
||||
}
|
||||
},
|
||||
;
|
||||
private final static Logger log = LoggerFactory.getLogger(WithdrawalFundsValidationRule.class);
|
||||
|
||||
@Override
|
||||
public String ruleName() {
|
||||
return "WithdrawalFundsValidationRule." + name();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package ru.spcex.clearing.service.validation;
|
||||
|
||||
public enum WithdrawalFundsValidationStore {
|
||||
CompanySymbol,
|
||||
Company,
|
||||
Account,
|
||||
AssetTrio,
|
||||
;
|
||||
}
|
||||
|
|
@ -5,8 +5,8 @@ import ru.clearing.classes.statics.data.account.Account;
|
|||
import ru.spcex.platform.enumeration.CurrencyCode;
|
||||
|
||||
public class LocaleUtil {
|
||||
private static final Locale ru = new Locale("ru");
|
||||
private static final Locale eng = new Locale("eng");
|
||||
public static final Locale ru = new Locale("ru");
|
||||
public static final Locale eng = new Locale("eng");
|
||||
|
||||
public static boolean isRus(Locale locale) {
|
||||
return ru.equals(locale);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
payment-instruction.purpose.withdrawal.tcr=Debt free cash withdrawal from TKR {0}.
|
||||
payment-instruction.purpose.withdrawal=Debt free cash withdrawal.
|
||||
sdf54.urgent=urgent
|
||||
sdf54.urgent=urgent
|
||||
withdrawal.funds.dmau=Withdrawal of funds from the register {0} of unidentified funds
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
payment-instruction.purpose.withdrawal.tcr=Возврат средств, свободных от обязательств с ТКР {0}.
|
||||
payment-instruction.purpose.withdrawal=Вывод средств.
|
||||
sdf54.urgent=срочно
|
||||
sdf54.urgent=срочно
|
||||
withdrawal.funds.dmau=Вывод средств с регистра невыясненных денежных средств по {0}
|
||||
|
|
@ -5343,7 +5343,9 @@ CREATE TABLE RISK_PARAMETER
|
|||
CURRENCY_PAIR_ID BIGINT,
|
||||
CREATED_AT timestamp,
|
||||
UPDATED_AT timestamp,
|
||||
WORKFLOW_STATUS VARCHAR(4)
|
||||
WORKFLOW_STATUS VARCHAR(4),
|
||||
PENALTY_VALUE numeric(72,18),
|
||||
QUOTE_VALUE numeric(72,18)
|
||||
);
|
||||
COMMENT ON TABLE RISK_PARAMETER IS 'Риск-параметры';
|
||||
COMMENT ON COLUMN RISK_PARAMETER.ID IS 'Идентификатор записи';
|
||||
|
|
@ -5354,6 +5356,8 @@ COMMENT ON COLUMN RISK_PARAMETER.CURRENCY_PAIR_ID IS 'Идентификатор
|
|||
COMMENT ON COLUMN RISK_PARAMETER.CREATED_AT IS 'Время создания записи';
|
||||
COMMENT ON COLUMN RISK_PARAMETER.UPDATED_AT IS 'Время изменения записи';
|
||||
COMMENT ON COLUMN RISK_PARAMETER.WORKFLOW_STATUS IS 'Статус';
|
||||
COMMENT ON COLUMN RISK_PARAMETER.QUOTE_VALUE IS 'Ставка переноса сопряженной валюты';
|
||||
COMMENT ON COLUMN RISK_PARAMETER.PENALTY_VALUE IS 'Ставка переноса при нехватке базовой валюты';
|
||||
GRANT ALL PRIVILEGES ON TABLE RISK_PARAMETER TO clearing;
|
||||
|
||||
-- rates - Расчетные курсы
|
||||
|
|
@ -5579,7 +5583,8 @@ CREATE TABLE ORDER_CURRENCY
|
|||
COMMENT VARCHAR(255),
|
||||
INITIAL_ORDER_ID BIGINT,
|
||||
CREATED_AT TIMESTAMP,
|
||||
UPDATED_AT TIMESTAMP
|
||||
UPDATED_AT TIMESTAMP,
|
||||
REGISTRY_ID BIGINT
|
||||
);
|
||||
|
||||
COMMENT ON TABLE ORDER_CURRENCY IS 'Заявки для заключения сделок переноса на валютном рынке';
|
||||
|
|
@ -5753,4 +5758,4 @@ GRANT ALL PRIVILEGES ON TABLE S_ORDERS TO clearing;
|
|||
|
||||
-- Data types
|
||||
|
||||
INSERT INTO DB_VERSION(ID, VERSION) values (1, '3.22') ON CONFLICT (ID) DO UPDATE SET VERSION = EXCLUDED.VERSION
|
||||
INSERT INTO DB_VERSION(ID, VERSION) values (1, '3.23') ON CONFLICT (ID) DO UPDATE SET VERSION = EXCLUDED.VE RSION
|
||||
|
|
@ -7,5 +7,6 @@
|
|||
/* Business objects */
|
||||
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (1000, 'SCND', 'CURR', 'RUB', 'UVAK', 'Режим непрерывных торгов (торги иностранной валютой с Провайдером ликвидности)', 1, 'Continuous trading mode (foreign currency trading with a Liquidity Provider)') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (1001, 'SCSP', 'CURR', 'RUB', 'TVAK', 'Технический режим переговорных сделок для сделок урегулирования', 1, 'Technical negotiated deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (1002, 'SCSW', 'CURR', 'RUB', 'TVWK', 'Технический режим витринных переговорных сделок для сделок урегулирования', 1, 'Technical negotiated showcase deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (1001, 'SCND', 'CURR', 'RUB', 'NVAK', 'Режим анонимных переговорных сделок (торги иностранной валютой с Провайдером ликвидности)', 1, 'Anonimous negotiated deals mode (foreign currency trading with a Liquidity Provider)') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (2002, 'SCSP', 'CURR', 'RUB', 'TVAK', 'Технический режим переговорных сделок для сделок урегулирования', 1, 'Technical negotiated deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (2003, 'SCSW', 'CURR', 'RUB', 'TVWK', 'Технический режим витринных переговорных сделок для сделок урегулирования', 1, 'Technical negotiated showcase deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
|
|
@ -7,5 +7,5 @@
|
|||
/* Business objects */
|
||||
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (2000, 'SCND', 'CURR', 'RUB', 'UVAF', 'Режим непрерывных торгов (торги иностранной валютой с Провайдером ликвидности)', 1, 'Continuous trading mode (foreign currency trading with a Liquidity Provider)') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (2001, 'SCSP', 'CURR', 'RUB', 'TVAF', 'Технический режим переговорных сделок для сделок урегулирования', 1, 'Technical negotiated deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (2002, 'SCSW', 'CURR', 'RUB', 'TVWF', 'Технический режим витринных переговорных сделок для сделок урегулирования', 1, 'Technical negotiated showcase deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (2002, 'SCSP', 'CURR', 'RUB', 'TVAF', 'Технический режим переговорных сделок для сделок урегулирования', 1, 'Technical negotiated deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
INSERT INTO MARKET(ID, MARKET_TYPE, SECTION, SETTLEMENT_CURRENCY, CODE, NAME, EXCHANGE_ID, DESCRIPTION) values (2003, 'SCSW', 'CURR', 'RUB', 'TVWF', 'Технический режим витринных переговорных сделок для сделок урегулирования', 1, 'Technical negotiated showcase deals mode for settlement') ON CONFLICT (ID) DO UPDATE SET MARKET_TYPE = EXCLUDED.MARKET_TYPE, SECTION = EXCLUDED.SECTION, SETTLEMENT_CURRENCY = EXCLUDED.SETTLEMENT_CURRENCY, CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, EXCHANGE_ID = EXCLUDED.EXCHANGE_ID, DESCRIPTION = EXCLUDED.DESCRIPTION;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
ALTER TABLE RISK_PARAMETER ADD COLUMN IF NOT EXISTS QUOTE_VALUE NUMERIC(72, 18);
|
||||
COMMENT ON COLUMN RISK_PARAMETER.QUOTE_VALUE IS 'Ставка переноса сопряженной валюты';
|
||||
ALTER TABLE RISK_PARAMETER ADD COLUMN IF NOT EXISTS PENALTY_VALUE NUMERIC(72, 18);
|
||||
COMMENT ON COLUMN RISK_PARAMETER.PENALTY_VALUE IS 'Ставка переноса при нехватке базовой валюты';
|
||||
|
||||
ALTER TABLE ORDER_CURRENCY ADD COLUMN IF NOT EXISTS REGISTRY_ID BIGINT;
|
||||
COMMENT ON COLUMN ORDER_CURRENCY.REGISTRY_ID IS 'Идентификатор регистра';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package ru.spcex.clearing.dflt.management.component.validation;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import ru.clearing.classes.statics.data.misc.OrderCurrency;
|
||||
import ru.spcex.clearing.dflt.management.error.DefaultManagementErrors;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.order.OrderCompanyUpdateRequest;
|
||||
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
|
||||
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||
|
||||
public class OrderCurrencyCompanyNotChanged
|
||||
implements IValidationRule<ImdgValidationContext<OrderCompanyUpdateRequest>> {
|
||||
public static final OrderCurrencyCompanyNotChanged INSTANCE = new OrderCurrencyCompanyNotChanged();
|
||||
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<OrderCompanyUpdateRequest> ctx) {
|
||||
OrderCompanyUpdateRequest validatedObject = ctx.getValidatedObject();
|
||||
OrderCurrency oc = ctx.getStoredObject(OrderCurrencyValidationStored.OrderCurrency);
|
||||
|
||||
BigDecimal reqQuantityLog = Optional.ofNullable(validatedObject.getQuantityLot())
|
||||
.map(BigDecimal::new)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
BigDecimal entityQuantityLog = Optional.ofNullable(oc.getQuantityLot())
|
||||
.orElse(BigDecimal.ZERO);
|
||||
|
||||
if (Objects.equals(validatedObject.getCompanyId(), oc.getCompanyId())
|
||||
&& Objects.equals(validatedObject.getTradingClearingRegistryId(), oc.getTradingClearingRegistryId())
|
||||
&& Objects.equals(reqQuantityLog, entityQuantityLog)) {
|
||||
return of(DefaultManagementErrors.RecordAlreadyPresent);
|
||||
}
|
||||
return empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ruleName() {
|
||||
return "OrderCurrencyCompanyNotChanged";
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ import ru.clearing.platform.dictionary.OrderStatusDictionary;
|
|||
import ru.clearing.platform.dictionary.OvernightTypeDictionary;
|
||||
import ru.clearing.platform.dictionary.SideDictionary;
|
||||
import ru.spcex.clearing.dflt.management.component.validation.OrderCurrencyByCompanyAndTcrAlreadyPresent;
|
||||
import ru.spcex.clearing.dflt.management.component.validation.OrderCurrencyCompanyNotChanged;
|
||||
import ru.spcex.clearing.dflt.management.component.validation.OrderCurrencyPLBLCheck;
|
||||
import ru.spcex.clearing.dflt.management.component.validation.OrderCurrencyValidationStored;
|
||||
import ru.spcex.clearing.dflt.management.component.validation.OvernightSettingAlreadyPresent;
|
||||
|
|
@ -355,7 +356,10 @@ public class ValidationConfig {
|
|||
.builder(r -> {
|
||||
OrderCurrency oc = ctx.getStoredObject(OrderCurrencyValidationStored.OrderCurrency);
|
||||
ImdgPredicateBuilder pb = tcrImdg.predicateBuilder();
|
||||
return pb.equals("companyId", oc.getCounterPartyId());
|
||||
return pb.and(
|
||||
pb.equals("companyId", oc.getCounterPartyId()),
|
||||
pb.equals("code", oc.getCounterTradingCode())
|
||||
);
|
||||
})
|
||||
.mapName(IMDGDistributedNames.Map_TradingClearingRegistry)
|
||||
.errorProvider(r -> recordNotFound("counter (CK) TradingClearingRegistry"))
|
||||
|
|
@ -434,6 +438,7 @@ public class ValidationConfig {
|
|||
companyPresentRule,
|
||||
tcrPresent,
|
||||
QuantityLotGreaterThanZero.INSTANCE,
|
||||
OrderCurrencyCompanyNotChanged.INSTANCE,
|
||||
//OrderCurrencyByCompanyAndTcrAlreadyPresent.getInstance(OrderCompanyUpdateRequest.class),
|
||||
OrderCurrencyPLBLCheck.INSTANCE,
|
||||
counterOrderPresent);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import ru.spcex.clearing.platform.messaging.domain.cud.order.OrderCurrencyUpdate
|
|||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
|
||||
import ru.spcex.clearing.platform.messaging.service.Status;
|
||||
import ru.spcex.platform.enumeration.MarketType;
|
||||
import ru.spcex.platform.enumeration.OrderStatus;
|
||||
import ru.spcex.platform.enumeration.OvernightType;
|
||||
import ru.spcex.platform.enumeration.SettleCode;
|
||||
|
|
@ -183,7 +182,7 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
|
|||
if (OvernightType.SWAP.equalsByKey(order.getOvernightType())) {
|
||||
Pair<OrderCurrency, OrderCurrency> newSpotPair = swapToSpotSplit(order, rgs);
|
||||
log.info("deleting old OrderCurrency.id={}", order.getId());
|
||||
orderCurrencyImdg.delete(order);
|
||||
reject(order);
|
||||
orderCurrencyImdg.insert(newSpotPair.getFirst());
|
||||
orderCurrencyImdg.insert(newSpotPair.getSecond());
|
||||
log.info("created OrderCurrency[{}, {}]",
|
||||
|
|
@ -192,14 +191,20 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
|
|||
OrderCurrency pairOrder = validator.getStored(OrderCurrencyValidationStored.OrderCurrencySpotPair);
|
||||
OrderCurrency newSwapOrder = spotToSwap(order, pairOrder, rgs);
|
||||
log.info("deleting old records OrderCurrency[{}, {}]", order.getId(), pairOrder.getId());
|
||||
orderCurrencyImdg.delete(order);
|
||||
orderCurrencyImdg.delete(pairOrder);
|
||||
reject(order);
|
||||
reject(pairOrder);
|
||||
orderCurrencyImdg.insert(newSwapOrder);
|
||||
log.info("created OrderCurrency.id={}", newSwapOrder.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void reject(OrderCurrency o) {
|
||||
o.setStatus(OrderStatus.REJECTED.getKey());
|
||||
o.setUpdated(Instant.now());
|
||||
orderCurrencyImdg.update(o);
|
||||
}
|
||||
|
||||
private Pair<OrderCurrency, OrderCurrency> swapToSpotSplit(OrderCurrency swap, Registry rgs) {
|
||||
OrderCurrency orderT0 = new OrderCurrency();
|
||||
OrderCurrency orderT1 = new OrderCurrency();
|
||||
|
|
@ -216,26 +221,34 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
|
|||
}
|
||||
|
||||
Market market = imdgQueryService.getSpotMarket();
|
||||
Listing listing = imdgQueryService.findListing(rgs, market.getCode());
|
||||
Listing listingT0 = imdgQueryService.findListing(rgs, market.getCode(), SettleCode.T0.getKey());
|
||||
Listing listingT1 = imdgQueryService.findListing(rgs, market.getCode(), SettleCode.T1.getKey());
|
||||
//мб возвращать вместе с листингом?
|
||||
CurrencyPairDictionary currPair = imdgQueryService.getCurrencyPairDictionaryBySecurityId(listing.getSecurityId());
|
||||
SCrossRate rate = imdgQueryService.getSCrossRates(currPair.getBaseCurrency(), LocalDate.now());
|
||||
CurrencyPairDictionary currPairT0 = imdgQueryService.getCurrencyPairDictionaryBySecurityId(listingT0.getSecurityId());
|
||||
SCrossRate rateT0 = imdgQueryService.getSCrossRates(currPairT0.getBaseCurrency(), LocalDate.now());
|
||||
CurrencyPairDictionary currPairT1 = imdgQueryService.getCurrencyPairDictionaryBySecurityId(listingT1.getSecurityId());
|
||||
SCrossRate rateT1 = imdgQueryService.getSCrossRates(currPairT1.getBaseCurrency(), LocalDate.now());
|
||||
|
||||
var pair = new Pair<>(orderT0, orderT1);
|
||||
Pair.forEach(pair, o -> {
|
||||
copyCommonFields(swap, o);
|
||||
o.setSecurityId(listing.getSecurityId());
|
||||
o.setSecuritySymbol(listing.getSymbolCode());
|
||||
o.setListingId(listing.getId());
|
||||
o.setOvernightType(OvernightType.SPOT.getKey());
|
||||
o.setMarket(MarketType.SCSP.getKey());
|
||||
o.setMarket(market.getCode());
|
||||
o.setCreated(Instant.now());
|
||||
});
|
||||
orderT0.setPrice(rate.getUnitRate());
|
||||
orderT1.setPrice(BigDecimalUtil.safeSumBD(swap.getPrice(), rate.getUnitRate()));
|
||||
updateOrderFieldsByListing(orderT0, listingT0);
|
||||
updateOrderFieldsByListing(orderT1, listingT1);
|
||||
orderT0.setPrice(rateT0.getUnitRate());
|
||||
orderT1.setPrice(BigDecimalUtil.safeSumBD(swap.getPrice(), rateT1.getUnitRate()));
|
||||
return pair;
|
||||
}
|
||||
|
||||
private void updateOrderFieldsByListing(OrderCurrency order, Listing listing) {
|
||||
order.setSecurityId(listing.getSecurityId());
|
||||
order.setSecuritySymbol(listing.getSymbolCode());
|
||||
order.setListingId(listing.getId());
|
||||
}
|
||||
|
||||
private OrderCurrency spotToSwap(OrderCurrency order1, OrderCurrency order2, Registry rgs) {
|
||||
OrderCurrency spotT0;
|
||||
OrderCurrency spotT1;
|
||||
|
|
@ -257,14 +270,14 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
|
|||
}
|
||||
|
||||
Market market = imdgQueryService.getSwapMarket();
|
||||
Listing listing = imdgQueryService.findListing(rgs, market.getCode());
|
||||
Listing listing = imdgQueryService.findListing(rgs, market.getCode(), SettleCode.T1.getKey());
|
||||
|
||||
copyCommonFields(order1, swap);
|
||||
swap.setSecurityId(listing.getSecurityId());
|
||||
swap.setSecuritySymbol(listing.getSymbolCode());
|
||||
swap.setListingId(listing.getId());
|
||||
swap.setOvernightType(OvernightType.SWAP.getKey());
|
||||
swap.setMarket(MarketType.SCSW.getKey());
|
||||
swap.setMarket(market.getCode());
|
||||
swap.setPrice(safeBD(spotT1.getPrice()).subtract(safeBD(spotT0.getPrice())));
|
||||
swap.setCreated(Instant.now());
|
||||
return swap;
|
||||
|
|
@ -380,8 +393,8 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
|
|||
OrderCurrency counterOrder = validator.getStored(OrderCurrencyValidationStored.CounterOrderCurrency);
|
||||
|
||||
log.info("deleting OrderCurrency[{}, {}]", order.getId(), counterOrder.getId());
|
||||
orderCurrencyImdg.delete(order);
|
||||
orderCurrencyImdg.delete(counterOrder);
|
||||
reject(order);
|
||||
reject(counterOrder);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -406,6 +419,7 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
|
|||
private void updateByFix(BaseRequest<OrderCurrencyStatusUpdateRequest> req) {
|
||||
OrderCurrencyStatusUpdateRequest payload = req.getRequestPayload();
|
||||
for (Long orderId : payload.getIds()) {
|
||||
log.debug("Process updating status by orderNum {}", orderId);
|
||||
SOrders sOrder = sOrdersImdg.getSingleObjectByPredicate(
|
||||
sOrdersImdg.predicateBuilder().equals("orderNum", orderId)
|
||||
);
|
||||
|
|
@ -416,7 +430,6 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
|
|||
}
|
||||
orderCurrency.setStatus(status.getKey());
|
||||
orderCurrency.setUpdated(Instant.now());
|
||||
// orderCurrency.setUpdated(sOrder.getTradeDate());//todo
|
||||
orderCurrencyImdg.update(orderCurrency);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ public class TaskListener extends QueueConsumer implements InitializingBean {
|
|||
kafkaSender.sendRequestToQueue(Consts.NOTIFICATION_NEW, newReq);
|
||||
}
|
||||
|
||||
log.info("SDOR export and send command to fix, request={}", req);
|
||||
log.info("export to tri...");
|
||||
try {
|
||||
Collection<OrderCurrency> orders = imdgQueryService.getClccOrderCurrencyIds();
|
||||
String content = orderCurrencyTriExportService.exportToTri(orders);
|
||||
|
|
@ -159,6 +159,7 @@ public class TaskListener extends QueueConsumer implements InitializingBean {
|
|||
LocalDateTime.now().format(formatter)));
|
||||
Files.writeString(fileName, content, StandardCharsets.UTF_8);
|
||||
if (SendOrdersTypes.FIX == sendOrdersTypes) {
|
||||
log.info("send command to fix service...");
|
||||
kafkaSender.sendRequestToQueue(Consts.SDOR_FIX_TASK, req.getRequestPayload());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package ru.spcex.clearing.dflt.management.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public record FinalCalculationResult(
|
||||
BigDecimal price,
|
||||
BigDecimal rate,
|
||||
BigDecimal quantityLot,
|
||||
CalculationResult calculationResult
|
||||
) {
|
||||
}
|
||||
|
|
@ -209,7 +209,6 @@ public class ImdgQueryService {
|
|||
public BigDecimal defineTransferRate(Long currencyPairDictionaryId, String securitySymbol) {
|
||||
ImdgPredicateBuilder pb = riskParameterImdg.predicateBuilder();
|
||||
boolean isRub = "RUB".equals(securitySymbol);
|
||||
String baseCurrency = isRub ? "CNY" : securitySymbol;
|
||||
|
||||
RiskParameter riskParameter = riskParameterImdg.getSingleObjectByPredicate(
|
||||
pb.and(
|
||||
|
|
@ -217,7 +216,7 @@ public class ImdgQueryService {
|
|||
pb.equals("currencyPairId", currencyPairDictionaryId)
|
||||
)
|
||||
);
|
||||
return isRub ? riskParameter.getValue() : riskParameter.getQuoteValue();
|
||||
return isRub ? riskParameter.getQuoteValue() : riskParameter.getPenaltyValue();
|
||||
}
|
||||
|
||||
public CurrencyPairDictionary getCurrencyPairDictionaryBySecurityId(Long securityId) {
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.misc.Listing;
|
||||
import ru.clearing.classes.statics.data.misc.OrderCurrency;
|
||||
import ru.clearing.classes.statics.data.misc.SCrossRate;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.clearing.classes.statics.data.security.Rates;
|
||||
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
|
||||
import ru.spcex.clearing.dflt.management.model.CalculationResult;
|
||||
import ru.spcex.clearing.dflt.management.model.FinalCalculationResult;
|
||||
import ru.spcex.clearing.dflt.management.model.OrderCurrencyContext;
|
||||
import ru.spcex.platform.enumeration.CurrencyCode;
|
||||
import ru.spcex.platform.enumeration.SettleCode;
|
||||
|
|
@ -32,10 +32,10 @@ public class OrderCalculationService {
|
|||
this.transferDateService = transferDateService;
|
||||
}
|
||||
|
||||
public void calcAndEnrichSwap(OrderCurrency order,
|
||||
public FinalCalculationResult calcAndEnrichSwap(SettleCode settleCode,
|
||||
OrderCurrencyContext context) {
|
||||
Registry registry = context.getRegistry();
|
||||
Listing listing = imdgQueryService.findListing(registry, context.getMarket().getCode(), order.getSettleCode());
|
||||
Listing listing = imdgQueryService.findListing(registry, context.getMarket().getCode(), settleCode.getKey());
|
||||
|
||||
CurrencyPairDictionary pair = imdgQueryService.getCurrencyPairDictionaryBySecurityId(listing.getSecurityId());
|
||||
BigDecimal s = imdgQueryService.defineTransferRate(pair.getId(), registry.getSecuritySymbol());
|
||||
|
|
@ -46,16 +46,15 @@ public class OrderCalculationService {
|
|||
: calculationSums(registry, listing.getLotSize().intValue(), s, n);
|
||||
|
||||
BigDecimal quantityLot = result.sum3().abs();
|
||||
BigDecimal price = swapPriceCalc(pair.getBaseCurrency(), s, n);
|
||||
BigDecimal price = swapPriceCalc(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue());
|
||||
|
||||
order.setPrice(price);
|
||||
order.setQuantityLot(quantityLot);
|
||||
return new FinalCalculationResult(price, s, quantityLot, result);
|
||||
}
|
||||
|
||||
public void calcAndEnrichSpot(OrderCurrency order,
|
||||
OrderCurrencyContext context) {
|
||||
public FinalCalculationResult calcAndEnrichSpot(SettleCode settleCode,
|
||||
OrderCurrencyContext context) {
|
||||
Registry registry = context.getRegistry();
|
||||
Listing listing = imdgQueryService.findListing(registry, context.getMarket().getCode(), order.getSettleCode());
|
||||
Listing listing = imdgQueryService.findListing(registry, context.getMarket().getCode(), settleCode.getKey());
|
||||
|
||||
CurrencyPairDictionary pair = imdgQueryService.getCurrencyPairDictionaryBySecurityId(listing.getSecurityId());
|
||||
BigDecimal s = imdgQueryService.defineTransferRate(pair.getId(), registry.getSecuritySymbol());
|
||||
|
|
@ -68,32 +67,28 @@ public class OrderCalculationService {
|
|||
SCrossRate rates = imdgQueryService.getSCrossRates(pair.getBaseCurrency(), LocalDate.now());
|
||||
BigDecimal quantityLot;
|
||||
BigDecimal price;
|
||||
if (SettleCode.T0.equalsByKey(order.getSettleCode())) {
|
||||
if (SettleCode.T0 == settleCode) {
|
||||
quantityLot = result.sum3().abs();
|
||||
price = rates.getUnitRate();
|
||||
price = rates.getUnitRate().setScale(listing.getPrecision().intValue(), RoundingMode.HALF_UP);
|
||||
} else {
|
||||
quantityLot = result.sum5().abs();
|
||||
BigDecimal delta = swapPriceCalc(pair.getBaseCurrency(), s, n);
|
||||
price = rates.getUnitRate().add(delta);
|
||||
BigDecimal delta = swapPriceCalc(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue());
|
||||
price = rates.getUnitRate().add(delta).setScale(listing.getPrecision().intValue(), RoundingMode.HALF_UP);;
|
||||
}
|
||||
|
||||
order.setPrice(price);
|
||||
order.setQuantityLot(quantityLot);
|
||||
order.setRate(s);
|
||||
return new FinalCalculationResult(price, s, quantityLot, result);
|
||||
}
|
||||
|
||||
private CalculationResult calculationSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) {
|
||||
BigDecimal planPosition = registry.getBalance();
|
||||
BigDecimal sum1 = planPosition.abs();
|
||||
|
||||
Registry rubRegistry = imdgQueryService.findAmtRegistry(registry, "RUB");
|
||||
BigDecimal planPositionRub = rubRegistry.getBalance();
|
||||
|
||||
Rates rates = imdgQueryService.getRate(registry.getSecuritySymbol(), LocalDate.now());
|
||||
BigDecimal rateValue = rates.getValue();
|
||||
|
||||
BigDecimal sum2 = planPositionRub.divide(rateValue, lotSize, RoundingMode.HALF_DOWN);
|
||||
BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING);
|
||||
SCrossRate sCrossRates = imdgQueryService.getSCrossRates(registry.getSecuritySymbol(), LocalDate.now());
|
||||
if (sCrossRates == null) {
|
||||
throw new IllegalStateException(String.format("Not fond rate by security symbol: %s", CurrencyCode.CNY.getKey()));
|
||||
}
|
||||
BigDecimal rateValue = sCrossRates.getUnitRate();
|
||||
BigDecimal sum3 = mathCeil(sum1, lotSize);
|
||||
BigDecimal sum4 = sum3.multiply(rateValue, MC).negate();
|
||||
BigDecimal sum5 = sum3.negate();
|
||||
|
||||
|
|
@ -104,7 +99,7 @@ public class OrderCalculationService {
|
|||
|
||||
BigDecimal sum6 = sum3.multiply(rateValue, MC).multiply(multiplier, MC);
|
||||
|
||||
return new CalculationResult(sum1, sum2, sum3, sum4, sum5, sum6);
|
||||
return new CalculationResult(sum1, BigDecimal.ZERO, sum3, sum4, sum5, sum6);
|
||||
}
|
||||
|
||||
private CalculationResult calculationRubSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) {
|
||||
|
|
@ -115,13 +110,14 @@ public class OrderCalculationService {
|
|||
}
|
||||
BigDecimal rateValue = sCrossRates.getUnitRate();
|
||||
|
||||
BigDecimal sum1 = planPosition.divide(rateValue, MC);
|
||||
BigDecimal sum1 = planPosition.divide(rateValue, MC).abs();
|
||||
|
||||
Registry cnyRegistry = imdgQueryService.findAmtRegistry(registry, "CNY");
|
||||
BigDecimal planPositionCny = cnyRegistry.getBalance();
|
||||
Registry amtRegistry = imdgQueryService.findAmtRegistry(registry, "CNY");
|
||||
BigDecimal planPositionCny = amtRegistry.getBalance();
|
||||
|
||||
BigDecimal sum2 = planPositionCny.divide(rateValue, lotSize, RoundingMode.HALF_DOWN);
|
||||
BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING).min(sum2).negate();
|
||||
BigDecimal sum2 = planPositionCny.setScale(lotSize, RoundingMode.HALF_DOWN);
|
||||
BigDecimal y = sum1.min(sum2);
|
||||
BigDecimal sum3 = mathCeil(y, lotSize).negate();
|
||||
BigDecimal sum4 = sum3.multiply(rateValue, MC).negate();
|
||||
BigDecimal sum5 = sum3.negate();
|
||||
|
||||
|
|
@ -135,7 +131,7 @@ public class OrderCalculationService {
|
|||
return new CalculationResult(sum1, sum2, sum3, sum4, sum5, sum6);
|
||||
}
|
||||
|
||||
private BigDecimal swapPriceCalc(String baseCurrency, BigDecimal s, BigDecimal n) {
|
||||
private BigDecimal swapPriceCalc(String baseCurrency, BigDecimal s, BigDecimal n, int precision) {
|
||||
Rates rate = imdgQueryService.getRate(baseCurrency, LocalDate.now());
|
||||
BigDecimal p = BigDecimal.ONE.divide(n, MC);
|
||||
log.info("Calculation swap price: {}*{}*{}", s, n, p);
|
||||
|
|
@ -143,10 +139,14 @@ public class OrderCalculationService {
|
|||
.multiply(s, MC)
|
||||
.multiply(n, MC)
|
||||
.multiply(p, MC)
|
||||
.setScale(8, RoundingMode.HALF_UP);
|
||||
.setScale(precision, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private boolean isRub(Registry registry) {
|
||||
return "RUB".equals(registry.getSecuritySymbol());
|
||||
}
|
||||
|
||||
private BigDecimal mathCeil(BigDecimal val, Integer multiplicity) {
|
||||
return BigDecimal.valueOf(Math.ceil(val.doubleValue() / multiplicity));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import ru.clearing.classes.statics.data.misc.Market;
|
|||
import ru.clearing.classes.statics.data.misc.OrderCurrency;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.spcex.clearing.dflt.management.model.CounterpartyInfo;
|
||||
import ru.spcex.clearing.dflt.management.model.FinalCalculationResult;
|
||||
import ru.spcex.clearing.dflt.management.model.OrderCurrencyContext;
|
||||
import ru.spcex.platform.enumeration.SettleCode;
|
||||
import static ru.spcex.platform.enumeration.SettleCode.T0;
|
||||
|
|
@ -20,7 +21,9 @@ public class OrderTemplateBuilder {
|
|||
this.imdgQueryService = imdgQueryService;
|
||||
}
|
||||
|
||||
public OrderCurrency buildPrimaryTransfer(OrderCurrencyContext context, SettleCode settleCode) {
|
||||
public OrderCurrency buildPrimaryTransfer(OrderCurrencyContext context,
|
||||
SettleCode settleCode,
|
||||
FinalCalculationResult finalCalculationResult) {
|
||||
OrderCurrency orderCurrency;
|
||||
switch (context.getOrderCategory()) {
|
||||
case "PL" -> orderCurrency = buildPrimaryTransferPl(context);
|
||||
|
|
@ -28,11 +31,13 @@ public class OrderTemplateBuilder {
|
|||
default -> throw new IllegalArgumentException("Unsupported order category: " + context.getOrderCategory());
|
||||
}
|
||||
Side side = resolvePrimaryTransferSide(context.getRegistry(), settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "overnight", settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "overnight", settleCode, finalCalculationResult);
|
||||
return orderCurrency;
|
||||
}
|
||||
|
||||
public OrderCurrency buildCounterTransfer(OrderCurrencyContext context, SettleCode settleCode) {
|
||||
public OrderCurrency buildCounterTransfer(OrderCurrencyContext context,
|
||||
SettleCode settleCode,
|
||||
FinalCalculationResult finalCalculationResult) {
|
||||
OrderCurrency orderCurrency;
|
||||
switch (context.getOrderCategory()) {
|
||||
case "PL" -> orderCurrency = buildCounterTransferPl(context);
|
||||
|
|
@ -41,11 +46,13 @@ public class OrderTemplateBuilder {
|
|||
}
|
||||
;
|
||||
Side side = resolveCounterTransferSide(context.getRegistry(), settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "overnight", settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "overnight", settleCode, finalCalculationResult);
|
||||
return orderCurrency;
|
||||
}
|
||||
|
||||
public OrderCurrency buildPrimaryBalancing(OrderCurrencyContext context, SettleCode settleCode) {
|
||||
public OrderCurrency buildPrimaryBalancing(OrderCurrencyContext context,
|
||||
SettleCode settleCode,
|
||||
FinalCalculationResult finalCalculationResult) {
|
||||
OrderCurrency orderCurrency;
|
||||
switch (context.getOrderCategory()) {
|
||||
case "PL" -> orderCurrency = buildPrimaryBalancingPl(context);
|
||||
|
|
@ -54,11 +61,13 @@ public class OrderTemplateBuilder {
|
|||
}
|
||||
;
|
||||
Side side = resolvePrimaryBalancingSide(context.getRegistry(), settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "balance", settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "balance", settleCode, finalCalculationResult);
|
||||
return orderCurrency;
|
||||
}
|
||||
|
||||
public OrderCurrency buildCounterBalancing(OrderCurrencyContext context, SettleCode settleCode) {
|
||||
public OrderCurrency buildCounterBalancing(OrderCurrencyContext context,
|
||||
SettleCode settleCode,
|
||||
FinalCalculationResult finalCalculationResult) {
|
||||
OrderCurrency orderCurrency;
|
||||
switch (context.getOrderCategory()) {
|
||||
case "PL" -> orderCurrency = buildCounterBalancingPl(context);
|
||||
|
|
@ -67,7 +76,7 @@ public class OrderTemplateBuilder {
|
|||
}
|
||||
;
|
||||
Side side = resolveCounterBalancingSide(context.getRegistry(), settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "balance", settleCode);
|
||||
enrichOrder(orderCurrency, context, side, "balance", settleCode, finalCalculationResult);
|
||||
return orderCurrency;
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +204,8 @@ public class OrderTemplateBuilder {
|
|||
OrderCurrencyContext context,
|
||||
Side side,
|
||||
String comment,
|
||||
SettleCode settleCode) {
|
||||
SettleCode settleCode,
|
||||
FinalCalculationResult finalCalculationResult) {
|
||||
Registry registry = context.getRegistry();
|
||||
Market market = context.getMarket();
|
||||
Listing listing = imdgQueryService.findListing(registry, market.getCode(), settleCode.getKey());
|
||||
|
|
@ -212,28 +222,32 @@ public class OrderTemplateBuilder {
|
|||
order.setComment(comment);
|
||||
order.setRegistryId(registry.getId());
|
||||
order.setCreated(Instant.now());
|
||||
|
||||
order.setPrice(finalCalculationResult.price());
|
||||
order.setQuantityLot(finalCalculationResult.quantityLot());
|
||||
order.setRate(finalCalculationResult.rate());
|
||||
}
|
||||
|
||||
private Side resolvePrimaryTransferSide(Registry registry, SettleCode settleCode) {
|
||||
Side side = T0 == settleCode ? Side.BUY : Side.SELL;
|
||||
return isRub(registry) ? side : side.revers();
|
||||
}
|
||||
|
||||
private Side resolveCounterTransferSide(Registry registry, SettleCode settleCode) {
|
||||
public Side resolvePrimaryTransferSide(Registry registry, SettleCode settleCode) {
|
||||
Side side = T0 == settleCode ? Side.SELL : Side.BUY;
|
||||
return isRub(registry) ? side : side.revers();
|
||||
}
|
||||
|
||||
private Side resolvePrimaryBalancingSide(Registry registry, SettleCode settleCode) {
|
||||
Side side = T0 == settleCode ? Side.SELL : Side.BUY;
|
||||
public Side resolveCounterTransferSide(Registry registry, SettleCode settleCode) {
|
||||
Side side = T0 == settleCode ? Side.BUY : Side.SELL;
|
||||
return isRub(registry) ? side : side.revers();
|
||||
}
|
||||
|
||||
private Side resolveCounterBalancingSide(Registry registry, SettleCode settleCode) {
|
||||
public Side resolvePrimaryBalancingSide(Registry registry, SettleCode settleCode) {
|
||||
Side side = T0 == settleCode ? Side.BUY : Side.SELL;
|
||||
return isRub(registry) ? side : side.revers();
|
||||
}
|
||||
|
||||
public Side resolveCounterBalancingSide(Registry registry, SettleCode settleCode) {
|
||||
Side side = T0 == settleCode ? Side.SELL : Side.BUY;
|
||||
return isRub(registry) ? side : side.revers();
|
||||
}
|
||||
|
||||
private boolean isRub(Registry registry) {
|
||||
return "RUB".equals(registry.getSecuritySymbol());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ru.spcex.clearing.dflt.management.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -8,14 +9,17 @@ import ru.clearing.classes.statics.data.misc.OrderCurrency;
|
|||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.clearing.classes.statics.data.security.RiskParameter;
|
||||
import ru.spcex.clearing.dflt.management.model.CounterpartyInfo;
|
||||
import ru.spcex.clearing.dflt.management.model.FinalCalculationResult;
|
||||
import ru.spcex.clearing.dflt.management.model.OrderCurrencyContext;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.platform.enumeration.CompanyRole;
|
||||
import ru.spcex.platform.enumeration.CurrencyCode;
|
||||
import ru.spcex.platform.enumeration.OvernightType;
|
||||
import ru.spcex.platform.enumeration.RegistryStatus;
|
||||
import ru.spcex.platform.enumeration.SettleCode;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||
|
||||
@Service
|
||||
public class SpotOvernightOrderService {
|
||||
|
|
@ -46,6 +50,7 @@ public class SpotOvernightOrderService {
|
|||
CounterpartyInfo categoryP = imdgQueryService.getCompanyByClearingCategory("P");
|
||||
CounterpartyInfo clcc = imdgQueryService.getCompanyByRole(CompanyRole.CLCC);
|
||||
CounterpartyInfo rgcm = imdgQueryService.getCompanyByRole(CompanyRole.RGCM);
|
||||
CurrencyCode currency = IEnumKey.getEnumByKey(CurrencyCode.class, registry.getSecuritySymbol());
|
||||
|
||||
OrderCurrencyContext context = OrderCurrencyContext.builder()
|
||||
.registry(registry)
|
||||
|
|
@ -58,25 +63,23 @@ public class SpotOvernightOrderService {
|
|||
.overnightType(OvernightType.SPOT)
|
||||
.build();
|
||||
|
||||
OrderCurrency primaryTransferT0 = templateBuilder.buildPrimaryTransfer(context, SettleCode.T0);
|
||||
OrderCurrency counterTransferT0 = templateBuilder.buildCounterTransfer(context, SettleCode.T0);
|
||||
OrderCurrency primaryTransferT1 = templateBuilder.buildPrimaryTransfer(context, SettleCode.T1);
|
||||
OrderCurrency counterTransferT1 = templateBuilder.buildCounterTransfer(context, SettleCode.T1);
|
||||
FinalCalculationResult finalCalculationResultT0 = swapCalculationService.calcAndEnrichSpot(SettleCode.T0, context);
|
||||
FinalCalculationResult finalCalculationResultT1 = swapCalculationService.calcAndEnrichSpot(SettleCode.T1, context);
|
||||
|
||||
OrderCurrency primaryBalancingT0 = templateBuilder.buildPrimaryBalancing(context, SettleCode.T0);
|
||||
OrderCurrency counterBalancingT0 = templateBuilder.buildCounterBalancing(context, SettleCode.T0);
|
||||
OrderCurrency primaryBalancingT1 = templateBuilder.buildPrimaryBalancing(context, SettleCode.T1);
|
||||
OrderCurrency counterBalancingT1 = templateBuilder.buildCounterBalancing(context, SettleCode.T1);
|
||||
if (CurrencyCode.RUB == currency &&
|
||||
finalCalculationResultT0.calculationResult().sum3().compareTo(BigDecimal.ZERO) >= 0) {
|
||||
log.warn("QuantityLot greater than zero; skip forming order currency");
|
||||
return;
|
||||
}
|
||||
OrderCurrency primaryTransferT0 = templateBuilder.buildPrimaryTransfer(context, SettleCode.T0, finalCalculationResultT0);
|
||||
OrderCurrency counterTransferT0 = templateBuilder.buildCounterTransfer(context, SettleCode.T0, finalCalculationResultT0);
|
||||
OrderCurrency primaryTransferT1 = templateBuilder.buildPrimaryTransfer(context, SettleCode.T1, finalCalculationResultT1);
|
||||
OrderCurrency counterTransferT1 = templateBuilder.buildCounterTransfer(context, SettleCode.T1, finalCalculationResultT1);
|
||||
|
||||
swapCalculationService.calcAndEnrichSpot(primaryTransferT0, context);
|
||||
swapCalculationService.calcAndEnrichSpot(counterTransferT0, context);
|
||||
swapCalculationService.calcAndEnrichSpot(primaryTransferT1, context);
|
||||
swapCalculationService.calcAndEnrichSpot(counterTransferT1, context);
|
||||
|
||||
swapCalculationService.calcAndEnrichSpot(primaryBalancingT0, context);
|
||||
swapCalculationService.calcAndEnrichSpot(counterBalancingT0, context);
|
||||
swapCalculationService.calcAndEnrichSpot(primaryBalancingT1, context);
|
||||
swapCalculationService.calcAndEnrichSpot(counterBalancingT1, context);
|
||||
OrderCurrency primaryBalancingT0 = templateBuilder.buildPrimaryBalancing(context, SettleCode.T0, finalCalculationResultT0);
|
||||
OrderCurrency counterBalancingT0 = templateBuilder.buildCounterBalancing(context, SettleCode.T0, finalCalculationResultT0);
|
||||
OrderCurrency primaryBalancingT1 = templateBuilder.buildPrimaryBalancing(context, SettleCode.T1, finalCalculationResultT1);
|
||||
OrderCurrency counterBalancingT1 = templateBuilder.buildCounterBalancing(context, SettleCode.T1, finalCalculationResultT1);
|
||||
|
||||
orderCurrencyImdg.insert(primaryTransferT0);
|
||||
orderCurrencyImdg.insert(counterTransferT0);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ru.spcex.clearing.dflt.management.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -8,14 +9,17 @@ import ru.clearing.classes.statics.data.misc.OrderCurrency;
|
|||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.clearing.classes.statics.data.security.RiskParameter;
|
||||
import ru.spcex.clearing.dflt.management.model.CounterpartyInfo;
|
||||
import ru.spcex.clearing.dflt.management.model.FinalCalculationResult;
|
||||
import ru.spcex.clearing.dflt.management.model.OrderCurrencyContext;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.platform.enumeration.CompanyRole;
|
||||
import ru.spcex.platform.enumeration.CurrencyCode;
|
||||
import ru.spcex.platform.enumeration.OvernightType;
|
||||
import ru.spcex.platform.enumeration.RegistryStatus;
|
||||
import ru.spcex.platform.enumeration.SettleCode;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||
|
||||
@Service
|
||||
public class SwapOvernightOrderService {
|
||||
|
|
@ -46,7 +50,7 @@ public class SwapOvernightOrderService {
|
|||
CounterpartyInfo categoryP = imdgQueryService.getCompanyByClearingCategory("P");
|
||||
CounterpartyInfo clcc = imdgQueryService.getCompanyByRole(CompanyRole.CLCC);
|
||||
CounterpartyInfo rgcm = imdgQueryService.getCompanyByRole(CompanyRole.RGCM);
|
||||
|
||||
CurrencyCode currency = IEnumKey.getEnumByKey(CurrencyCode.class, registry.getSecuritySymbol());
|
||||
OrderCurrencyContext context = OrderCurrencyContext.builder()
|
||||
.registry(registry)
|
||||
.orderCategory(orderCategory)
|
||||
|
|
@ -58,15 +62,17 @@ public class SwapOvernightOrderService {
|
|||
.overnightType(OvernightType.SWAP)
|
||||
.build();
|
||||
|
||||
OrderCurrency primaryTransfer = templateBuilder.buildPrimaryTransfer(context, SettleCode.T1);
|
||||
OrderCurrency counterTransfer = templateBuilder.buildCounterTransfer(context, SettleCode.T1);
|
||||
OrderCurrency primaryBalancing = templateBuilder.buildPrimaryBalancing(context, SettleCode.T1);
|
||||
OrderCurrency counterBalancing = templateBuilder.buildCounterBalancing(context, SettleCode.T1);
|
||||
FinalCalculationResult finalCalculationResult = swapCalculationService.calcAndEnrichSwap(SettleCode.T1, context);
|
||||
if (CurrencyCode.RUB == currency &&
|
||||
finalCalculationResult.calculationResult().sum3().compareTo(BigDecimal.ZERO) >= 0) {
|
||||
log.warn("QuantityLot greater than zero; skip forming order currency");
|
||||
return;
|
||||
}
|
||||
|
||||
swapCalculationService.calcAndEnrichSwap(primaryTransfer, context);
|
||||
swapCalculationService.calcAndEnrichSwap(counterTransfer, context);
|
||||
swapCalculationService.calcAndEnrichSwap(primaryBalancing, context);
|
||||
swapCalculationService.calcAndEnrichSwap(counterBalancing, context);
|
||||
OrderCurrency primaryTransfer = templateBuilder.buildPrimaryTransfer(context, SettleCode.T1, finalCalculationResult);
|
||||
OrderCurrency counterTransfer = templateBuilder.buildCounterTransfer(context, SettleCode.T1, finalCalculationResult);
|
||||
OrderCurrency primaryBalancing = templateBuilder.buildPrimaryBalancing(context, SettleCode.T1, finalCalculationResult);
|
||||
OrderCurrency counterBalancing = templateBuilder.buildCounterBalancing(context, SettleCode.T1, finalCalculationResult);
|
||||
|
||||
orderCurrencyImdg.insert(primaryTransfer);
|
||||
orderCurrencyImdg.insert(counterTransfer);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package ru.spcex.clearing.dflt.service;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.spcex.clearing.dflt.management.service.OrderTemplateBuilder;
|
||||
import ru.spcex.platform.enumeration.SettleCode;
|
||||
import ru.spcex.platform.enumeration.Side;
|
||||
|
||||
public class OrderTemplateBuilderTest {
|
||||
|
||||
@Test
|
||||
public void testSwapNotRubT1() {
|
||||
OrderTemplateBuilder builder = new OrderTemplateBuilder(null);
|
||||
Assertions.assertEquals(Side.SELL, builder.resolvePrimaryTransferSide(createNotRubRegistry(), SettleCode.T1));
|
||||
Assertions.assertEquals(Side.BUY, builder.resolvePrimaryTransferSide(createRubRegistry(), SettleCode.T1));
|
||||
Assertions.assertEquals(Side.BUY, builder.resolvePrimaryTransferSide(createNotRubRegistry(), SettleCode.T0));
|
||||
Assertions.assertEquals(Side.SELL, builder.resolvePrimaryTransferSide(createNotRubRegistry(), SettleCode.T1));
|
||||
}
|
||||
|
||||
public static Registry createNotRubRegistry() {
|
||||
Registry registry = new Registry();
|
||||
registry.setSecuritySymbol("CNY");
|
||||
return registry;
|
||||
}
|
||||
|
||||
public static Registry createRubRegistry() {
|
||||
Registry registry = new Registry();
|
||||
registry.setSecuritySymbol("RUB");
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,47 @@
|
|||
package ru.spcex.clearing.fix.quickfix;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.regex.Pattern;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import quickfix.*;
|
||||
import quickfix.field.*;
|
||||
import quickfix.ConfigError;
|
||||
import quickfix.DoNotSend;
|
||||
import quickfix.FieldNotFound;
|
||||
import quickfix.IncorrectDataFormat;
|
||||
import quickfix.IncorrectTagValue;
|
||||
import quickfix.LogFactory;
|
||||
import quickfix.Message;
|
||||
import quickfix.MessageFactory;
|
||||
import quickfix.MessageStoreFactory;
|
||||
import quickfix.RejectLogon;
|
||||
import quickfix.Session;
|
||||
import quickfix.SessionID;
|
||||
import quickfix.SessionNotFound;
|
||||
import quickfix.SessionSettings;
|
||||
import quickfix.SocketInitiator;
|
||||
import quickfix.StringField;
|
||||
import quickfix.UnsupportedMessageType;
|
||||
import quickfix.field.Account;
|
||||
import quickfix.field.ClOrdID;
|
||||
import quickfix.field.ContraBroker;
|
||||
import quickfix.field.ExDestination;
|
||||
import quickfix.field.HandlInst;
|
||||
import quickfix.field.OrdStatus;
|
||||
import quickfix.field.OrdType;
|
||||
import quickfix.field.OrderQty;
|
||||
import quickfix.field.Price;
|
||||
import quickfix.field.SecurityID;
|
||||
import quickfix.field.SecurityIDSource;
|
||||
import quickfix.field.SettlType;
|
||||
import quickfix.field.Side;
|
||||
import quickfix.field.Text;
|
||||
import quickfix.field.TransactTime;
|
||||
import quickfix.fix44.ExecutionReport;
|
||||
import quickfix.fix44.MessageCracker;
|
||||
import quickfix.fix44.NewOrderSingle;
|
||||
|
|
@ -21,11 +55,6 @@ import ru.spcex.platform.imdg.api.Imdg;
|
|||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
import ru.spcex.platform.imdg.api.ImdgTransaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Service
|
||||
public class Application extends MessageCracker implements quickfix.Application, InitializingBean, DisposableBean {
|
||||
private static final Logger log = LoggerFactory.getLogger(Application.class);
|
||||
|
|
@ -113,25 +142,19 @@ public class Application extends MessageCracker implements quickfix.Application,
|
|||
ImdgTransaction transaction = imdgProvider.newTransaction();
|
||||
transaction.beginTransaction();
|
||||
try {
|
||||
if (executionReport.isSetField(OrderID.FIELD) && executionReport.isSetField(ExDestination.FIELD) && executionReport.isSetField(TransactTime.FIELD)) {
|
||||
OrderID orderId = executionReport.getOrderID();
|
||||
if (executionReport.isSetField(ClOrdID.FIELD) && executionReport.isSetField(ExDestination.FIELD) && executionReport.isSetField(TransactTime.FIELD) && executionReport.isSetField(OrdStatus.FIELD)) {
|
||||
// OrderID orderId = executionReport.getOrderID();
|
||||
ExDestination exDestination = (ExDestination) executionReport.getField(new ExDestination());
|
||||
TransactTime transactTime = executionReport.getTransactTime();
|
||||
SecurityID securityID = executionReport.getSecurityID();
|
||||
Price price = executionReport.getPrice();
|
||||
OrderQty orderQty = executionReport.getOrderQty();
|
||||
Account account = executionReport.getAccount();
|
||||
Side side = executionReport.getSide();
|
||||
Currency currency = executionReport.getCurrency();
|
||||
SettlType settlType = executionReport.getSettlType();
|
||||
OrdStatus ordStatus = executionReport.getOrdStatus();
|
||||
ClOrdID clOrdID = executionReport.getClOrdID();
|
||||
|
||||
Pattern orderIdPattern = Pattern.compile("(\\d{6})-([A-Z]+)-(\\d+)");
|
||||
Matcher matcher = orderIdPattern.matcher(orderId.getValue());
|
||||
if (matcher.matches()) {
|
||||
// Matcher matcher = orderIdPattern.matcher(orderId.getValue());
|
||||
// if (matcher.matches()) {
|
||||
// LocalDate tradeDate = LocalDate.parse(matcher.group(1), DateTimeFormatter.ofPattern("yyMMdd"));
|
||||
// String classCode = matcher.group(2);
|
||||
Long orderNum = Long.parseLong(matcher.group(3));
|
||||
Long orderNum = Long.parseLong(clOrdID.getValue());
|
||||
|
||||
Imdg<SOrders> sOrdersImdg = transaction.getImdg(IMDGDistributedNames.Map_SOrders, SOrders.class);
|
||||
SOrders sOrders = sOrdersImdg.getSingleObjectByPredicate(sOrdersImdg.predicateBuilder().and(
|
||||
|
|
@ -145,28 +168,36 @@ public class Application extends MessageCracker implements quickfix.Application,
|
|||
sOrders.setClassCode(exDestination.getValue());
|
||||
sOrders.setTradeDate(transactTime.getValue().toLocalDate());
|
||||
|
||||
sOrders.setSecCode(securityID.getValue());
|
||||
sOrders.setPrice(BigDecimal.valueOf(price.getValue()));
|
||||
sOrders.setQty(BigDecimal.valueOf(orderQty.getValue()));
|
||||
sOrders.setAccount(account.getValue());
|
||||
sOrders.setSettleCode(settlType.getValue());
|
||||
sOrders.setPriceCurrency(currency.getValue());
|
||||
sOrders.setState(String.valueOf(ordStatus.getValue()));
|
||||
if (executionReport.isSetSecurityID())
|
||||
sOrders.setSecCode(executionReport.getSecurityID().getValue());
|
||||
if (executionReport.isSetPrice())
|
||||
sOrders.setPrice(BigDecimal.valueOf(executionReport.getPrice().getValue()));
|
||||
if (executionReport.isSetOrderQty())
|
||||
sOrders.setQty(BigDecimal.valueOf(executionReport.getOrderQty().getValue()));
|
||||
if (executionReport.isSetAccount())
|
||||
sOrders.setAccount(executionReport.getAccount().getValue());
|
||||
if (executionReport.isSetSettlType())
|
||||
sOrders.setSettleCode(executionReport.getSettlType().getValue());
|
||||
if (executionReport.isSetCurrency())
|
||||
sOrders.setPriceCurrency(executionReport.getCurrency().getValue());
|
||||
|
||||
sOrders.setState(String.valueOf(ordStatus.getValue()));
|
||||
if (ordStatus.valueEquals(OrdStatus.NEW)) {
|
||||
sOrders.setOrderDateTime(transactTime.getValue().toInstant(ZoneOffset.UTC));
|
||||
} else if (ordStatus.valueEquals(OrdStatus.CANCELED)) {
|
||||
sOrders.setWithdrawDateTime(transactTime.getValue().toInstant(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
sOrders.setCreated(Instant.now());
|
||||
sOrdersImdg.insert(sOrders);
|
||||
} else {
|
||||
sOrders.setState(String.valueOf(ordStatus.getValue()));
|
||||
if (ordStatus.valueEquals(OrdStatus.NEW)) {
|
||||
sOrders.setOrderDateTime(transactTime.getValue().toInstant(ZoneOffset.UTC));
|
||||
} else if (ordStatus.valueEquals(OrdStatus.CANCELED)) {
|
||||
sOrders.setWithdrawDateTime(transactTime.getValue().toInstant(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
sOrders.setUpdated(Instant.now());
|
||||
sOrdersImdg.update(sOrders);
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +206,7 @@ public class Application extends MessageCracker implements quickfix.Application,
|
|||
updateRequest.addId(orderNum);
|
||||
kafkaSender.sendRequestToQueue(Consts.ORDER_CURRENCY_STATUS_UPDATE_FIX, updateRequest);
|
||||
}
|
||||
}
|
||||
// }
|
||||
transaction.commitTransaction();
|
||||
} catch (Exception e) {
|
||||
log.error(executionReport.toString(), e);
|
||||
|
|
@ -200,7 +231,7 @@ public class Application extends MessageCracker implements quickfix.Application,
|
|||
newOrderSingle.setField(new ContraBroker(orderCurrency.getCounterTradingCode()));
|
||||
newOrderSingle.set(new SettlType(orderCurrency.getSettleCode()));
|
||||
newOrderSingle.setField(new StringField(5018, orderCurrency.getTradingCode())); // FirmId
|
||||
|
||||
newOrderSingle.set(new HandlInst(HandlInst.AUTOMATED_EXECUTION_ORDER_PRIVATE_NO_BROKER_INTERVENTION));
|
||||
boolean result = Session.sendToTarget(newOrderSingle, fixSessionID);
|
||||
} catch (SessionNotFound sessionNotFound) {
|
||||
log.error(orderCurrency.toString(), sessionNotFound);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import java.math.BigDecimal;
|
|||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import ru.spcex.clearing.gatewayapi.config.deserializers.LocalDateDeserializer;
|
||||
import ru.spcex.clearing.gatewayapi.config.deserializers.LocalDateTimeV2Deserializer;
|
||||
import ru.spcex.clearing.gatewayapi.config.deserializers.LocalDateTimeDeserializer;
|
||||
|
||||
public class CurrencyRate {
|
||||
|
||||
|
|
@ -32,11 +32,11 @@ public class CurrencyRate {
|
|||
|
||||
private BigDecimal price;
|
||||
|
||||
@JsonDeserialize(using = LocalDateTimeV2Deserializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonProperty("update_date_time")
|
||||
private LocalDateTime updateDateTime;
|
||||
|
||||
@JsonDeserialize(using = LocalDateTimeV2Deserializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonProperty("source_date_time")
|
||||
private LocalDateTime sourceDateTime;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class RiskParameterMapStore extends TemplateMapStore<RiskParameter> {
|
|||
public String[] getFields() {
|
||||
return new String[]{
|
||||
"ID", "VALUE", "SETTLEMENT_TYPE", "CURRENCY_PAIR", "CURRENCY_PAIR_ID", "CREATED_AT", "UPDATED_AT", "WORKFLOW_STATUS",
|
||||
"QUOTE_VALUE"
|
||||
"QUOTE_VALUE", "PENALTY_VALUE"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -47,6 +47,7 @@ public class RiskParameterMapStore extends TemplateMapStore<RiskParameter> {
|
|||
object.setUpdated(getInstantFromTimestamp(resultSet, "UPDATED_AT"));
|
||||
object.setWorkflowStatus(resultSet.getObject("WORKFLOW_STATUS", String.class));
|
||||
object.setQuoteValue(resultSet.getObject("QUOTE_VALUE", BigDecimal.class));
|
||||
object.setPenaltyValue(resultSet.getObject("PENALTY_VALUE", BigDecimal.class));
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +62,8 @@ public class RiskParameterMapStore extends TemplateMapStore<RiskParameter> {
|
|||
TimeUtil.toDateFromInstant(object.getCreated()),
|
||||
TimeUtil.toDateFromInstant(object.getUpdated()),
|
||||
object.getWorkflowStatus(),
|
||||
object.getQuoteValue()
|
||||
object.getQuoteValue(),
|
||||
object.getPenaltyValue()
|
||||
};
|
||||
return args;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public class RiskParameterFacade implements IClearingFacade {
|
|||
riskParameter.setSettlementType(request.getSettlementType());
|
||||
riskParameter.setValue(request.getValue());
|
||||
riskParameter.setQuoteValue(request.getQuoteValue());
|
||||
riskParameter.setPenaltyValue(request.getPenaltyValue());
|
||||
riskParameter.setWorkflowStatus(request.getWorkflowStatus());
|
||||
riskParameter.setCreated(Instant.now());
|
||||
|
||||
|
|
@ -55,6 +56,7 @@ public class RiskParameterFacade implements IClearingFacade {
|
|||
|
||||
riskParameterForUpdate.setValue(request.getValue());
|
||||
riskParameterForUpdate.setQuoteValue(request.getQuoteValue());
|
||||
riskParameterForUpdate.setPenaltyValue(request.getPenaltyValue());
|
||||
riskParameterForUpdate.setWorkflowStatus(request.getWorkflowStatus());
|
||||
|
||||
riskParameterImdg.update(riskParameterForUpdate);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package ru.spcex.platform.imdg.validation.rule;
|
|||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.spcex.platform.classes.base.SpcexObjectBase;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
|
||||
|
|
@ -10,6 +12,7 @@ import ru.spcex.platform.utils.enumeration.EnumMessage;
|
|||
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||
|
||||
public class PresentByPredicate<T> implements IValidationRule<ImdgValidationContext<T>> {
|
||||
private static final Logger log = LoggerFactory.getLogger(PresentByPredicate.class);
|
||||
|
||||
private final String mapName;
|
||||
private final Function<T, EnumMessage> errorProvider;
|
||||
|
|
@ -42,8 +45,10 @@ public class PresentByPredicate<T> implements IValidationRule<ImdgValidationCont
|
|||
|
||||
if (obj == null) {
|
||||
EnumMessage errMsg = errorProvider.apply(validatedObject);
|
||||
log.debug("object not found by predicate: {}", predicate);
|
||||
return Optional.of(errMsg);
|
||||
}
|
||||
log.debug("object found by predicate [{}]: {}.id={}", predicate, mapName, obj.getId());
|
||||
|
||||
if (storeEnabled != null) {
|
||||
context.storeObject(storeEnabled, obj);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ public class RiskParameterNewRequest {
|
|||
@JsonProperty
|
||||
private BigDecimal quoteValue;
|
||||
@JsonProperty
|
||||
private BigDecimal penaltyValue;
|
||||
@JsonProperty
|
||||
private String settlementType;
|
||||
@JsonProperty
|
||||
private Long currencyPairId;
|
||||
|
|
@ -55,4 +57,12 @@ public class RiskParameterNewRequest {
|
|||
public void setWorkflowStatus(String status) {
|
||||
this.workflowStatus = status;
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyValue() {
|
||||
return penaltyValue;
|
||||
}
|
||||
|
||||
public void setPenaltyValue(BigDecimal penaltyValue) {
|
||||
this.penaltyValue = penaltyValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ public class RiskParameterUpdateRequest {
|
|||
@JsonProperty
|
||||
private BigDecimal quoteValue;
|
||||
@JsonProperty
|
||||
private BigDecimal penaltyValue;
|
||||
@JsonProperty
|
||||
private String workflowStatus;
|
||||
|
||||
public Long getId() {
|
||||
|
|
@ -45,4 +47,12 @@ public class RiskParameterUpdateRequest {
|
|||
public void setWorkflowStatus(String status) {
|
||||
this.workflowStatus = status;
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyValue() {
|
||||
return penaltyValue;
|
||||
}
|
||||
|
||||
public void setPenaltyValue(BigDecimal penaltyValue) {
|
||||
this.penaltyValue = penaltyValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue