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

This commit is contained in:
ialbert 2026-05-25 12:12:29 +03:00
commit 0cada83af9
10 changed files with 90 additions and 101 deletions

View file

@ -13,6 +13,7 @@ import ru.clearing.platform.dictionary.ServiceStatusDictionary;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.account.validation.BackendClientCodeValidationRule;
import ru.spcex.clearing.account.validation.GatewayClientCodeValidationRule;
import ru.spcex.clearing.account.validation.GatewayEksClientCodeValidationRule;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest;
@ -117,7 +118,7 @@ public class ClientCodeValidationConfig {
Account.class,
AccountError.RequiredFieldEmpty,
AccountError.AccountNotFound,
true,
false,
acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId())
? null : AccountError.AccountNotFound
),
@ -196,9 +197,9 @@ public class ClientCodeValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_DepoAccount);
return new ValidatorImpl<>(context,
FieldRequiredRule.instance("client_code", TkrAccount::getClientCode, AccountError.RequiredFieldEmpty),
GatewayClientCodeValidationRule.CompanyPresent,
GatewayEksClientCodeValidationRule.CompanyPresent,
// GatewayClientCodeValidationRule.AllAccountsPresent,
GatewayClientCodeValidationRule.DepoAccountsPresent
GatewayEksClientCodeValidationRule.DepoAccountsPresent
// GatewayClientCodeValidationRule.TcrIsNotPresent,
// GatewayClientCodeValidationRule.TcrListIsNotPresent
);

View file

