From be0d90a2104f2c1174077044ed283fb86f0f6d37 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 12:42:53 +0300 Subject: [PATCH 01/28] http://jira.mfd.msk:8088/browse/CLS-943 --- .../management/service/ImdgQueryService.java | 2 +- .../service/OrderCalculationService.java | 13 +++++--- .../service/OrderTemplateBuilder.java | 18 +++++------ .../service/OrderTemplateBuilderTest.java | 32 +++++++++++++++++++ 4 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 clearing-parent/default-management/src/test/java/ru/spcex/clearing/dflt/service/OrderTemplateBuilderTest.java diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java index 8f891adeb..e6da65351 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java @@ -217,7 +217,7 @@ public class ImdgQueryService { pb.equals("currencyPairId", currencyPairDictionaryId) ) ); - return isRub ? riskParameter.getValue() : riskParameter.getQuoteValue(); + return isRub ? riskParameter.getQuoteValue() : riskParameter.getValue(); } public CurrencyPairDictionary getCurrencyPairDictionaryBySecurityId(Long securityId) { diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java index 17c860266..af5d89260 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java @@ -50,6 +50,7 @@ public class OrderCalculationService { order.setPrice(price); order.setQuantityLot(quantityLot); + order.setRate(s); } public void calcAndEnrichSpot(OrderCurrency order, @@ -90,8 +91,12 @@ public class OrderCalculationService { BigDecimal planPositionRub = rubRegistry.getBalance(); Rates rates = imdgQueryService.getRate(registry.getSecuritySymbol(), LocalDate.now()); - BigDecimal rateValue = rates.getValue(); + 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 sum2 = planPositionRub.divide(rateValue, lotSize, RoundingMode.HALF_DOWN); BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING); BigDecimal sum4 = sum3.multiply(rateValue, MC).negate(); @@ -117,10 +122,10 @@ public class OrderCalculationService { BigDecimal sum1 = planPosition.divide(rateValue, MC); - 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 sum2 = planPositionCny.setScale(lotSize, RoundingMode.HALF_DOWN); BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING).min(sum2).negate(); BigDecimal sum4 = sum3.multiply(rateValue, MC).negate(); BigDecimal sum5 = sum3.negate(); diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java index 2af0fa2ef..03faf6e79 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java @@ -214,26 +214,26 @@ public class OrderTemplateBuilder { order.setCreated(Instant.now()); } - 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()); } diff --git a/clearing-parent/default-management/src/test/java/ru/spcex/clearing/dflt/service/OrderTemplateBuilderTest.java b/clearing-parent/default-management/src/test/java/ru/spcex/clearing/dflt/service/OrderTemplateBuilderTest.java new file mode 100644 index 000000000..38bb174a2 --- /dev/null +++ b/clearing-parent/default-management/src/test/java/ru/spcex/clearing/dflt/service/OrderTemplateBuilderTest.java @@ -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; + } +} From c8cb1faaa8fbfe49f3657f7bd92e7679dae516c2 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 13:23:25 +0300 Subject: [PATCH 02/28] http://jira.mfd.msk:8088/browse/CLS-979 --- .../controller/queue/register/RegistryController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/register/RegistryController.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/register/RegistryController.java index 0fefc1160..77f2cfbb7 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/register/RegistryController.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/register/RegistryController.java @@ -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) From f539b93a9421451ca38240f4c2ba1cd7f2d92ecb Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 14:11:13 +0300 Subject: [PATCH 03/28] http://jira.mfd.msk:8088/browse/CLS-950 --- .../cud/securities/RiskParameterNewAction.java | 10 +++++++++- .../securities/RiskParameterUpdateAction.java | 14 +++++++++++++- .../src/main/resources/meta/meta.json | 18 +++++++++++++++--- .../src/main/resources/meta/meta.xml | 9 ++++++--- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterNewAction.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterNewAction.java index 74b308982..466bb6a08 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterNewAction.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterNewAction.java @@ -12,9 +12,12 @@ public class RiskParameterNewAction implements IAction @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 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 public void setWorkflowStatus(String workflowStatus) { this.workflowStatus = workflowStatus; } + + public void setPenaltyValue(BigDecimal penaltyValue) { + this.penaltyValue = penaltyValue; + } } diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterUpdateAction.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterUpdateAction.java index 581628feb..6c3d9f073 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterUpdateAction.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/request/cud/securities/RiskParameterUpdateAction.java @@ -15,9 +15,12 @@ public class RiskParameterUpdateAction implements IAction - + @@ -2570,19 +2570,22 @@ + - + + - + + From 144e23cb6e9dea4f4cc95eb26d3e867a42644160 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 14:14:00 +0300 Subject: [PATCH 04/28] http://jira.mfd.msk:8088/browse/CLS-951 --- .../classes/statics/data/security/RiskParameter.java | 9 +++++++++ clearing-parent/db-scripts/src/main/resources/db/DDL.sql | 9 +++++++-- .../db-scripts/src/main/resources/db/updateDDL_3.23.sql | 2 ++ .../clearing/imdg/object/RiskParameterMapStore.java | 6 ++++-- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/RiskParameter.java b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/RiskParameter.java index 7eb083de2..cbafa813f 100644 --- a/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/RiskParameter.java +++ b/clearing-parent/classes/src/main/java/ru/clearing/classes/statics/data/security/RiskParameter.java @@ -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; + } } diff --git a/clearing-parent/db-scripts/src/main/resources/db/DDL.sql b/clearing-parent/db-scripts/src/main/resources/db/DDL.sql index 1f8a0abba..09ea748a4 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/DDL.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/DDL.sql @@ -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 'Заявки для заключения сделок переноса на валютном рынке'; diff --git a/clearing-parent/db-scripts/src/main/resources/db/updateDDL_3.23.sql b/clearing-parent/db-scripts/src/main/resources/db/updateDDL_3.23.sql index 421745ac9..0ec389bcb 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/updateDDL_3.23.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/updateDDL_3.23.sql @@ -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 'Идентификатор регистра'; diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/RiskParameterMapStore.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/RiskParameterMapStore.java index 3f0ed06b1..3e453fc06 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/RiskParameterMapStore.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/RiskParameterMapStore.java @@ -31,7 +31,7 @@ public class RiskParameterMapStore extends TemplateMapStore { 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 { 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 { TimeUtil.toDateFromInstant(object.getCreated()), TimeUtil.toDateFromInstant(object.getUpdated()), object.getWorkflowStatus(), - object.getQuoteValue() + object.getQuoteValue(), + object.getPenaltyValue() }; return args; } From 24bb9d39662acdcef46ed9c8278aa684f44447f4 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 14:14:33 +0300 Subject: [PATCH 05/28] http://jira.mfd.msk:8088/browse/CLS-954 --- .../securities/service/facade/RiskParameterFacade.java | 2 ++ .../domain/cud/security/RiskParameterNewRequest.java | 10 ++++++++++ .../cud/security/RiskParameterUpdateRequest.java | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/facade/RiskParameterFacade.java b/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/facade/RiskParameterFacade.java index dc0058614..b9b9c4ae8 100644 --- a/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/facade/RiskParameterFacade.java +++ b/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/facade/RiskParameterFacade.java @@ -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); diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterNewRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterNewRequest.java index b910fc5d5..f3a52f224 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterNewRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterNewRequest.java @@ -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; + } } diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterUpdateRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterUpdateRequest.java index fde0f985f..4c9458eb4 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterUpdateRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/security/RiskParameterUpdateRequest.java @@ -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; + } } From b3d01c17eafa3939c97728207792027991ddcea5 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 14:41:08 +0300 Subject: [PATCH 06/28] fix sendOrder handlInst --- .../main/java/ru/spcex/clearing/fix/quickfix/Application.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java index af4d01e09..5132432e0 100644 --- a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java +++ b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java @@ -200,7 +200,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); From b1b2cd7a499fd0a8e481c94f97f5134b6a1f6b24 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 14:44:47 +0300 Subject: [PATCH 07/28] fix meta name for quoteValue --- .../backend-api/src/main/resources/meta/meta.json | 8 ++++---- .../backend-api/src/main/resources/meta/meta.xml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.json b/clearing-parent/backend-api/src/main/resources/meta/meta.json index 18afaf230..108699223 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.json +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.json @@ -1,6 +1,6 @@ { - "version": "3.23.295.166", + "version": "3.23.295.167", "enums": { @@ -11095,7 +11095,7 @@ } , {"code": "quoteValue", - "name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10 + "name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10 } , {"code": "workflowStatus", @@ -11129,7 +11129,7 @@ } , {"code": "quoteValue", - "name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10 + "name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10 } , {"code": "workflowStatus", @@ -11160,7 +11160,7 @@ } , {"code": "quoteValue", - "name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10 + "name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10 } , {"code": "workflowStatus", diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.xml b/clearing-parent/backend-api/src/main/resources/meta/meta.xml index 3378f64fc..3a2b87b44 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.xml @@ -1,6 +1,6 @@ - + @@ -2571,7 +2571,7 @@ - + @@ -2579,14 +2579,14 @@ - + - + From 9223d8b391863dbdeaf21b23a8f1e71686f4e097 Mon Sep 17 00:00:00 2001 From: ialbert Date: Wed, 29 Apr 2026 15:05:20 +0300 Subject: [PATCH 08/28] http://jira.mfd.msk:8088/browse/CLS-981 --- .../clearing/config/ValidationConfig.java | 92 ++++++++- .../clearing/service/EventsReceiver.java | 9 +- .../payment/WithdrawalFundsService.java | 192 ++++++++++++++++++ .../WithdrawalFundsValidationRule.java | 69 +++++++ .../WithdrawalFundsValidationStore.java | 10 + .../validation/rule/PresentByPredicate.java | 5 + 6 files changed, 375 insertions(+), 2 deletions(-) create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java index 049b76667..1a1fde574 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java @@ -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 pmtImdg; Imdg 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,81 @@ public class ValidationConfig { }; } + @Bean("withdrawalFundsValidator") + public Function withdrawalFundsValidator() { + return identificationFundsRequest -> { + ImdgValidationContext 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) 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>() { + @Override + public Optional validate(ImdgValidationContext ctx) { + Company cmp = ctx.getStoredObject(WithdrawalFundsValidationStore.Company); + Account acc = ctx.getStoredObject(WithdrawalFundsValidationStore.Account); + Optional 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, + WithdrawalFundsValidationRule.TcrPresent + ); + }; + } + @Bean("splitDepositValidator") public Function splitDepositValidator() { return refundDateRequest -> { diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java index 5a4698be4..ebab4d998 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java @@ -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); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java new file mode 100644 index 000000000..5a6da932a --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java @@ -0,0 +1,192 @@ +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.TradingClearingRegistry; +import ru.clearing.classes.statics.data.sdf.SDf54; +import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.BaseRequest; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.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.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.log.ExceptionUtils; +import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD; +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 withdrawalFundsVal; + private final Sdf54Creator sdf54Creator; + private final Imdg sdf54Imdg; + private final Imdg pmtImdg; + private final KafkaSender kafkaSender; + private final ImdgId idGen; + private final RequestHelper reqHelp; + private final UserRoleVerification rights; + private final IMessageResolver msgResolver; + private final AssetTBFProcessing assetsMng; + private final DmiService dmiService; + + public WithdrawalFundsService(Function withdrawalFundsVal, Sdf54Creator sdf54Creator, ImdgProvider imdgProvider, KafkaSender kafkaSender, RequestHelper reqHelp, UserRoleVerification rights, IMessageResolver msgResolver, 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.idGen = imdgProvider.getImdgIdGenerator(); + this.reqHelp = reqHelp; + this.rights = rights; + this.msgResolver = msgResolver; + this.assetsMng = assetsMng; + this.dmiService = dmiService; + } + + public RequestInfoUpdate withdrawalFunds(BaseRequest 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 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); + TradingClearingRegistry tcr = validator.getStored(WithdrawalFundsValidationStore.TCR); + 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()); + + dmiService.setProcComment(tcr.getId(), + curr, + safeBD(payload.getAmount()).negate(), + sDf54.getDocnm_ref()); + log.debug("recalculating assests..."); + 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 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 "Вывод средств с регистра невыясненных денежных средств по %s" + .formatted(payload.getSecuritySymbol()); + } else { + return "Withdrawal of funds from the register %s of unidentified funds" + .formatted(payload.getSecuritySymbol()); + } + } + +} + diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java new file mode 100644 index 000000000..9d27ac50a --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java @@ -0,0 +1,69 @@ +package ru.spcex.clearing.service.validation; + +import java.math.BigDecimal; +import java.util.Objects; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistryList; +import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest; +import ru.spcex.clearing.service.AnltSearcher; +import ru.spcex.clearing.service.TcrSearcher; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +public enum WithdrawalFundsValidationRule implements IValidationRule> { + Fields() { + @Override + public Optional validate(ImdgValidationContext 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"); + } + return empty(); + } + }, + TcrPresent() { + @Override + public Optional validate(ImdgValidationContext context) { + Account accCred = context.getStoredObject(WithdrawalFundsValidationStore.Account); + Company addressee = context.getStoredObject(WithdrawalFundsValidationStore.Company); + Imdg tcrImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); + Imdg tcrListImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class); + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + Imdg accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); + TcrSearcher tcrSearcher = new TcrSearcher(tcrImdg, tcrListImdg, companyImdg, accountImdg); + AnltSearcher.AnltSearch srchRes = tcrSearcher.searchByAccountId(accCred.getId(), accCred.getCurrency()); + if (!srchRes.isFound()) { + return Optional.of(srchRes.getError()); + } + if (srchRes.getCompany() != null) { + if (!Objects.equals(srchRes.getCompany().getId(), addressee.getId())) { + return of(ClearingError.AccountIsNotMatchedWithCompany, accCred.getId(), addressee.getId()); + } + } + TradingClearingRegistry tcr = srchRes.getTcr(); + if (tcr == null) { + return of(ClearingError.RecordNotFound, "TCR"); + } + context.storeObject(WithdrawalFundsValidationStore.TCR, tcr); + return Optional.empty(); + } + }; + private final static Logger log = LoggerFactory.getLogger(WithdrawalFundsValidationRule.class); + + @Override + public String ruleName() { + return "WithdrawalFundsValidationRule." + name(); + } +} \ No newline at end of file diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java new file mode 100644 index 000000000..55882c5e1 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java @@ -0,0 +1,10 @@ +package ru.spcex.clearing.service.validation; + +public enum WithdrawalFundsValidationStore { + CompanySymbol, + Company, + Account, + AssetTrio, + TCR, + ; +} diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/validation/rule/PresentByPredicate.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/validation/rule/PresentByPredicate.java index 5269785bc..c38ec4be8 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/validation/rule/PresentByPredicate.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/validation/rule/PresentByPredicate.java @@ -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 implements IValidationRule> { + private static final Logger log = LoggerFactory.getLogger(PresentByPredicate.class); private final String mapName; private final Function errorProvider; @@ -42,8 +45,10 @@ public class PresentByPredicate implements IValidationRule Date: Wed, 29 Apr 2026 15:12:28 +0300 Subject: [PATCH 09/28] http://jira.mfd.msk:8088/browse/CLS-943 --- .../management/listener/TaskListener.java | 3 +- .../model/FinalCalculationResult.java | 10 ++++++ .../management/service/ImdgQueryService.java | 3 +- .../service/OrderCalculationService.java | 22 ++++++------- .../service/OrderTemplateBuilder.java | 32 +++++++++++++------ .../service/SpotOvernightOrderService.java | 29 +++++++---------- .../service/SwapOvernightOrderService.java | 19 ++++++----- 7 files changed, 67 insertions(+), 51 deletions(-) create mode 100644 clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java index 05468783f..91590fd68 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java @@ -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 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) { diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java new file mode 100644 index 000000000..60a8b246b --- /dev/null +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java @@ -0,0 +1,10 @@ +package ru.spcex.clearing.dflt.management.model; + +import java.math.BigDecimal; + +public record FinalCalculationResult( + BigDecimal price, + BigDecimal rate, + BigDecimal quantityLot +) { +} \ No newline at end of file diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java index e6da65351..e400d01ea 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/ImdgQueryService.java @@ -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.getQuoteValue() : riskParameter.getValue(); + return isRub ? riskParameter.getQuoteValue() : riskParameter.getPenaltyValue(); } public CurrencyPairDictionary getCurrencyPairDictionaryBySecurityId(Long securityId) { diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java index af5d89260..f57e7388e 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java @@ -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()); @@ -48,15 +48,13 @@ public class OrderCalculationService { BigDecimal quantityLot = result.sum3().abs(); BigDecimal price = swapPriceCalc(pair.getBaseCurrency(), s, n); - order.setPrice(price); - order.setQuantityLot(quantityLot); - order.setRate(s); + return new FinalCalculationResult(price, s, quantityLot); } - 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()); @@ -69,7 +67,7 @@ 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(); } else { @@ -78,9 +76,7 @@ public class OrderCalculationService { price = rates.getUnitRate().add(delta); } - order.setPrice(price); - order.setQuantityLot(quantityLot); - order.setRate(s); + return new FinalCalculationResult(price, s, quantityLot); } private CalculationResult calculationSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) { diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java index 03faf6e79..bbc744c44 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderTemplateBuilder.java @@ -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,6 +222,10 @@ 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()); } public Side resolvePrimaryTransferSide(Registry registry, SettleCode settleCode) { diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java index 9b9991915..e7bb83d53 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java @@ -8,6 +8,7 @@ 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; @@ -58,25 +59,17 @@ 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 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); - 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); - - 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); diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java index 67f95849c..dd9b5d6e6 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java @@ -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,6 +9,7 @@ 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; @@ -58,15 +60,16 @@ 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 (finalCalculationResult.quantityLot().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); From b289104d325ac46efbe2376278c90bd12fb861cf Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 16:15:32 +0300 Subject: [PATCH 10/28] update MARKET_LCC.sql --- .../db-scripts/src/main/resources/db/MARKET_LCC.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clearing-parent/db-scripts/src/main/resources/db/MARKET_LCC.sql b/clearing-parent/db-scripts/src/main/resources/db/MARKET_LCC.sql index 8bbec5f24..5546656b4 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/MARKET_LCC.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/MARKET_LCC.sql @@ -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; \ No newline at end of file +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; \ No newline at end of file From 5b0438f99bbddfbc7ab84fc6b5ed98c39dc75bd6 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 16:16:51 +0300 Subject: [PATCH 11/28] fix meta [market for orderCurrency] --- .../backend-api/src/main/resources/meta/meta.json | 6 +++--- .../backend-api/src/main/resources/meta/meta.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.json b/clearing-parent/backend-api/src/main/resources/meta/meta.json index 108699223..5ed265db6 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.json +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.json @@ -1,6 +1,6 @@ { - "version": "3.23.295.167", + "version": "3.23.295.168", "enums": { @@ -11755,7 +11755,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", @@ -11843,7 +11843,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", diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.xml b/clearing-parent/backend-api/src/main/resources/meta/meta.xml index 3a2b87b44..fbc0ce044 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.xml @@ -1,6 +1,6 @@ - + @@ -2729,7 +2729,7 @@ - + @@ -2751,7 +2751,7 @@ - + From 31c54dae8f0968d644d99f32d6f582e897eef726 Mon Sep 17 00:00:00 2001 From: mmarkelov Date: Wed, 29 Apr 2026 16:26:27 +0300 Subject: [PATCH 12/28] fix ExecutionReport checking field values --- .../clearing/fix/quickfix/Application.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java index 5132432e0..a6df06253 100644 --- a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java +++ b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java @@ -113,17 +113,10 @@ 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)) { + if (executionReport.isSetField(OrderID.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(); Pattern orderIdPattern = Pattern.compile("(\\d{6})-([A-Z]+)-(\\d+)"); @@ -145,14 +138,20 @@ 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)) { @@ -161,6 +160,7 @@ public class Application extends MessageCracker implements quickfix.Application, 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)) { From e862ca4703fc324e0c45a9e37815325d7cf6ee90 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 16:41:15 +0300 Subject: [PATCH 13/28] set precision for price --- .../management/service/OrderCalculationService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java index f57e7388e..90a37270b 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java @@ -46,7 +46,7 @@ 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()); return new FinalCalculationResult(price, s, quantityLot); } @@ -69,11 +69,11 @@ public class OrderCalculationService { BigDecimal price; 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);; } return new FinalCalculationResult(price, s, quantityLot); @@ -136,7 +136,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); @@ -144,7 +144,7 @@ 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) { From 18542d067228acd9eac28dac2c323e29890fe29f Mon Sep 17 00:00:00 2001 From: ialbert Date: Wed, 29 Apr 2026 18:19:40 +0300 Subject: [PATCH 14/28] http://jira.mfd.msk:8088/browse/CLS-981 --- .../clearing/config/ValidationConfig.java | 3 +- .../clearing/messages/ClearingMessage.java | 1 + .../payment/WithdrawalFundsService.java | 28 +++++++------- .../WithdrawalFundsValidationRule.java | 37 +------------------ .../WithdrawalFundsValidationStore.java | 1 - .../ru/spcex/clearing/util/LocaleUtil.java | 4 +- .../messages/clearing_eng.properties | 3 +- .../resources/messages/clearing_ru.properties | 3 +- 8 files changed, 24 insertions(+), 56 deletions(-) diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java index 1a1fde574..bdce7f0da 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java @@ -483,8 +483,7 @@ public class ValidationConfig { cmpSymbCheck, cmpCheck, accCheck, - assetPresent, - WithdrawalFundsValidationRule.TcrPresent + assetPresent ); }; } diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/messages/ClearingMessage.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/messages/ClearingMessage.java index cf150d1ff..d349eb641 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/messages/ClearingMessage.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/messages/ClearingMessage.java @@ -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; diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java index 5a6da932a..72b75624a 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java @@ -12,10 +12,11 @@ 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.TradingClearingRegistry; +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; @@ -28,6 +29,7 @@ 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; @@ -39,8 +41,8 @@ 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 static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD; import ru.spcex.platform.utils.text.TextUtil; import ru.spcex.platform.utils.time.TimeUtil; import ru.spcex.platform.utils.validation.IValidator; @@ -52,24 +54,28 @@ public class WithdrawalFundsService { private final Sdf54Creator sdf54Creator; private final Imdg sdf54Imdg; private final Imdg pmtImdg; + private final Imdg 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 withdrawalFundsVal, Sdf54Creator sdf54Creator, ImdgProvider imdgProvider, KafkaSender kafkaSender, RequestHelper reqHelp, UserRoleVerification rights, IMessageResolver msgResolver, AssetTBFProcessing assetsMng, DmiService dmiService) { + public WithdrawalFundsService(Function 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; } @@ -93,7 +99,6 @@ public class WithdrawalFundsService { Company cmp = validator.getStored(WithdrawalFundsValidationStore.Company); Account acc = validator.getStored(WithdrawalFundsValidationStore.Account); AssetTrio assets = validator.getStored(WithdrawalFundsValidationStore.AssetTrio); - TradingClearingRegistry tcr = validator.getStored(WithdrawalFundsValidationStore.TCR); String curr = TextUtil.isEmpty(payload.getSecuritySymbol()) ? CurrencyCode.RUB.getKey() : payload.getSecuritySymbol(); Instant now = Instant.now(); @@ -152,11 +157,10 @@ public class WithdrawalFundsService { sdf54Imdg.insert(sDf54); log.info("created sdf54.id={}", sDf54.getId()); - dmiService.setProcComment(tcr.getId(), - curr, - safeBD(payload.getAmount()).negate(), - sDf54.getDocnm_ref()); - log.debug("recalculating assests..."); + Registry d__i = dmiService.createDmi(payload.getAmount(), 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(); @@ -180,11 +184,9 @@ public class WithdrawalFundsService { return payload.getPaymentPurpose(); } if (CurrencyCode.RUB.equalsByKey(payload.getSecuritySymbol())) { - return "Вывод средств с регистра невыясненных денежных средств по %s" - .formatted(payload.getSecuritySymbol()); + return localizer.resolve(ClearingMessage.withdrawalOfFundsDmau, LocaleUtil.ru, payload.getSecuritySymbol()); } else { - return "Withdrawal of funds from the register %s of unidentified funds" - .formatted(payload.getSecuritySymbol()); + return localizer.resolve(ClearingMessage.withdrawalOfFundsDmau, LocaleUtil.eng, payload.getSecuritySymbol()); } } diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java index 9d27ac50a..652a1030f 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java @@ -1,20 +1,11 @@ package ru.spcex.clearing.service.validation; import java.math.BigDecimal; -import java.util.Objects; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ru.clearing.classes.statics.data.account.Account; -import ru.clearing.classes.statics.data.company.Company; -import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; -import ru.clearing.classes.statics.data.registry.TradingClearingRegistryList; import ru.spcex.clearing.error.ClearingError; -import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest; -import ru.spcex.clearing.service.AnltSearcher; -import ru.spcex.clearing.service.TcrSearcher; -import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.validation.IValidationRule; @@ -33,33 +24,7 @@ public enum WithdrawalFundsValidationRule implements IValidationRule validate(ImdgValidationContext context) { - Account accCred = context.getStoredObject(WithdrawalFundsValidationStore.Account); - Company addressee = context.getStoredObject(WithdrawalFundsValidationStore.Company); - Imdg tcrImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); - Imdg tcrListImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class); - Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); - Imdg accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); - TcrSearcher tcrSearcher = new TcrSearcher(tcrImdg, tcrListImdg, companyImdg, accountImdg); - AnltSearcher.AnltSearch srchRes = tcrSearcher.searchByAccountId(accCred.getId(), accCred.getCurrency()); - if (!srchRes.isFound()) { - return Optional.of(srchRes.getError()); - } - if (srchRes.getCompany() != null) { - if (!Objects.equals(srchRes.getCompany().getId(), addressee.getId())) { - return of(ClearingError.AccountIsNotMatchedWithCompany, accCred.getId(), addressee.getId()); - } - } - TradingClearingRegistry tcr = srchRes.getTcr(); - if (tcr == null) { - return of(ClearingError.RecordNotFound, "TCR"); - } - context.storeObject(WithdrawalFundsValidationStore.TCR, tcr); - return Optional.empty(); - } - }; + ; private final static Logger log = LoggerFactory.getLogger(WithdrawalFundsValidationRule.class); @Override diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java index 55882c5e1..40298589b 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationStore.java @@ -5,6 +5,5 @@ public enum WithdrawalFundsValidationStore { Company, Account, AssetTrio, - TCR, ; } diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/LocaleUtil.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/LocaleUtil.java index 864b5a36d..344cf512c 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/LocaleUtil.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/LocaleUtil.java @@ -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); diff --git a/clearing-parent/clearing-service/src/main/resources/messages/clearing_eng.properties b/clearing-parent/clearing-service/src/main/resources/messages/clearing_eng.properties index 7ddb3cb64..69a334b22 100644 --- a/clearing-parent/clearing-service/src/main/resources/messages/clearing_eng.properties +++ b/clearing-parent/clearing-service/src/main/resources/messages/clearing_eng.properties @@ -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 \ No newline at end of file +sdf54.urgent=urgent +withdrawal.funds.dmau=Withdrawal of funds from the register {0} of unidentified funds \ No newline at end of file diff --git a/clearing-parent/clearing-service/src/main/resources/messages/clearing_ru.properties b/clearing-parent/clearing-service/src/main/resources/messages/clearing_ru.properties index a411e49bb..b975e1cba 100644 --- a/clearing-parent/clearing-service/src/main/resources/messages/clearing_ru.properties +++ b/clearing-parent/clearing-service/src/main/resources/messages/clearing_ru.properties @@ -1,3 +1,4 @@ payment-instruction.purpose.withdrawal.tcr=Возврат средств, свободных от обязательств с ТКР {0}. payment-instruction.purpose.withdrawal=Вывод средств. -sdf54.urgent=срочно \ No newline at end of file +sdf54.urgent=срочно +withdrawal.funds.dmau=Вывод средств с регистра невыясненных денежных средств по {0} \ No newline at end of file From 6e5cfd8c6adcfea41c5428d9873cf7904f90bc90 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 18:22:46 +0300 Subject: [PATCH 15/28] fix calc sum3 --- .../management/model/FinalCalculationResult.java | 3 ++- .../service/OrderCalculationService.java | 16 +++++++++++----- .../service/SwapOvernightOrderService.java | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java index 60a8b246b..85844fca4 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/model/FinalCalculationResult.java @@ -5,6 +5,7 @@ import java.math.BigDecimal; public record FinalCalculationResult( BigDecimal price, BigDecimal rate, - BigDecimal quantityLot + BigDecimal quantityLot, + CalculationResult calculationResult ) { } \ No newline at end of file diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java index 90a37270b..61ae83d20 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java @@ -48,7 +48,7 @@ public class OrderCalculationService { BigDecimal quantityLot = result.sum3().abs(); BigDecimal price = swapPriceCalc(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue()); - return new FinalCalculationResult(price, s, quantityLot); + return new FinalCalculationResult(price, s, quantityLot, result); } public FinalCalculationResult calcAndEnrichSpot(SettleCode settleCode, @@ -76,7 +76,7 @@ public class OrderCalculationService { price = rates.getUnitRate().add(delta).setScale(listing.getPrecision().intValue(), RoundingMode.HALF_UP);; } - return new FinalCalculationResult(price, s, quantityLot); + return new FinalCalculationResult(price, s, quantityLot, result); } private CalculationResult calculationSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) { @@ -94,7 +94,8 @@ public class OrderCalculationService { } BigDecimal rateValue = sCrossRates.getUnitRate(); BigDecimal sum2 = planPositionRub.divide(rateValue, lotSize, RoundingMode.HALF_DOWN); - BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING); + //Математическое округление кратное lotSize + BigDecimal sum3 = mathCeil(sum1, lotSize); BigDecimal sum4 = sum3.multiply(rateValue, MC).negate(); BigDecimal sum5 = sum3.negate(); @@ -116,13 +117,14 @@ public class OrderCalculationService { } BigDecimal rateValue = sCrossRates.getUnitRate(); - BigDecimal sum1 = planPosition.divide(rateValue, MC); + BigDecimal sum1 = planPosition.divide(rateValue, MC).abs(); Registry amtRegistry = imdgQueryService.findAmtRegistry(registry, "CNY"); BigDecimal planPositionCny = amtRegistry.getBalance(); BigDecimal sum2 = planPositionCny.setScale(lotSize, RoundingMode.HALF_DOWN); - BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING).min(sum2).negate(); + BigDecimal y = sum1.min(sum2); + BigDecimal sum3 = mathCeil(y, lotSize).negate(); BigDecimal sum4 = sum3.multiply(rateValue, MC).negate(); BigDecimal sum5 = sum3.negate(); @@ -150,4 +152,8 @@ public class OrderCalculationService { 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) * multiplicity); + } } diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java index dd9b5d6e6..8d55b7cb6 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java @@ -61,7 +61,7 @@ public class SwapOvernightOrderService { .build(); FinalCalculationResult finalCalculationResult = swapCalculationService.calcAndEnrichSwap(SettleCode.T1, context); - if (finalCalculationResult.quantityLot().compareTo(BigDecimal.ZERO) > 0) { + if (finalCalculationResult.calculationResult().sum3().compareTo(BigDecimal.ZERO) >= 0) { log.warn("QuantityLot greater than zero; skip forming order currency"); return; } From 33298fb391d639ce0b44941c911bed8a5bb9ba21 Mon Sep 17 00:00:00 2001 From: ialbert Date: Wed, 29 Apr 2026 18:40:50 +0300 Subject: [PATCH 16/28] http://jira.mfd.msk:8088/browse/CLS-981 --- .../main/java/ru/spcex/clearing/service/Sdf54Creator.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf54Creator.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf54Creator.java index 3bc18ade7..4ad0cc08d 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf54Creator.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/Sdf54Creator.java @@ -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) { From 1b484e63c1517fa313b5a81f5917ec3e1e758178 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 19:09:44 +0300 Subject: [PATCH 17/28] fix resolve id by FIX answer --- .../clearing/fix/quickfix/Application.java | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java index a6df06253..bc01e09d6 100644 --- a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java +++ b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java @@ -1,13 +1,46 @@ package ru.spcex.clearing.fix.quickfix; +import java.math.BigDecimal; +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 +54,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,18 +141,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) && executionReport.isSetField(OrdStatus.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(); 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 sOrdersImdg = transaction.getImdg(IMDGDistributedNames.Map_SOrders, SOrders.class); SOrders sOrders = sOrdersImdg.getSingleObjectByPredicate(sOrdersImdg.predicateBuilder().and( @@ -175,7 +204,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); From 53d051f76137d1c129821a060ed3319f3eaa30c7 Mon Sep 17 00:00:00 2001 From: ialbert Date: Wed, 29 Apr 2026 19:38:45 +0300 Subject: [PATCH 18/28] http://jira.mfd.msk:8088/browse/CLS-981 --- .../ru/spcex/clearing/service/executors/Sdf57Executor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java index ec201d1e6..c7909a465 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java @@ -475,7 +475,7 @@ public class Sdf57Executor extends AbstractExecutor { 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,7 +499,7 @@ public class Sdf57Executor extends AbstractExecutor { .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()); }); From e0cda64903a5136633f2a3ca1b1305e0f1f95ea6 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 29 Apr 2026 19:44:12 +0300 Subject: [PATCH 19/28] http://jira.mfd.msk:8088/browse/CLS-986 --- .../account/config/validation/BankAccountValidationConfig.java | 2 +- .../dflt/management/listener/OrderCurrencyListener.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/BankAccountValidationConfig.java b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/BankAccountValidationConfig.java index 0f9e0153d..340cd5b18 100644 --- a/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/BankAccountValidationConfig.java +++ b/clearing-parent/account-service/src/main/java/ru/spcex/clearing/account/config/validation/BankAccountValidationConfig.java @@ -72,7 +72,7 @@ public class BankAccountValidationConfig { AccountError.DictionaryNotFound, false), ValidateSymbolsRule.notRequired("БИК", - BankAccountUpdateRequest::getBankIdentificationCode, + BankAccountNewRequest::getBankIdentificationCode, AccountError.BadSymbol), ValidateSymbolsRule.required("Наименование компании", BankAccountNewRequest::getBankName, diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java index a532f1084..b82f80aba 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java @@ -416,7 +416,6 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing } orderCurrency.setStatus(status.getKey()); orderCurrency.setUpdated(Instant.now()); -// orderCurrency.setUpdated(sOrder.getTradeDate());//todo orderCurrencyImdg.update(orderCurrency); } } From 703ecf967b751be88fba919a1077f0c0db30c11e Mon Sep 17 00:00:00 2001 From: ialbert Date: Thu, 30 Apr 2026 13:06:11 +0300 Subject: [PATCH 20/28] http://jira.mfd.msk:8088/browse/CLS-952 --- .../listener/OrderCurrencyListener.java | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java index a532f1084..0b7f0b704 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java @@ -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; @@ -216,26 +215,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 +264,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; From 34b0b4c0976c1e647b33f8675c4e32696cd410a0 Mon Sep 17 00:00:00 2001 From: ialbert Date: Thu, 30 Apr 2026 13:11:48 +0300 Subject: [PATCH 21/28] http://jira.mfd.msk:8088/browse/CLS-952 --- .../management/listener/OrderCurrencyListener.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java index 9f9d0b267..78d1ee01a 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java @@ -182,7 +182,7 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing if (OvernightType.SWAP.equalsByKey(order.getOvernightType())) { Pair 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[{}, {}]", @@ -191,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 swapToSpotSplit(OrderCurrency swap, Registry rgs) { OrderCurrency orderT0 = new OrderCurrency(); OrderCurrency orderT1 = new OrderCurrency(); From cabc01ca06a230b2f00c48e09a1a2827dac9b683 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Thu, 30 Apr 2026 13:47:20 +0300 Subject: [PATCH 22/28] http://jira.mfd.msk:8088/browse/CLS-943 --- .../management/service/OrderCalculationService.java | 11 ++--------- .../management/service/SpotOvernightOrderService.java | 10 ++++++++++ .../management/service/SwapOvernightOrderService.java | 7 +++++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java index 61ae83d20..e121a51c7 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java @@ -83,18 +83,11 @@ public class OrderCalculationService { 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()); - 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 sum2 = planPositionRub.divide(rateValue, lotSize, RoundingMode.HALF_DOWN); - //Математическое округление кратное lotSize BigDecimal sum3 = mathCeil(sum1, lotSize); BigDecimal sum4 = sum3.multiply(rateValue, MC).negate(); BigDecimal sum5 = sum3.negate(); @@ -106,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) { @@ -154,6 +147,6 @@ public class OrderCalculationService { } private BigDecimal mathCeil(BigDecimal val, Integer multiplicity) { - return BigDecimal.valueOf(Math.ceil(val.doubleValue() / multiplicity) * multiplicity); + return BigDecimal.valueOf(Math.ceil(val.doubleValue() / multiplicity)); } } diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java index e7bb83d53..e1d27f8c7 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SpotOvernightOrderService.java @@ -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; @@ -12,11 +13,13 @@ 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 { @@ -47,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) @@ -61,6 +65,12 @@ public class SpotOvernightOrderService { FinalCalculationResult finalCalculationResultT0 = swapCalculationService.calcAndEnrichSpot(SettleCode.T0, context); FinalCalculationResult finalCalculationResultT1 = swapCalculationService.calcAndEnrichSpot(SettleCode.T1, context); + + 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); diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java index 8d55b7cb6..1f9ecb8a6 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/SwapOvernightOrderService.java @@ -13,11 +13,13 @@ 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 { @@ -48,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) @@ -61,7 +63,8 @@ public class SwapOvernightOrderService { .build(); FinalCalculationResult finalCalculationResult = swapCalculationService.calcAndEnrichSwap(SettleCode.T1, context); - if (finalCalculationResult.calculationResult().sum3().compareTo(BigDecimal.ZERO) >= 0) { + if (CurrencyCode.RUB == currency && + finalCalculationResult.calculationResult().sum3().compareTo(BigDecimal.ZERO) >= 0) { log.warn("QuantityLot greater than zero; skip forming order currency"); return; } From 13cf9733911cd12838fa188c0c7ae32f0a578e4a Mon Sep 17 00:00:00 2001 From: ialbert Date: Thu, 30 Apr 2026 15:02:07 +0300 Subject: [PATCH 23/28] http://jira.mfd.msk:8088/browse/CLS-981 --- .../service/executors/Sdf57Executor.java | 27 +++++++++++++++---- .../payment/WithdrawalFundsService.java | 2 +- .../WithdrawalFundsValidationRule.java | 3 +++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java index c7909a465..f62f6e24c 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf57Executor.java @@ -453,6 +453,7 @@ public class Sdf57Executor extends AbstractExecutor { Company cmp = stmtCmpAcc.company(); Account acc = stmtCmpAcc.account(); Optional 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()) { @@ -505,11 +506,8 @@ public class Sdf57Executor extends AbstractExecutor { }); //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 { 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()); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java index 72b75624a..05cba3432 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/payment/WithdrawalFundsService.java @@ -157,7 +157,7 @@ public class WithdrawalFundsService { sdf54Imdg.insert(sDf54); log.info("created sdf54.id={}", sDf54.getId()); - Registry d__i = dmiService.createDmi(payload.getAmount(), assets.a__t()); + 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()); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java index 652a1030f..d23b21e83 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/WithdrawalFundsValidationRule.java @@ -21,6 +21,9 @@ public enum WithdrawalFundsValidationRule implements IValidationRule Date: Thu, 30 Apr 2026 15:15:04 +0300 Subject: [PATCH 24/28] http://jira.mfd.msk:8088/browse/CLS-958 // http://jira.mfd.msk:8088/browse/CLS-952 --- .../backend-api/src/main/resources/meta/meta.json | 13 +------------ .../backend-api/src/main/resources/meta/meta.xml | 4 +--- .../db-scripts/src/main/resources/db/DDL.sql | 2 +- .../management/listener/OrderCurrencyListener.java | 5 +++-- .../ru/spcex/clearing/fix/quickfix/Application.java | 4 +++- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.json b/clearing-parent/backend-api/src/main/resources/meta/meta.json index 5ed265db6..ec7bc9cc8 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.json +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.json @@ -1,6 +1,6 @@ { - "version": "3.23.295.168", + "version": "3.23.295.169", "enums": { @@ -6389,17 +6389,6 @@ "name": "Отправка заявок в Торговую систему", - "fields": [] - } - , - {"method":"post", - - "destination": "ORST", - - "group": "Обмен с Торговой системой", - - "name": "Получение статуса заявок из Торговой системы", - "fields": [] } ] diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.xml b/clearing-parent/backend-api/src/main/resources/meta/meta.xml index fbc0ce044..1742d743f 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.xml @@ -1,6 +1,6 @@ - + @@ -1478,8 +1478,6 @@ - - diff --git a/clearing-parent/db-scripts/src/main/resources/db/DDL.sql b/clearing-parent/db-scripts/src/main/resources/db/DDL.sql index 09ea748a4..a970ebed4 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/DDL.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/DDL.sql @@ -5758,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 \ No newline at end of file +INSERT INTO DB_VERSION(ID, VERSION) values (1, '3.23') ON CONFLICT (ID) DO UPDATE SET VERSION = EXCLUDED.VE RSION \ No newline at end of file diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java index 78d1ee01a..6862a3e59 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java @@ -393,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; } @@ -419,6 +419,7 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing private void updateByFix(BaseRequest 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) ); diff --git a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java index bc01e09d6..84f036ad1 100644 --- a/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java +++ b/clearing-parent/fix-service/src/main/java/ru/spcex/clearing/fix/quickfix/Application.java @@ -1,6 +1,7 @@ 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; @@ -186,7 +187,7 @@ public class Application extends MessageCracker implements quickfix.Application, } 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())); @@ -196,6 +197,7 @@ public class Application extends MessageCracker implements quickfix.Application, sOrders.setWithdrawDateTime(transactTime.getValue().toInstant(ZoneOffset.UTC)); } + sOrders.setUpdated(Instant.now()); sOrdersImdg.update(sOrders); } From 0def756f087cfef4290e5d6a99c44a6e3b674a2e Mon Sep 17 00:00:00 2001 From: ialbert Date: Thu, 30 Apr 2026 16:03:10 +0300 Subject: [PATCH 25/28] http://jira.mfd.msk:8088/browse/CLS-989 --- .../service/executors/Sdf55Executor.java | 6 +- .../clearing/service/registry/DmiService.java | 93 ++++++++++++------- .../validation/Sdf55ValidationRule.java | 5 +- 3 files changed, 68 insertions(+), 36 deletions(-) diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf55Executor.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf55Executor.java index f7ac9ec83..5dd4a02cd 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf55Executor.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/executors/Sdf55Executor.java @@ -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(), diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/registry/DmiService.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/registry/DmiService.java index 72581f901..16daa75ab 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/registry/DmiService.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/registry/DmiService.java @@ -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 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 createDmi(Long tcrId, String securitySymbol, BigDecimal summ) { diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf55ValidationRule.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf55ValidationRule.java index 58d8f2978..16a1b5d14 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf55ValidationRule.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/Sdf55ValidationRule.java @@ -104,9 +104,10 @@ public enum Sdf55ValidationRule implements IValidationRule Date: Thu, 30 Apr 2026 16:45:53 +0300 Subject: [PATCH 26/28] http://jira.mfd.msk:8088/browse/CLS-952 --- .../OrderCurrencyCompanyNotChanged.java | 40 +++++++++++++++++++ .../management/config/ValidationConfig.java | 7 +++- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/component/validation/OrderCurrencyCompanyNotChanged.java diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/component/validation/OrderCurrencyCompanyNotChanged.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/component/validation/OrderCurrencyCompanyNotChanged.java new file mode 100644 index 000000000..f6836c56e --- /dev/null +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/component/validation/OrderCurrencyCompanyNotChanged.java @@ -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> { + public static final OrderCurrencyCompanyNotChanged INSTANCE = new OrderCurrencyCompanyNotChanged(); + + @Override + public Optional validate(ImdgValidationContext 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"; + } +} diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java index f84141bcf..cef013209 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java @@ -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); From 2bb22acef95032e16686df0bdd2ec3f47f3fd2e6 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Thu, 30 Apr 2026 16:19:55 +0300 Subject: [PATCH 27/28] update marketEfis --- .../db-scripts/src/main/resources/db/MARKET_efis.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clearing-parent/db-scripts/src/main/resources/db/MARKET_efis.sql b/clearing-parent/db-scripts/src/main/resources/db/MARKET_efis.sql index 5bedca97f..e5f793482 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/MARKET_efis.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/MARKET_efis.sql @@ -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; From feb9f5783c978db514eae5ebb8dd3acd70182021 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Thu, 30 Apr 2026 16:54:54 +0300 Subject: [PATCH 28/28] fix format dateTime for gatewayReq --- .../controller/inbound/request/security/CurrencyRate.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/controller/inbound/request/security/CurrencyRate.java b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/controller/inbound/request/security/CurrencyRate.java index c60b0e7b9..f8258a99a 100644 --- a/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/controller/inbound/request/security/CurrencyRate.java +++ b/clearing-parent/gateway-api/src/main/java/ru/spcex/clearing/gatewayapi/controller/inbound/request/security/CurrencyRate.java @@ -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;