@ -43,7 +43,9 @@ public enum BackendClientCodeValidationRule implements IValidationRule<ImdgValid
ClientCodeNewRequest validatedObject = context.getValidatedObject();
List<Long> currencyIds = validatedObject.getCurrencyAccountList();
Long moneyAccountId = validatedObject.getMoneyAccountId();
if (moneyAccountId == null) {
return empty();
}
Imdg<TradingClearingRegistry> tradingClearingRegistryImdg =
context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
Imdg<TradingClearingRegistryList> tradingClearingRegistryListImdg =
@ -58,6 +60,9 @@ public enum BackendClientCodeValidationRule implements IValidationRule<ImdgValid
return of(AccountError.TradingClearingRegistryAlreadyExist);
}
if (currencyIds == null || currencyIds.isEmpty()) {
return empty();
}
for (Long id : currencyIds) {
TradingClearingRegistryList tcrList = tradingClearingRegistryListImdg.getFirstObjectByFieldValues(
Map.of(

View file

@ -7,8 +7,6 @@ import java.util.Map;
import java.util.Optional;
import org.springframework.util.StringUtils;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountSymbols;
import ru.clearing.classes.statics.data.account.DepoAccount;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistryList;
@ -98,18 +96,9 @@ public enum GatewayClientCodeValidationRule implements IValidationRule<ImdgValid
return empty();
}
Imdg<AccountSymbols> accountSymbolsImdg = context.obtainMap(IMDGDistributedNames.Map_AccountSymbols, AccountSymbols.class);
ImdgPredicateBuilder predicateBuilder = accountSymbolsImdg.predicateBuilder();
AccountSymbols accountSymbols = accountSymbolsImdg.getSingleObjectByPredicate(
predicateBuilder.equals("accountSymbolValue", depoAccountVal)
);
if (accountSymbols == null) {
return of(AccountError.DepoAccountNotFound, "depo_account");
}
Imdg<DepoAccount> imdg = context.obtainMap(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class);
DepoAccount depoAccount = imdg.getFirstObjectByPredicate(
predicateBuilder.equals("accountId", accountSymbols.getAccountId())
Imdg<Account> imdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
Account depoAccount = imdg.getFirstObjectByFieldValues(
Map.of("account", depoAccountVal)
);
if (depoAccount == null) {
context.storeObject(ClientCodeStoreObjects.DEPO_ACCOUNT, Optional.empty());

View file

@ -8,6 +8,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountSymbols;
import ru.clearing.classes.statics.data.account.DepoAccount;
import ru.clearing.classes.statics.data.company.Company;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
@ -15,6 +17,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.TkrAccount;
import ru.spcex.clearing.platform.messaging.domain.cud.gateway.MoneyAccountMsgRequest;
import ru.spcex.platform.enumeration.CurrencyCode;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
@ -75,9 +78,18 @@ public enum GatewayEksClientCodeValidationRule implements IValidationRule<ImdgVa
return empty();
}
Imdg<Account> imdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
Account depoAccount = imdg.getFirstObjectByFieldValues(
Map.of("account", depoAccountVal)
Imdg<AccountSymbols> accountSymbolsImdg = context.obtainMap(IMDGDistributedNames.Map_AccountSymbols, AccountSymbols.class);
ImdgPredicateBuilder predicateBuilder = accountSymbolsImdg.predicateBuilder();
AccountSymbols accountSymbols = accountSymbolsImdg.getSingleObjectByPredicate(
predicateBuilder.equals("accountSymbolValue", depoAccountVal)
);
if (accountSymbols == null) {
return of(AccountError.DepoAccountNotFound, "depo_account");
}
Imdg<DepoAccount> imdg = context.obtainMap(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class);
DepoAccount depoAccount = imdg.getFirstObjectByPredicate(
predicateBuilder.equals("accountId", accountSymbols.getAccountId())
);
if (depoAccount == null) {
context.storeObject(ClientCodeStoreObjects.DEPO_ACCOUNT, Optional.empty());

View file

@ -1,6 +1,6 @@
{
"version": "3.25.300.176",
"version": "3.26.301.178",
"enums": {
@ -4200,18 +4200,6 @@
{"code": "tradingClearingRegistryId",
"type": 1,"dbname": "Идентификатор торгово-клирингового регистра","name": "Торгово-клиринговый регистр","shortname": "ТКР","searchable": true,"sortable": true,"link": "tradingClearingRegistry","linkCode": "code"
}
,
{"code": "moneyAccountId",
"type": 1,"dbname": "Идентификатор денежного счета","name": "Номер денежного счета","shortname": "Денежный счет","searchable": true,"sortable": true,"link": "account","linkCode": "account"
}
,
{"code": "depoAccountId",
"type": 1,"dbname": "Идентификатор депозитарного счета","name": "Номер депозитарного счета","shortname": "Депозитарный счет","searchable": true,"sortable": true,"link": "account","linkCode": "account"
}
,
{"code": "currencyAccountId",
"type": 1,"dbname": "Идентификатор валютного счета","name": "Номер валютного счета","shortname": "Валютный счет","searchable": true,"sortable": true,"link": "account","linkCode": "account"
}
,
{"code": "status",
"type": 12,"dbname": "Код статуса","name": "Наименование статуса","shortname": "Статус","searchable": true,"sortable": true,"link": "workflowStatus"
@ -4230,7 +4218,7 @@
"name": "Добавление кода клиента",
"confirmation": "companyId,code,tradingClearingRegistryId,moneyAccountId,depoAccountId,status",
"confirmation": "companyId,code,tradingClearingRegistryId,status",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.account.ClientCodeNewAction",
@ -4246,18 +4234,6 @@
{"code": "tradingClearingRegistryId",
"type": 1,"name": "Торгово-клиринговый регистр","shortname": "ТКР","link": "tradingClearingRegistry","linkCode": "code"
}
,
{"code": "moneyAccountId",
"type": 1,"name": "Номер денежного счета","shortname": "Денежный счет","link": "account","linkCode": "account"
}
,
{"code": "depoAccountId",
"type": 1,"name": "Номер депозитарного счета","shortname": "Депозитарный счет","link": "account","linkCode": "account"
}
,
{"code": "currencyAccountList",
"type": 7,"name": "Список валютных счетов","shortname": "Список валютных счетов","link": "account","linkCode": "account"
}
,
{"code": "status",
"type": 12,"name": "Наименование статуса","shortname": "Статус","link": "workflowStatus"
@ -4269,7 +4245,7 @@
"name": "Изменение кода клиента",
"confirmation": "companyId,code,tradingClearingRegistryId,moneyAccountId,depoAccountId,status",
"confirmation": "companyId,code,tradingClearingRegistryId,status",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.account.ClientCodeUpdateAction",
@ -4289,18 +4265,6 @@
{"code": "tradingClearingRegistryId",
"type": 1,"name": "Торгово-клиринговый регистр","shortname": "ТКР","link": "tradingClearingRegistry","linkCode": "code"
}
,
{"code": "moneyAccountId",
"type": 1,"name": "Номер денежного счета","shortname": "Денежный счет","link": "account","linkCode": "account"
}
,
{"code": "depoAccountId",
"type": 1,"name": "Номер депозитарного счета","shortname": "Депозитарный счет","link": "account","linkCode": "account"
}
,
{"code": "currencyAccountList",
"type": 7,"name": "Список валютных счетов","shortname": "Список валютных счетов","link": "account","linkCode": "account"
}
,
{"code": "status",
"type": 12,"name": "Наименование статуса","shortname": "Статус","link": "workflowStatus"

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--?xml-stylesheet type="text/xsl" href="\..\corp-reports\src\data\meta\meta.server.xslt"?-->
<meta version="3.25.300.176">
<meta version="3.26.301.178">
<!-- _xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _xsi:noNamespaceSchemaLocation="file:///E:/d/projects/meta/from/meta.xsd" -->
<!--Здесь словари-->
<enums>
@ -971,30 +971,21 @@
<companyId type="1" dbname="Идентификатор компании" name="Наименование компании" shortname="Компания" searchable="true" sortable="true" visible="true" link="company" linkCode="shortName"/>
<code type="2" length="255" name="Код клиента" shortname="Код клиента" searchable="true" sortable="true" visible="true"/>
<tradingClearingRegistryId type="1" dbname="Идентификатор торгово-клирингового регистра" name="Торгово-клиринговый регистр" shortname="ТКР" searchable="true" sortable="true" link="tradingClearingRegistry" linkCode="code"/>
<moneyAccountId type="1" dbname="Идентификатор денежного счета" name="Номер денежного счета" shortname="Денежный счет" searchable="true" sortable="true" link="account" linkCode="account"/>
<depoAccountId type="1" dbname="Идентификатор депозитарного счета" name="Номер депозитарного счета" shortname="Депозитарный счет" searchable="true" sortable="true" link="account" linkCode="account"/>
<currencyAccountId type="1" dbname="Идентификатор валютного счета" name="Номер валютного счета" shortname="Валютный счет" searchable="true" sortable="true" link="account" linkCode="account"/>
<status type="12" dbname="Код статуса" name="Наименование статуса" shortname="Статус" searchable="true" sortable="true" link="workflowStatus"/>
<createdAt field="created" type="4" webtype="5" dbname="Дата-время создания записи" name="Время создания записи" shortname="Создано" searchable="true" sortable="true"/>
<updatedAt field="updated" type="4" webtype="5" dbname="Дата-время изменения записи" name="Время изменения записи" shortname="Изменено" searchable="true" sortable="true"/>
<actions>
<post name="Добавление кода клиента" confirmation="companyId,code,tradingClearingRegistryId,moneyAccountId,depoAccountId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.account.ClientCodeNewAction">
<post name="Добавление кода клиента" confirmation="companyId,code,tradingClearingRegistryId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.account.ClientCodeNewAction">
<companyId type="1" name="Наименование компании" shortname="Компания" link="company" linkCode="shortName" required="true" enabled="false"/>
<code type="2" length="255" name="Код клиента" shortname="Код клиента" required="true"/>
<tradingClearingRegistryId type="1" name="Торгово-клиринговый регистр" shortname="ТКР" link="tradingClearingRegistry" linkCode="code"/>
<moneyAccountId type="1" name="Номер денежного счета" shortname="Денежный счет" link="account" linkCode="account"/>
<depoAccountId type="1" name="Номер депозитарного счета" shortname="Депозитарный счет" link="account" linkCode="account"/>
<currencyAccountList type="7" name="Список валютных счетов" shortname="Список валютных счетов" link="account" linkCode="account"/>
<status type="12" name="Наименование статуса" shortname="Статус" link="workflowStatus"/>
</post>
<put name="Изменение кода клиента" confirmation="companyId,code,tradingClearingRegistryId,moneyAccountId,depoAccountId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.account.ClientCodeUpdateAction">
<put name="Изменение кода клиента" confirmation="companyId,code,tradingClearingRegistryId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.account.ClientCodeUpdateAction">
<id type="1" name="Идентификатор записи" shortname="ID" link="clientCode" linkCode="id" required="true"/>
<companyId type="1" name="Наименование компании" shortname="Компания" link="company" linkCode="shortName" enabled="false"/>
<code type="2" length="255" name="Код клиента" shortname="Код клиента"/>
<tradingClearingRegistryId type="1" name="Торгово-клиринговый регистр" shortname="ТКР" link="tradingClearingRegistry" linkCode="code"/>
<moneyAccountId type="1" name="Номер денежного счета" shortname="Денежный счет" link="account" linkCode="account"/>
<depoAccountId type="1" name="Номер депозитарного счета" shortname="Депозитарный счет" link="account" linkCode="account"/>
<currencyAccountList type="7" name="Список валютных счетов" shortname="Список валютных счетов" link="account" linkCode="account"/>
<status type="12" name="Наименование статуса" shortname="Статус" link="workflowStatus"/>
</put>
<delete name="Блокировка кода клиента" confirmation="companyId,code" class="ru.spcex.clearing.backendapi.controller.request.cud.common.CommonDeleteAction">

View file

@ -5852,4 +5852,4 @@ GRANT ALL PRIVILEGES ON TABLE ORDER_CURRENCY_HISTORY TO clearing;
-- Data types
INSERT INTO DB_VERSION(ID, VERSION) values (1, '3.24') ON CONFLICT (ID) DO UPDATE SET VERSION = EXCLUDED.VERSION
INSERT INTO DB_VERSION(ID, VERSION) values (1, '3.26') ON CONFLICT (ID) DO UPDATE SET VERSION = EXCLUDED.VERSION

View file

@ -1,4 +1,4 @@
-- DB version: 3.24 -> 3.25
-- DB version: 3.25 -> 3.26
ALTER TABLE ORDER_CURRENCY ADD COLUMN IF NOT EXISTS EXCHANGE_ORDER_ID BIGINT;

View file

@ -11,6 +11,7 @@ import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
@ -51,6 +52,7 @@ import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.collection.Pair;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.log.ExceptionUtils;
import ru.spcex.platform.utils.number.BigDecimalUtil;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
import ru.spcex.platform.utils.validation.IValidator;
@ -429,38 +431,50 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
private void updateByImporter(BaseRequest<OrderCurrencyStatusUpdateRequest> req) {
OrderCurrencyStatusUpdateRequest payload = req.getRequestPayload();
for (Long orderId : payload.getIds()) {
SOrders sOrder = sOrdersImdg.getSingleObjectByID(orderId);
OrderCurrency orderCurrency = orderCurrencyImdg.getSingleObjectByID(orderId);
if (orderCurrency == null) {
log.warn("OrderCurrency[{}] not found", orderId);
continue;
try {
SOrders sOrder = sOrdersImdg.getSingleObjectByID(orderId);
OrderCurrency orderCurrency = orderCurrencyImdg.getSingleObjectByID(orderId);
if (orderCurrency == null) {
log.warn("OrderCurrency[{}] not found", orderId);
continue;
}
OrderStatus status = resolveStatusByImportState(sOrder.getState());
if (status == null) {
continue;
}
orderCurrency.setStatus(status.getKey());
if (orderCurrency.getExchangeOrderId() == null) {
orderCurrency.setExchangeOrderId(normalize(sOrder.getExchangeOrderNum()));
}
orderCurrency.setUpdated(Instant.now());
orderCurrencyImdg.update(orderCurrency);
} catch (Exception e) {
log.error("Error updating status by orderNum {} with error:{}", orderId, ExceptionUtils.getStackTrace(e));
}
OrderStatus status = resolveStatusByImportState(sOrder.getState());
if (status == null) {
continue;
}
orderCurrency.setStatus(status.getKey());
orderCurrency.setExchangeOrderId(Long.valueOf(sOrder.getExchangeOrderNum()));
orderCurrency.setUpdated(Instant.now());
orderCurrencyImdg.update(orderCurrency);
}
}
private void updateByFix(BaseRequest<OrderCurrencyStatusUpdateRequest> req) {
OrderCurrencyStatusUpdateRequest payload = req.getRequestPayload();
for (Long orderId : payload.getIds()) {
log.debug("Process updating status by orderNum {}", orderId);
SOrders sOrder = sOrdersImdg.getSingleObjectByPredicate(
sOrdersImdg.predicateBuilder().equals("orderNum", orderId)
);
OrderCurrency orderCurrency = orderCurrencyImdg.getSingleObjectByID(orderId);
OrderStatus status = resolveStatusByFixState(sOrder.getState());
if (status == null) {
continue;
try {
log.debug("Process updating status by orderNum {}", orderId);
SOrders sOrder = sOrdersImdg.getSingleObjectByPredicate(
sOrdersImdg.predicateBuilder().equals("orderNum", orderId)
);
OrderCurrency orderCurrency = orderCurrencyImdg.getSingleObjectByID(orderId);
OrderStatus status = resolveStatusByFixState(sOrder.getState());
if (status == null) {
continue;
}
orderCurrency.setStatus(status.getKey());
if (orderCurrency.getExchangeOrderId() == null) {
orderCurrency.setExchangeOrderId(normalize(sOrder.getExchangeOrderNum()));
}
orderCurrency.setUpdated(Instant.now());
orderCurrencyImdg.update(orderCurrency);
} catch (Exception e) {
log.error("Error updating status by orderNum {} with error:{}", orderId, ExceptionUtils.getStackTrace(e));
}
orderCurrency.setStatus(status.getKey());
orderCurrency.setExchangeOrderId(Long.valueOf(sOrder.getExchangeOrderNum()));
orderCurrency.setUpdated(Instant.now());
orderCurrencyImdg.update(orderCurrency);
}
}
@ -486,4 +500,17 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing
default -> null;
};
}
private Long normalize(String value) {
if (StringUtils.isEmpty(value) || value.equals("0")){
return 0L;
}
String[] parts = value.split("-", 3);
if (parts.length != 3) {
throw new IllegalArgumentException("Ожидается формат: digits-text-digits");
}
String digits = parts[0] + parts[2];
return Long.valueOf(digits);
}
}

View file

@ -155,7 +155,7 @@ public class OrderTemplateBuilder {
order.setTradingCode(registry.getTradingCode());
order.setCounterPartyId(clcc.companyId());
order.setCounterTradingCode(clcc.tradingCode());
order.setComment("Type=3");
order.setComment("Type=1");
order.setType("PLOV");
return order;
}
@ -171,7 +171,7 @@ public class OrderTemplateBuilder {
order.setTradingCode(clcc.tradingCode());
order.setCounterPartyId(registry.getCompanyId());
order.setCounterTradingCode(registry.getTradingCode());
order.setComment("Type=3");
order.setComment("Type=1");
order.setType("PLOV");
return order;
}