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

This commit is contained in:
ialbert 2024-05-01 17:13:33 +03:00
commit 8375759ea2
45 changed files with 1361 additions and 251 deletions

View file

@ -48,6 +48,7 @@ public class AccountValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary);
addImdg.accept(IMDGDistributedNames.Map_AccountTypeDictionary);
addImdg.accept(IMDGDistributedNames.Map_CurrencyCodeDictionary);
return new ValidatorImpl<>(context,
IdPresentRule.instance("companyId",
CorrespondentAccountNewRequest::getCompanyId,
@ -106,6 +107,15 @@ public class AccountValidationConfig {
return DictionaryPresentRule.DICTIONARY_NOT_FOUND_DECORATOR_2.decorator(causeEmpty, errorCode, fieldName, fieldValue);
}
),
DictionaryPresentRule.instance("currency",
CorrespondentAccountNewRequest::getCurrency,
IMDGDistributedNames.Map_CurrencyCodeDictionary,
ServiceStatusDictionary.class,
null,
AccountError.DictionaryNotFound,
false
),
new SameAccountValidationRule<>(AccountType.Corr, CorrespondentAccountNewRequest::getAccount)
);
};

View file

@ -38,6 +38,7 @@ public class InformationAccountValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_InformationAccount);
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary);
addImdg.accept(IMDGDistributedNames.Map_AccountTypeDictionary);
addImdg.accept(IMDGDistributedNames.Map_CurrencyCodeDictionary);
addImdg.accept(IMDGDistributedNames.Map_Account);
return new ValidatorImpl<>(context,
IdPresentRule.instance("companyId",
@ -59,6 +60,10 @@ public class InformationAccountValidationConfig {
DictionaryPresentRule.instance("accountType", InformationAccountNewRequest::getAccountType,
IMDGDistributedNames.Map_AccountTypeDictionary, AccountTypeDictionary.class,
AccountError.RequiredFieldEmpty, AccountError.DictionaryNotFound, false),
DictionaryPresentRule.instance("currency", InformationAccountNewRequest::getCurrency,
IMDGDistributedNames.Map_CurrencyCodeDictionary, ServiceStatusDictionary.class,
null, AccountError.DictionaryNotFound,false
),
new SameAccountValidationRule<>(AccountType.Info, InformationAccountNewRequest::getAccount)
);
};

View file

@ -1,5 +1,6 @@
package ru.spcex.clearing.account.config.validation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.Account;
@ -14,6 +15,7 @@ import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.CurrencyCode;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
@ -52,7 +54,7 @@ public class TradingClearingRegistryListValidationConfig {
AccountError.RequiredFieldEmpty,
AccountError.TradingClearingRegistryNotFound,
false),
new ExistAllCurrencyAccountId<>("accountId",
new ExistAllAccountId<>("accountId",
TradingClearingRegistryListNewRequest::getAccountId,
false,
null),
@ -79,17 +81,18 @@ public class TradingClearingRegistryListValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary);
return new ValidatorImpl<ImdgValidationContext<TradingClearingRegistryListUpdateRequest>>(context,
IdPresentRule.instance2("id",
TradingClearingRegistryListUpdateRequest::getTradingClearingRegistryId,
TradingClearingRegistryListUpdateRequest::getId,
IMDGDistributedNames.Map_TradingClearingRegistryList,
TradingClearingRegistryList.class,
AccountError.RequiredFieldEmpty,
AccountError.TradingClearingRegistryNotFound,
AccountError.RecordNotFound,
true,
(tcrList)-> {
Long accountId = tcrList.getAccountId();
if (accountId==null)
return null;
if (!IEnumKey.contains(context.getValidatedObject().getStatus(), ServiceStatus.Active, ServiceStatus.Reopened))
if (!IEnumKey.contains(context.getValidatedObject().getStatus(),
ServiceStatus.Active, ServiceStatus.Reopened))
return null;
Imdg<TradingClearingRegistryList> tradingClearingRegistryListImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class);
@ -119,13 +122,13 @@ public class TradingClearingRegistryListValidationConfig {
}
public static class ExistAllCurrencyAccountId<R> implements IValidationRule<ImdgValidationContext<R>> {
public static class ExistAllAccountId<R> implements IValidationRule<ImdgValidationContext<R>> {
String fieldName;
Function<R, Long> accountIdGetter;
boolean required;
Function<R, Long> idGetter;
public ExistAllCurrencyAccountId(String fieldName, Function<R, Long> accountIdGetter, boolean required, Function<R, Long> idGetter) {
public ExistAllAccountId(String fieldName, Function<R, Long> accountIdGetter, boolean required, Function<R, Long> idGetter) {
this.fieldName = fieldName;
this.accountIdGetter = accountIdGetter;
this.required = required;
@ -148,7 +151,11 @@ public class TradingClearingRegistryListValidationConfig {
Account byIdObject = accountImdg.getSingleObjectByID(accountId);
if (byIdObject == null)
return of(AccountError.AccountNotFound, accountId, fieldName);
if (!AccountType.Curr.equalsByKey(byIdObject.getAccountType())) {
if (!IEnumKey.contains(byIdObject.getAccountType(), AccountType.Clrn, AccountType.Info)) {
return of(AccountError.AccountIsNotACurrency, accountId,
fieldName, "expected: CLRN/INFO but is " + byIdObject.getAccountType()); // Счет %S не
}
if (CurrencyCode.isRub(byIdObject.getCurrency()) || StringUtils.isEmpty(byIdObject.getCurrency())) {
return of(AccountError.AccountIsNotACurrency, accountId, fieldName); // Счет %S не валютный
}
}

View file

@ -129,18 +129,20 @@ public class AccountService extends QueueConsumer implements InitializingBean {
if (requestInfoUpdate != null) return requestInfoUpdate;
CorrespondentAccountNewRequest req = userRequest.getRequestPayload();
String currency = req.getCurrency() == null ? CurrencyCode.RUB.getKey() : req.getCurrency();
Instant now = Instant.now();
Account account = new Account();
account.setCompanyId(req.getCompanyId());
account.setAccount(req.getAccount());
if (AccountType.Info.equalsByKey(req.getAccountType())) {
Long infoSequenceId = informationAccountService.accountNextId();
Long infoSequenceId = informationAccountService.accountNextId(currency);
String accountValue = informationAccountService.generateInfoAccount(infoSequenceId);
log.trace("New info-account SequenceId={} account={}", infoSequenceId, accountValue);
account.setAccount(accountValue);
}
account.setAccountType(req.getAccountType());
account.setCurrency(currency);
if (req.getStatus() == null) {
account.setStatus(WorkflowStatus.Active.getKey());
log.trace("Status not set in request. Use default: {}", account.getStatus());
@ -198,10 +200,11 @@ public class AccountService extends QueueConsumer implements InitializingBean {
infoAcc.setAccountId(account.getId());
Account firstAccountAntl = accountMap.getFirstObjectByFieldValues(Map.of(
"companyId", Sender.One.getId(),
"accountType", AccountType.Anlt.getKey()
"accountType", AccountType.Anlt.getKey(),
"currency", account.getCurrency()
));
if (firstAccountAntl == null) {
log.warn("Can not find 1 ANTL account for fill information ClearingAccountId.");
log.warn("Can not find 1 ANTL {} account for fill information ClearingAccountId.", account.getCurrency());
} else {
infoAcc.setClearingAccountId(firstAccountAntl.getId());
}

View file

@ -16,7 +16,6 @@ import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.account.InformationAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.reports.NotificationRequest;
import ru.spcex.clearing.platform.messaging.serialization.LogFormatter;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
@ -26,6 +25,7 @@ import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.CurrencyCode;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
@ -40,6 +40,7 @@ import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
@ -63,7 +64,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali
* Кэш-счётчик сквозных номеров счетов.
* См. accountNextId()
*/
protected AtomicLong infoCounter;
protected Map<String, AtomicLong> infoCounterByCurrency = new HashMap<>();
@Autowired
public InformationAccountService(Consumer<String, Object> kafkaQueue,
@ -115,15 +116,17 @@ public class InformationAccountService extends QueueConsumer implements Initiali
if (requestInfoUpdate != null) return requestInfoUpdate;
InformationAccountNewRequest req = userRequest.getRequestPayload();
String currency = req.getCurrency() == null ? CurrencyCode.RUB.getKey() : req.getCurrency(); //userRequest.getRequestPayload().getCurrency();
Long newId = informationAccountImdg.nextIDSequenceFor();
Long infoSequenceId = accountNextId();
Long infoSequenceId = accountNextId(currency);
String accountValue = generateInfoAccount(infoSequenceId);
log.trace("New info-account id={}, sequenceId={}, account={}", newId, infoSequenceId, accountValue);
ImdgPredicateBuilder accountPredicateBuilder = accountImdg.predicateBuilder();
ImdgPredicate companyIdPredicate = accountPredicateBuilder.equals("companyId", 1L);
ImdgPredicate accountTypePredicate = accountPredicateBuilder.equals("accountType", AccountType.Anlt.getKey());
ImdgPredicate accountTypePredicate = accountPredicateBuilder.and(accountPredicateBuilder.equals("accountType", AccountType.Anlt.getKey()),
accountPredicateBuilder.equals("currency", currency));
ImdgPredicate andPredicate = accountPredicateBuilder.and(companyIdPredicate, accountTypePredicate);
Collection<Account> accountsAnlt = accountImdg.getCollectionObjectsByPredicate(andPredicate);
if (accountsAnlt.isEmpty()) {
@ -209,8 +212,11 @@ public class InformationAccountService extends QueueConsumer implements Initiali
}
String currency = userRequest.getRequestPayload().getCurrency();
if (currency == null)
currency = CurrencyCode.RUB.getKey();
Long newId = informationAccountImdg.nextIDSequenceFor();
Long infoSequenceId = accountNextId(); // требуется последовательность n+1
Long infoSequenceId = accountNextId(currency); // требуется последовательность n+1
String accountValue = generateInfoAccount(infoSequenceId);
log.trace("New info-account id={}, sequenceId={}, account={}", newId, infoSequenceId, accountValue);
@ -218,7 +224,8 @@ public class InformationAccountService extends QueueConsumer implements Initiali
{
ImdgPredicate andPredicate = pb.and(
pb.equals("companyId", 1L),
pb.equals("accountType", AccountType.Anlt.getKey())
pb.equals("accountType", AccountType.Anlt.getKey()),
pb.equals("currency", currency)
);
Collection<Account> accountsAnlt = accountImdg.getCollectionObjectsByPredicate(andPredicate);
if (accountsAnlt.isEmpty()) {
@ -302,13 +309,20 @@ public class InformationAccountService extends QueueConsumer implements Initiali
/**
* Сквозной номер инфо-счетов
*
* @param
* @return infoCounter++
*/
public synchronized Long accountNextId() {
public synchronized Long accountNextId(String currency) {
if (currency == null)
currency = CurrencyCode.RUB.getKey(); // default
AtomicLong infoCounter = infoCounterByCurrency.get(currency);
if (infoCounter == null) synchronized (this) {
if (infoCounter == null) {
log.debug("Init account-information counter.");
Collection<Account> allInfoAcc = accountImdg.getCollectionObjectsByFieldValues(Map.of("accountType", AccountType.Info.getKey()));
Collection<Account> allInfoAcc = accountImdg.getCollectionObjectsByFieldValues(Map.of(
"accountType", AccountType.Info.getKey(),
"currency", currency
));
if (allInfoAcc.isEmpty()) {
infoCounter = new AtomicLong(1);
log.debug("No account information on map. n={}", infoCounter.get());
@ -341,6 +355,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali
if (parsedCount == 0 && lastAccount != null)
log.debug("Last unparseable account: {}", lastAccount);
}
infoCounterByCurrency.put(currency, infoCounter);
}
}
return infoCounter.incrementAndGet();

View file

@ -1,5 +1,10 @@
package ru.spcex.clearing.account.service;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
@ -21,12 +26,8 @@ import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.CreateRegistryByTCRListRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.CreateRegistryRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryListNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryListUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.reports.NotificationRequest;
import ru.spcex.clearing.platform.messaging.serialization.LogFormatter;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
@ -35,19 +36,12 @@ import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.TradingClearingRegistryPurpose;
import ru.spcex.platform.enumeration.TradingClearingRegistryType;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.log.ExceptionUtils;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.*;
import java.util.function.Function;
@Service
public class TradingClearingRegistryListService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
@ -141,7 +135,9 @@ public class TradingClearingRegistryListService extends QueueConsumer implements
return requestInfoUpdate;
}
TradingClearingRegistryListNewRequest req = userRequest.getRequestPayload();
Account account = accountImdg.getSingleObjectByID(req.getAccountId());
Instant now = Instant.now();
List<Long> newIds=new ArrayList<>();
@ -153,6 +149,7 @@ public class TradingClearingRegistryListService extends QueueConsumer implements
tradingClearingRegistryList.setUpdated(now);
tradingClearingRegistryList.setTradingClearingRegistryId(req.getTradingClearingRegistryId());
tradingClearingRegistryList.setAccountId(currAccId);
tradingClearingRegistryList.setCurrency(account.getCurrency());
if (req.getStatus() == null) {
tradingClearingRegistryList.setStatus(ServiceStatus.Active.getKey());
log.trace("TCRList status in request not set. Use default: {}", tradingClearingRegistryList.getStatus());
@ -210,6 +207,7 @@ public class TradingClearingRegistryListService extends QueueConsumer implements
}
TradingClearingRegistryListNewRequest req = userRequest.getRequestPayload();
Account account = accountImdg.getSingleObjectByID(req.getAccountId());
Instant now = Instant.now();
Long id = tradingClearingRegistryListImdg.nextIDSequenceFor();
@ -219,6 +217,7 @@ public class TradingClearingRegistryListService extends QueueConsumer implements
tradingClearingRegistryList.setUpdated(now);
tradingClearingRegistryList.setTradingClearingRegistryId(req.getTradingClearingRegistryId());
tradingClearingRegistryList.setAccountId(req.getAccountId());
tradingClearingRegistryList.setCurrency(account.getCurrency());
if (req.getStatus() == null) {
tradingClearingRegistryList.setStatus(ServiceStatus.Active.getKey());
log.trace("TCRList status in request not set. Use default: {}", tradingClearingRegistryList.getStatus());
@ -231,26 +230,26 @@ public class TradingClearingRegistryListService extends QueueConsumer implements
if (!innerCall) {
// Для каждого счета из списка (currencyAccountList) должна быть создана отдельная запись объекте clientCode с данным счетом для данного клиента, т.е. у одного клиента может быть несколько валютных счетов.
try {
TradingClearingRegistry tcr = tradingClearingRegistryImdg.getSingleObjectByID(req.getTradingClearingRegistryId());
ClientCodeNewRequest cCodeReq = new ClientCodeNewRequest();
cCodeReq.setTradingClearingRegistryId(req.getTradingClearingRegistryId());
cCodeReq.setDepoAccountId(tcr.getDepoAccountId());
cCodeReq.setMoneyAccountId(tcr.getMoneyAccountId());
cCodeReq.setCompanyId(tcr.getCompanyId());
cCodeReq.setCurrencyAccountList(Arrays.asList(req.getAccountId())); // todo rewrite API
cCodeReq.setStatus(tradingClearingRegistryList.getStatus());
//todo cCodeReq.setCode();
BaseRequest<ClientCodeNewRequest> request2 = new BaseRequest<>();
request2.setRequestPayload(cCodeReq);
requestInfoUpdate = clientCodeService.clientCodeNew0(request2, true);
if (requestInfoUpdate != null) return requestInfoUpdate;
} catch (Exception e) {
log.error("Can not wait creation of tradingClearingRegistryList. request id={}; {}",
userRequest.getId(),
ExceptionUtils.getStackTrace(e));
return requestHelper.makeErrorResponse(userRequest, AccountError.GeneralError, "Can not create TCR: " + e.getMessage());
}
// try {
// TradingClearingRegistry tcr = tradingClearingRegistryImdg.getSingleObjectByID(req.getTradingClearingRegistryId());
// ClientCodeNewRequest cCodeReq = new ClientCodeNewRequest();
// cCodeReq.setTradingClearingRegistryId(req.getTradingClearingRegistryId());
// cCodeReq.setDepoAccountId(tcr.getDepoAccountId());
// cCodeReq.setMoneyAccountId(tcr.getMoneyAccountId());
// cCodeReq.setCompanyId(tcr.getCompanyId());
// cCodeReq.setCurrencyAccountList(Arrays.asList(req.getAccountId())); // todo rewrite API
// cCodeReq.setStatus(tradingClearingRegistryList.getStatus());
// //todo cCodeReq.setCode();
// BaseRequest<ClientCodeNewRequest> request2 = new BaseRequest<>();
// request2.setRequestPayload(cCodeReq);
// requestInfoUpdate = clientCodeService.clientCodeNew0(request2, true);
// if (requestInfoUpdate != null) return requestInfoUpdate;
// } catch (Exception e) {
// log.error("Can not wait creation of tradingClearingRegistryList. request id={}; {}",
// userRequest.getId(),
// ExceptionUtils.getStackTrace(e));
// return requestHelper.makeErrorResponse(userRequest, AccountError.GeneralError, "Can not create TCR: " + e.getMessage());
// }
}

View file

@ -1,5 +1,12 @@
package ru.spcex.clearing.account.service;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
@ -40,10 +47,6 @@ import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.*;
import java.util.function.Function;
@Service
public class TradingClearingRegistryService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
@ -394,14 +397,15 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
if (code.length() > 4)
code = code.substring(code.length() - 4);
code = "%4s".formatted(code).replace(' ', '0');
code += registryPurpose.getKey(); // C / M / ...
// code += registryPurpose.getKey(); // C / M / ...
code += "C";//пока ставим всегда С, возможно придется откатить
String trType = tradingRegistryType + "T"; // 2 символа
code += trType;
String sId = "%5s".formatted(id).replace(' ', '0');
if (sId.length() > 5)
sId = sId.substring(sId.length() - 5);
code += sId;
return code; // 12 имволов
return code; // 12 символов
}
public RequestInfoUpdate tradingClearingRegistryUpdate(BaseRequest<TradingClearingRegistryUpdateRequest> userRequest) {

View file

@ -124,6 +124,7 @@ class InformationAccountServiceTest {
Account accountAnlt = new Account();
accountAnlt.setAccountType(AccountType.Anlt.getKey());
accountAnlt.setCompanyId(1L);
accountAnlt.setCurrency("RUB");
anltAccountId = accountImdg.insert(accountAnlt);
new TestObjectCreator(hazelcastServiceTest).createUserAdmin(1000L);
@ -134,6 +135,7 @@ class InformationAccountServiceTest {
InformationAccountNewRequest InformationAccountNewRequest = new InformationAccountNewRequest();
InformationAccountNewRequest.setCompanyId(companyId);
InformationAccountNewRequest.setAccount(account);
InformationAccountNewRequest.setCurrency(null);
String jsonString = getJsonStringForNew(InformationAccountNewRequest, 0L);
@ -178,11 +180,13 @@ class InformationAccountServiceTest {
Account account = new Account();
account.setId(120L);
account.setAccountType(AccountType.Info.getKey());
account.setCurrency(CurrencyCode.RUB.getKey());
account.setCompanyId(10L);
account.setAccount("39911810000000127000");
accountImdg.insert(account);
InformationAccount accountInfo = new InformationAccount();
accountInfo.setId(121L);
account.setCurrency(CurrencyCode.RUB.getKey());
accountInfo.setAccountId(account.getId());
accountInfo.setCompanyId(account.getCompanyId());
accountInfoImdg.insert(accountInfo);
@ -190,9 +194,17 @@ class InformationAccountServiceTest {
UserRoleVerification userRoleVerification = Mockito.mock(UserRoleVerification.class);
InformationAccountService infoAccSvc=new InformationAccountService(null,null,null,
null, userRoleVerification, hazelcastServiceTest, null, null, null, null);
Long n = infoAccSvc.accountNextId();
Long n = infoAccSvc.accountNextId(null);
Assertions.assertEquals(13L, n);
n = infoAccSvc.accountNextId();
n = infoAccSvc.accountNextId(null);
Assertions.assertEquals(14L, n);
// Другие валюты
n = infoAccSvc.accountNextId(CurrencyCode.RUB.getKey());
Assertions.assertEquals(15L, n);
n = infoAccSvc.accountNextId("CNY");
Assertions.assertEquals(2L, n);
n = infoAccSvc.accountNextId("CNY");
Assertions.assertEquals(3L, n);
}
}

View file

@ -167,7 +167,8 @@ class TradingClearingRegistryListServiceTest {
c2Account.setAccount("AAAX-44654-CURR");
c2Account.setStatus("ACTV");
c2Account.setCompanyId(COMPANY_ID); // для валидации принадлежности счёта
c2Account.setAccountType(AccountType.Curr.getKey());
c2Account.setAccountType(AccountType.Info.getKey());
c2Account.setCurrency("USD");
accounts.insert(c2Account);
Account c3Account = new Account();
@ -175,7 +176,8 @@ class TradingClearingRegistryListServiceTest {
c3Account.setAccount("AAAX-12654-CURR");
c3Account.setStatus("ACTV");
c3Account.setCompanyId(COMPANY_ID); // для валидации принадлежности счёта
c3Account.setAccountType(AccountType.Curr.getKey());
c3Account.setAccountType(AccountType.Info.getKey());
c3Account.setCurrency("USD");
accounts.insert(c3Account);
new TestObjectCreator(hazelcastServiceTest).createUserAdmin(1000L);
@ -201,7 +203,7 @@ class TradingClearingRegistryListServiceTest {
final String ccCode = null;
TradingClearingRegistryListNewRequest tcrlNewRequest = new TradingClearingRegistryListNewRequest();
tcrlNewRequest.setTradingClearingRegistryId(TCR_ID);
tcrlNewRequest.setCurrencyAccountList(Arrays.asList(134L));
tcrlNewRequest.setAccountId(134L);
tcrlNewRequest.setStatus("ACTV");
ClientCode predictableClientCode = new ClientCode();
@ -212,7 +214,7 @@ class TradingClearingRegistryListServiceTest {
TradingClearingRegistryList predictableTradingClearingRegistryList = new TradingClearingRegistryList();
predictableTradingClearingRegistryList.setAccountId(134L);
predictableTradingClearingRegistryList.setStatus("ACTV");
predictableTradingClearingRegistryList.setCurrency("RUB");
predictableTradingClearingRegistryList.setCurrency("USD");
//ACT
String jsonString = TestUtils.getJsonStringForNew(tcrlNewRequest, ID);

View file

@ -40,6 +40,7 @@ public class HistoryConfig {
hst.add(excludeLiabilitiesRegister());
hst.add(liabilitiesRegister());
hst.add(executionRegister());
hst.add(session());
return hst;
}
@ -174,4 +175,17 @@ public class HistoryConfig {
));
return sbscr;
}
private HistorySubscription session() {
HistorySubscription sbscr = new HistorySubscription();
sbscr.setDestination("session");
sbscr.setSearchProxyMapName(IMDGDistributedNames.Map_SearchSession);
sbscr.setFullHistoryMapName(IMDGDistributedNames.Map_Session);
sbscr.setConditions(List.of(
new ClearingDateFromCondition(pb),
new ClearingDateToCondition(pb)
));
return sbscr;
}
}

View file

@ -1,4 +1,4 @@
package ru.spcex.clearing.backendapi.controller.queue.register;
package ru.spcex.clearing.backendapi.controller.queue.registry;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@ -24,6 +24,7 @@ import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutionException;
// todo unittest for TradingClearingRegistryListController
@Controller
@RequestMapping("/trading-clearing-registries-list")
public class TradingClearingRegistryListController extends AbstractQueueController {

View file

@ -17,6 +17,9 @@ public class AccountInformationNewAction implements IAction<InformationAccountNe
@ApiModelProperty(value = "Наименование статуса", example = "ACTV")
@JsonProperty
private String status;
@ApiModelProperty(value = "Код валюты", example = "RUB")
@JsonProperty
public String currency;
@ApiModelProperty(value = "Наименование типа счета", example = "INFO")
@JsonProperty
private String accountType;
@ -26,6 +29,7 @@ public class AccountInformationNewAction implements IAction<InformationAccountNe
var req = new InformationAccountNewRequest();
req.setCompanyId(this.companyId);
req.setAccount(this.account);
req.setCurrency(this.currency);
req.setStatus(this.status);
req.setAccountType(this.accountType);
return req;

View file

@ -29,6 +29,9 @@ public class AccountNewAction implements IAction<AccountNewRequest> {
@ApiModelProperty(value = "Наименование типа счета", example = "CLRN")
@JsonProperty
private String accountType;
@ApiModelProperty(value = "Код валюты", example = "RUB")
@JsonProperty
private String currency;
@Override
public AccountNewRequest toRequest() {
@ -37,6 +40,7 @@ public class AccountNewAction implements IAction<AccountNewRequest> {
req.setAccount(this.account);
req.setStatus(this.status);
req.setAccountType(this.accountType);
req.setCurrency(this.currency);
return req;
}
@ -77,4 +81,12 @@ public class AccountNewAction implements IAction<AccountNewRequest> {
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}

View file

@ -1,6 +1,6 @@
{
"version": "3.11.0.83",
"version": "3.11.0.86",
"enums": {
@ -4303,7 +4303,7 @@
"name": "Добавление списка счетов ТКР",
"confirmation": "tradingClearingRegistryId,accountId,status",
"confirmation": "tradingClearingRegistryId,accountId",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListNewAction",
@ -4322,7 +4322,7 @@
"name": "Изменение списка счетов ТКР",
"confirmation": "tradingClearingRegistryId,accountId,status",
"confirmation": "id,status",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListUpdateAction",
@ -4764,6 +4764,10 @@
{"code": "accountType",
"type": 12,"name": "Наименование типа счета","shortname": "Тип","link": "accountType","required": true,"visible": false
}
,
{"code": "currency",
"type": 12,"name": "Код валюты","shortname": "Валюта","visible": true,"link": "currencyCode","linkCode": "code"
}
]
}
,
@ -6136,6 +6140,8 @@
"destination": "sessions",
"historyDestination": "history",
"class": "ru.clearing.classes.statics.data.misc.Session",
"logUpdates": "true",

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.11.0.83">
<meta version="3.11.0.86">
<!-- _xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _xsi:noNamespaceSchemaLocation="file:///E:/d/projects/meta/from/meta.xsd" -->
<!--Здесь словари-->
<enums>
@ -997,11 +997,11 @@
<createdAt field="created" type="4" name="Дата и время создания записи" shortname="Создано" searchable="true" sortable="true" ignore="true"/>
<updatedAt field="updated" type="4" name="Дата и время изменения записи" shortname="Изменено" searchable="true" sortable="true" ignore="true"/>
<actions>
<post name="Добавление списка счетов ТКР" confirmation="tradingClearingRegistryId,accountId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListNewAction">
<post name="Добавление списка счетов ТКР" confirmation="tradingClearingRegistryId,accountId" class="ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListNewAction">
<tradingClearingRegistryId type="1" name="Торгово-клиринговый регистр" shortname="ТКР" link="tradingClearingRegistry" linkCode="code"/>
<accountId type="1" name="Идентификатор счёта" shortname="Счёт" link="account" linkCode="account"/>
</post>
<put name="Изменение списка счетов ТКР" confirmation="tradingClearingRegistryId,accountId,status" class="ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListUpdateAction">
<put name="Изменение списка счетов ТКР" confirmation="id,status" class="ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListUpdateAction">
<id type="1" name="Идентификатор записи" shortname="ID" link="clientCode" linkCode="id" required="true"/>
<status type="12" name="Наименование статуса" shortname="Статус" link="serviceStatus" required="true"/>
</put>
@ -1105,6 +1105,7 @@
<account type="2" length="50" name="Номер счета" shortname="Счет"/>
<status type="12" name="Наименование статуса" shortname="Статус" link="serviceStatus"/>
<accountType type="12" name="Наименование типа счета" shortname="Тип" link="accountType" required="true" visible="false"/>
<currency type="12" name="Код валюты" shortname="Валюта" visible="true" link="currencyCode" linkCode="code"/>
</post>
<put name="Изменение счета" confirmation="companyId,account,status" class="ru.spcex.clearing.backendapi.controller.request.cud.account.AccountUpdateAction">
<id type="1" name="Идентификатор записи" shortname="ID" link="account" linkCode="id" required="true"/>
@ -1413,7 +1414,7 @@
</post>
</actions>
</launcher>
<session name="Клиринговые сессии" destination="sessions" class="ru.clearing.classes.statics.data.misc.Session" logUpdates="true" table="session">
<session name="Клиринговые сессии" destination="sessions" historyDestination="history" class="ru.clearing.classes.statics.data.misc.Session" logUpdates="true" table="session">
<id type="1" name="Идентификатор записи" shortname="ID" searchable="true" sortable="true"/>
<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"/>

View file

@ -1,6 +1,6 @@
{
"version": "3.11.0.83",
"version": "3.11.0.86",
"enums": {
@ -4303,7 +4303,7 @@
"name": "Добавление списка счетов ТКР",
"confirmation": "tradingClearingRegistryId,accountId,status",
"confirmation": "tradingClearingRegistryId,accountId",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListNewAction",
@ -4322,7 +4322,7 @@
"name": "Изменение списка счетов ТКР",
"confirmation": "tradingClearingRegistryId,accountId,status",
"confirmation": "id,status",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryListUpdateAction",
@ -4764,6 +4764,10 @@
{"code": "accountType",
"type": 12,"name": "Наименование типа счета","shortname": "Тип","link": "accountType","required": true,"visible": false
}
,
{"code": "currency",
"type": 12,"name": "Код валюты","shortname": "Валюта","visible": true,"link": "currencyCode","linkCode": "code"
}
]
}
,
@ -6136,6 +6140,8 @@
"destination": "sessions",
"historyDestination": "history",
"class": "ru.clearing.classes.statics.data.misc.Session",
"logUpdates": "true",

View file

@ -22,12 +22,12 @@ GRANT ALL PRIVILEGES ON TABLE CURRENCY_SETTLEMENT_TYPE_DICTIONARY TO clearing;
-- currencyPair - Справочник валютных пар
DROP TABLE IF EXISTS CURRENCY_PAIR_DICTIONARY;
CREATE TABLE CURRENCY_PAIR_DICTIONARY(ID bigint PRIMARY KEY, CODE varchar(25), BASE_CURRENCY_ID varchar(4), QUOTE_CURRENCY_ID varchar(4), MAJOR_SIGN varchar(4));
CREATE TABLE CURRENCY_PAIR_DICTIONARY(ID bigint PRIMARY KEY, CODE varchar(25), BASE_CURRENCY varchar(4), QUOTE_CURRENCY varchar(4), MAJOR_SIGN varchar(4));
COMMENT ON TABLE CURRENCY_PAIR_DICTIONARY IS 'Справочник валютных пар';
COMMENT ON COLUMN CURRENCY_PAIR_DICTIONARY.ID IS 'Идентификатор';
COMMENT ON COLUMN CURRENCY_PAIR_DICTIONARY.CODE IS 'Код';
COMMENT ON COLUMN CURRENCY_PAIR_DICTIONARY.BASE_CURRENCY_ID IS 'Код валюты лота (linked to currencyCode)';
COMMENT ON COLUMN CURRENCY_PAIR_DICTIONARY.QUOTE_CURRENCY_ID IS 'Код сопряженной валюты (linked to currencyCode)';
COMMENT ON COLUMN CURRENCY_PAIR_DICTIONARY.BASE_CURRENCY IS 'Код валюты лота (linked to currencyCode)';
COMMENT ON COLUMN CURRENCY_PAIR_DICTIONARY.QUOTE_CURRENCY IS 'Код сопряженной валюты (linked to currencyCode)';
COMMENT ON COLUMN CURRENCY_PAIR_DICTIONARY.MAJOR_SIGN IS 'Код признака конвертируемости валюты (linked to majorSign)';
GRANT ALL PRIVILEGES ON TABLE CURRENCY_PAIR_DICTIONARY TO clearing;
@ -65,7 +65,7 @@ GRANT ALL PRIVILEGES ON TABLE SETTLEMENT_HOUSE_PROPERTIES_HISTORY TO clearing;
-- currencyPairSecurity - Инструменты валютного рынка
DROP TABLE IF EXISTS CURRENCY_PAIR_SECURITY;
CREATE TABLE CURRENCY_PAIR_SECURITY(, CURRENCY_PAIR_ID bigint, BASE_UNIT_SIZE numeric(72,2), CODE varchar(255), SETTLEMENT_TYPE varchar(4), CLEARING_ORGANIZATION varchar(255), SECURITY_ID bigint, ID bigint PRIMARY KEY, CREATED_AT timestamp, UPDATED_AT timestamp);
CREATE TABLE CURRENCY_PAIR_SECURITY(ID bigint PRIMARY KEY, CURRENCY_PAIR_ID bigint, BASE_UNIT_SIZE numeric(72,2), CODE varchar(255), SETTLEMENT_TYPE varchar(4), CLEARING_ORGANIZATION varchar(255), SECURITY_ID bigint, CREATED_AT timestamp, UPDATED_AT timestamp);
COMMENT ON TABLE CURRENCY_PAIR_SECURITY IS 'Инструменты валютного рынка';
COMMENT ON COLUMN CURRENCY_PAIR_SECURITY.CURRENCY_PAIR_ID IS 'Валютная пара (linked to currencyPair)';
COMMENT ON COLUMN CURRENCY_PAIR_SECURITY.BASE_UNIT_SIZE IS 'Количество валюты лота';
@ -81,7 +81,7 @@ GRANT ALL PRIVILEGES ON TABLE CURRENCY_PAIR_SECURITY TO clearing;
-- History log of currencyPairSecurity - Инструменты валютного рынка
DROP TABLE IF EXISTS CURRENCY_PAIR_SECURITY_HISTORY;
CREATE TABLE CURRENCY_PAIR_SECURITY_HISTORY(CURRENCY_PAIR_SECURITY_ID BIGINT NOT NULL, EVENT_TIME timestamp, EVENT_USER_ID BIGINT, EVENT_TYPE VARCHAR(4), , CURRENCY_PAIR_ID bigint, BASE_UNIT_SIZE numeric(72,2), CODE varchar(255), SETTLEMENT_TYPE varchar(4), CLEARING_ORGANIZATION varchar(255), SECURITY_ID bigint, ID bigint PRIMARY KEY, CREATED_AT timestamp, UPDATED_AT timestamp);
CREATE TABLE CURRENCY_PAIR_SECURITY_HISTORY(CURRENCY_PAIR_SECURITY_ID BIGINT NOT NULL, EVENT_TIME timestamp, EVENT_USER_ID BIGINT, EVENT_TYPE VARCHAR(4), ID bigint PRIMARY KEY, CURRENCY_PAIR_ID bigint, BASE_UNIT_SIZE numeric(72,2), CODE varchar(255), SETTLEMENT_TYPE varchar(4), CLEARING_ORGANIZATION varchar(255), SECURITY_ID bigint, CREATED_AT timestamp, UPDATED_AT timestamp);
COMMENT ON TABLE CURRENCY_PAIR_SECURITY_HISTORY IS 'История изменений таблицы currencyPairSecurity';
COMMENT ON COLUMN CURRENCY_PAIR_SECURITY_HISTORY.CURRENCY_PAIR_SECURITY_ID IS 'Идентификатор записи в таблице CURRENCY_PAIR_SECURITY';
COMMENT ON COLUMN CURRENCY_PAIR_SECURITY_HISTORY.EVENT_TIME IS 'Дата и время изменения';

View file

@ -158,7 +158,7 @@ public class GatewayController {
@ResponseBody
public CommonResponse limits(@RequestBody LimitRequest request) {
log.debug("Received message: {}", request);
notificationService.sendLimitNotification(request);
executor.submit(() -> notificationService.sendLimitNotification(request));
return createCommonResponse(request.getId());
}
@ -175,7 +175,10 @@ public class GatewayController {
@ResponseBody
public CommonResponse operations(@RequestBody OperationsRequest request) {
log.debug("Received message: {}", request);
executor.submit(() -> operationService.checkAssetsAndSendMessage(request));
executor.submit(() -> {
operationService.checkAssetsAndSendMessage(request);
notificationService.updateGatewayResultInMap(request);
});
return createCommonResponse(request.getId());
}

View file

@ -10,13 +10,16 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import ru.clearing.classes.statics.data.register.GatewayResult;
import ru.spcex.clearing.gatewayapi.config.GatewayApiSettings;
import ru.spcex.clearing.gatewayapi.config.InboundServerSettings;
import ru.spcex.clearing.gatewayapi.controller.inbound.request.operations.SentAsset;
import ru.spcex.clearing.gatewayapi.controller.outbound.request.OutboundRequest;
import ru.spcex.clearing.gatewayapi.controller.outbound.response.SuccessResponse;
import ru.spcex.clearing.gatewayapi.enums.OutboundRequestType;
import ru.spcex.clearing.gatewayapi.service.builders.GatewayResultBuilder;
import ru.spcex.clearing.gatewayapi.service.builders.OutboundRequestBuilder;
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.AssetOperationListRequest;
@ -32,6 +35,8 @@ import ru.spcex.platform.enumeration.ReportKeys;
import ru.spcex.platform.enumeration.ReportType;
import ru.spcex.platform.enumeration.Section;
import ru.spcex.platform.enumeration.Task;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.IEnumKey;
import java.math.BigDecimal;
@ -47,6 +52,7 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
private final InboundServerSettings inboundServerSettings;
private final Map<Long, List<SentAsset>> sentAssets;
private final Map<UUID, OutboundRequest> outboundRequestByUuid;
protected final Imdg<GatewayResult> gatewayResultImdg;
private final static Pattern REPORT_FILE_NAME_PATTERN = Pattern.compile("(\\S*)_(\\d{15}).csv");
public GatewayService(Consumer<String, Object> kafkaQueue,
@ -55,13 +61,15 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
UserRoleVerification userRoleVerification,
GatewayApiSettings gatewayApiSettings,
@Qualifier("sentAssets") Map<Long, List<SentAsset>> sentAssets,
Map<UUID, OutboundRequest> outboundRequestByUuid) {
Map<UUID, OutboundRequest> outboundRequestByUuid,
ImdgProvider imdgProvider) {
super(kafkaQueue, kafkaProducer);
this.restTemplate = restTemplate;
this.userRoleVerification = userRoleVerification;
this.inboundServerSettings = gatewayApiSettings.getInboundServer();
this.sentAssets = sentAssets;
this.outboundRequestByUuid = outboundRequestByUuid;
this.gatewayResultImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_GatewayResult, GatewayResult.class);
}
@Override
@ -121,6 +129,7 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
HttpEntity<OutboundRequest> request = makeDefaultRequest(outboundFondRequest);
outboundRequestByUuid.put(outboundFondRequest.getId(), outboundFondRequest);
gatewayResultImdg.insert(GatewayResultBuilder.builder().outboundRequest(outboundFondRequest).build());
ResponseEntity<SuccessResponse> response = restTemplate.exchange(url, HttpMethod.POST, request, SuccessResponse.class);
SuccessResponse bodyResponse = response.getBody();
if (bodyResponse != null) {
@ -181,7 +190,9 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
Long requestId = request.getId();
Collection<AssetOperationRequest> assetOperations = request.getRequestPayload().getAssetOperationRequests();
List<SentAsset> assets = new ArrayList<>();
GatewayResultBuilder gatewayBuilder = GatewayResultBuilder.builder();
for (AssetOperationRequest assetOperation : assetOperations) {
gatewayBuilder.assetOperation(assetOperation);
Map<String, Object> content = new HashMap<>() {{
put("direction", assetOperation.getDirection());
put("code", assetOperation.getCode());
@ -199,10 +210,12 @@ public class GatewayService extends QueueConsumer implements InitializingBean {
.type(OutboundRequestType.ASSET_OPERATION.getKey())
.content(content).build();
gatewayBuilder.outboundRequest(outboundRequest);
String url = formingInboundUrl(inboundServerSettings.getPathLOCM());
HttpEntity<OutboundRequest> r = makeDefaultRequest(outboundRequest);
try {
outboundRequestByUuid.put(outboundRequest.getId(), outboundRequest);
gatewayResultImdg.insert(gatewayBuilder.build());
ResponseEntity<SuccessResponse> response = restTemplate.exchange(url, HttpMethod.POST, r, SuccessResponse.class);
SuccessResponse bodyResponse = response.getBody();
if (bodyResponse != null) {

View file

@ -3,16 +3,24 @@ package ru.spcex.clearing.gatewayapi.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.register.GatewayResult;
import ru.spcex.clearing.gatewayapi.controller.inbound.request.limit.LimitRequest;
import ru.spcex.clearing.gatewayapi.controller.inbound.request.operations.OperationsRequest;
import ru.spcex.clearing.gatewayapi.controller.outbound.request.OutboundRequest;
import ru.spcex.clearing.gatewayapi.controller.outbound.response.ErrorResponse;
import ru.spcex.clearing.gatewayapi.enums.OutboundRequestType;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.NotificationNewRequest;
import ru.spcex.clearing.platform.messaging.serialization.LogFormatter;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.enumeration.ObjectType;
import ru.spcex.platform.enumeration.Priority;
import ru.spcex.platform.enumeration.ResultStatuses;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -23,12 +31,15 @@ public class NotificationService {
private final KafkaSender kafkaSender;
private final Map<UUID, OutboundRequest> outboundRequestByUuid;
private final List<String> supportedTypes = List.of(OutboundRequestType.FILL_LIMITS.getKey());
protected final Imdg<GatewayResult> gatewayResultImdg;
private final List<String> supportedTypes = List.of(OutboundRequestType.FILL_LIMITS.getKey(), OutboundRequestType.ASSET_OPERATION.getKey());
public NotificationService(KafkaSender kafkaSender,
Map<UUID, OutboundRequest> outboundRequestByUuid) {
Map<UUID, OutboundRequest> outboundRequestByUuid,
ImdgProvider imdgProvider) {
this.kafkaSender = kafkaSender;
this.outboundRequestByUuid = outboundRequestByUuid;
this.gatewayResultImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_GatewayResult, GatewayResult.class);
}
public void sendLimitNotification(LimitRequest request) {
@ -40,6 +51,9 @@ public class NotificationService {
}
log.info("Receive request: uuid = {}, file = {} with result = {} and sending section = {}.",
request.getId(), request.getLogFile(), request.getResult(), outboundReq.getSection());
updateGatewayResultInMap(request);
newRequest.setObjectType(ObjectType.rgst.getKey());
newRequest.setComment(request.getDescription());
if (request.getResult() != null && request.getResult()) {
@ -53,14 +67,69 @@ public class NotificationService {
kafkaSender.sendRequestToQueue(Consts.NOTIFICATION_NEW, newRequest);
}
public void updateGatewayResultInMap(LimitRequest request) {
if (request.getId() == null || request.getResult() == null) {
log.warn("GatewayResult not found because LimitRequest not valid: {}", LogFormatter.toString(request));
return;
}
GatewayResult gatewayResult = gatewayResultImdg.getFirstObjectByFieldValues(Map.of("requestId", request.getId().toString()));
if (gatewayResult == null) {
log.warn("GatewayResult by requestId = {} not found in map", request.getId().toString());
return;
}
gatewayResult.setUpdated(Instant.now());
gatewayResult.setGatewayResultStatus(request.getResult() ? ResultStatuses.success.getKey() : ResultStatuses.notSuccess.getKey());
gatewayResult.setResult(LogFormatter.toString(request));
gatewayResultImdg.update(gatewayResult);
log.info("Updated gatewayResult: {} in map", LogFormatter.toString(gatewayResult));
}
public void updateGatewayResultInMap(OperationsRequest request) {
if (request.getId() == null || request.getResult() == null) {
log.warn("GatewayResult not found because OperationsRequest not valid: {}", LogFormatter.toString(request));
return;
}
GatewayResult gatewayResult = gatewayResultImdg.getFirstObjectByFieldValues(Map.of("requestId", request.getId().toString()));
if (gatewayResult == null) {
log.warn("GatewayResult by requestId = {} not found in map", request.getId().toString());
return;
}
gatewayResult.setUpdated(Instant.now());
gatewayResult.setGatewayResultStatus(request.getResult() ? ResultStatuses.success.getKey() : ResultStatuses.notSuccess.getKey());
gatewayResult.setResult(LogFormatter.toString(request));
gatewayResultImdg.update(gatewayResult);
log.info("Updated gatewayResult: {} in map", LogFormatter.toString(gatewayResult));
}
public void updateGatewayResultInMap(ErrorResponse response) {
if (response.getId() == null) {
log.warn("GatewayResult not found because OperationsRequest not valid: {}", LogFormatter.toString(response));
return;
}
GatewayResult gatewayResult = gatewayResultImdg.getFirstObjectByFieldValues(Map.of("requestId", response.getId().toString()));
if (gatewayResult == null) {
log.warn("GatewayResult by requestId = {} not found in map", response.getId().toString());
return;
}
gatewayResult.setUpdated(Instant.now());
gatewayResult.setGatewayResultStatus(ResultStatuses.notSuccess.getKey());
gatewayResult.setResult(LogFormatter.toString(response));
gatewayResultImdg.update(gatewayResult);
log.info("Updated gatewayResult: {} in map", LogFormatter.toString(gatewayResult));
}
public void sendErrorNotification(ErrorResponse response, OutboundRequest request) {
NotificationNewRequest newRequest = new NotificationNewRequest();
log.info("Receive ErrorResponse: uuid = {}, file = {} and sending section = {}.",
response.getId(), request.getContent().get("file"), request.getSection());
updateGatewayResultInMap(response);
if (OutboundRequestType.FILL_LIMITS.equalsByKey(request.getType()) && request.getContent() != null && request.getContent().size() > 0)
log.info("Receive ErrorResponse: uuid = {}, file = {}, sending type = {} and section = {}.",
response.getId(), request.getContent().get("file"), request.getType(), request.getSection());
else
log.info("Receive ErrorResponse: uuid = {}, sending type = {} and section = {}.", response.getId(), request.getType(), request.getSection());
newRequest.setObjectType(ObjectType.rgst.getKey());
newRequest.setComment(response.getMessage());
newRequest.setPriority(Priority.HIGH.getKey());
log.info("Sending notification to kafka: {}", newRequest);
log.info("Sending notification to kafka: {}", LogFormatter.toString(newRequest));
kafkaSender.sendRequestToQueue(Consts.NOTIFICATION_NEW, newRequest);
}

View file

@ -7,7 +7,6 @@ import ru.spcex.clearing.gatewayapi.controller.inbound.request.WithSecurityId;
import ru.spcex.clearing.gatewayapi.controller.inbound.request.listing.fond.*;
import ru.spcex.clearing.gatewayapi.service.adapter.SecurityRequestAdapter;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.company.CurrencyPairSecurityGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.EquitySecurityGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.FixedIncomeGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.SecurityFondGatewayRequest;

View file

@ -15,16 +15,22 @@ public class CurrencyPairSecurityRequestAdapter {
CurrencyPairSecurityNewRequest securityNewRequest = new CurrencyPairSecurityNewRequest();
securityNewRequest.setInstrumentType(InstrumentType.CRNC.getKey());
securityNewRequest.setSecuritySymbol(currencyInstrument.getTicker());
securityNewRequest.setShortName(currencyInstrument.getTicker());
securityNewRequest.setFullName(currencyInstrument.getName());
securityNewRequest.setBaseUnitSize(currencyInstrument.getNumberOfLotCurrency());
securityNewRequest.setSettlementType(currencyInstrument.getSettleCode());
securityNewRequest.setClearingOrganization(currencyInstrument.getClearingOrganization());
securityNewRequest.setWorkflowStatus(currencyInstrument.getWorkflowStatus());
//to listing
// Для listing
securityNewRequest.setMinStep(currencyInstrument.getMinStep());
securityNewRequest.setPrecision(currencyInstrument.getPrecision());
securityNewRequest.setLotSize(currencyInstrument.getLotSize());
req.setTradeMode(currencyInstrument.getTradingMode());
// для currencyPairId
req.setLotCurrencyLetterCode(currencyInstrument.getLotCurrencyLetterCode());
req.setMatchedCurrencyLetterCode(currencyInstrument.getMatchedCurrencyLetterCode());
req.setCurrencySecurityNewRequest(securityNewRequest);
// req.setUuid(currencyInstrument.getInitiatorId() != null ? currencyInstrument.getInitiatorId().toString() : null);

View file

@ -0,0 +1,95 @@
package ru.spcex.clearing.gatewayapi.service.builders;
import ru.clearing.classes.statics.data.register.GatewayResult;
import ru.spcex.clearing.gatewayapi.controller.outbound.request.OutboundRequest;
import ru.spcex.clearing.gatewayapi.enums.OutboundRequestType;
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.AssetOperationRequest;
import ru.spcex.clearing.platform.messaging.serialization.LogFormatter;
import ru.spcex.platform.enumeration.InOutDirection;
import ru.spcex.platform.enumeration.Section;
import java.time.Instant;
import static ru.spcex.platform.utils.enumeration.IEnumKey.getEnumByKey;
public class GatewayResultBuilder {
private String requestId;
private String nameRequest;
private String request;
private InOutDirection direction;
private GatewayResultBuilder() {
}
public static GatewayResultBuilder builder() {
return new GatewayResultBuilder();
}
public GatewayResultBuilder assetOperation(AssetOperationRequest assetOperation) {
this.direction = getEnumByKey(InOutDirection.class, assetOperation.getDirection());
return this;
}
public GatewayResultBuilder outboundRequest(OutboundRequest outboundRequest) {
this.request = LogFormatter.toString(outboundRequest);
this.requestId = outboundRequest.getId().toString();
Section section = getEnumByKey(Section.class, outboundRequest.getSection());
if (direction != null && OutboundRequestType.ASSET_OPERATION.equalsByKey(outboundRequest.getType()))
this.nameRequest = getNameReqByAsset(section, direction);
else if (OutboundRequestType.FILL_LIMITS.equalsByKey(outboundRequest.getType()))
this.nameRequest = getNameReqByLim(section);
return this;
}
public GatewayResult build() {
GatewayResult outboundRequest = new GatewayResult();
Instant now = Instant.now();
outboundRequest.setCreated(now);
outboundRequest.setUpdated(now);
outboundRequest.setRequestId(requestId);
outboundRequest.setNameRequest(nameRequest);
outboundRequest.setRequest(request);
return outboundRequest;
}
private String getNameReqByAsset(Section section, InOutDirection direction) {
String nameRequest;
if (InOutDirection.in.equals(direction)) {
if (Section.MKR.equals(section)) {
nameRequest = "Зачисление денежных средств";
} else if (Section.FOND.equals(section)) {
nameRequest = "Зачисление ценных бумаг";
} else if (Section.CURR.equals(section)) {
nameRequest = "Зачисление валютных средств";
} else {
nameRequest = "Зачисление " + section.getKey();
}
} else {
if (Section.MKR.equals(section)) {
nameRequest = "Списание денежных средств";
} else if (Section.FOND.equals(section)) {
nameRequest = "Списание ценных бумаг";
} else if (Section.CURR.equals(section)) {
nameRequest = "Списание валютных средств";
} else {
nameRequest = "Списание " + section.getKey();
}
}
return nameRequest;
}
private String getNameReqByLim(Section section) {
String nameRequest;
if (Section.MKR.equals(section)) {
nameRequest = "Лимиты по денежным средствам";
} else if (Section.FOND.equals(section)) {
nameRequest = "Лимиты по ценным бумагам";
} else if (Section.CURR.equals(section)) {
nameRequest = "Лимиты по валютным средствам";
} else {
nameRequest = "Лимиты по " + section.getKey();
}
return nameRequest;
}
}

View file

@ -432,9 +432,12 @@ class GatewayControllerTest extends AbstractControllerTest{
]
}
""";
CurrListingsRequest cudReqObj = JsonUtil.readValue(CURR_REQ, CurrListingsRequest.class);
Assertions.assertEquals("CNY", cudReqObj.getCurrencyInstrumentList().get(0).getLotCurrencyLetterCode());
Assertions.assertEquals("RUB", cudReqObj.getCurrencyInstrumentList().get(0).getMatchedCurrencyLetterCode());
//ACT
MvcResult mvcResult = perform(MockMvcRequestBuilders.post(LISTING_FOND_URL)
MvcResult mvcResult = perform(MockMvcRequestBuilders.post(LISTING_CURR_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(CURR_REQ))
.andDo(print())//output to the log request and response

View file

@ -32,18 +32,23 @@ import ru.spcex.clearing.gatewayapi.controller.outbound.request.OutboundRequest;
import ru.spcex.clearing.gatewayapi.controller.outbound.response.ErrorResponse;
import ru.spcex.clearing.gatewayapi.controller.outbound.response.SuccessResponse;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.AssetOperationListRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.AssetOperationRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.LimExportedRequest;
import ru.spcex.clearing.test.config.ImdgTestConfig;
import ru.spcex.clearing.test.config.KafkaTestConfig;
import ru.spcex.platform.enumeration.InOutDirection;
import ru.spcex.platform.enumeration.Section;
import ru.spcex.platform.imdg.api.ImdgProvider;
import javax.annotation.PostConstruct;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
@ -61,6 +66,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class GatewayServiceTest {
private static final CharacterEncodingFilter CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter();
public static final String LIMITS_URL = "/limits/";
public static final String OPERATIONS_URL = "/operations/";
private MockRestServiceServer mockServer;
@Autowired
@ -137,6 +143,36 @@ public class GatewayServiceTest {
service.requestOnLimit(req);
}
@Disabled//Для отладки
@Test
void requestOnAsset() throws Exception {
String message = "test response";
BaseRequest<AssetOperationListRequest> req = new BaseRequest<>();
AssetOperationListRequest reqP = new AssetOperationListRequest();
AssetOperationRequest reqI = new AssetOperationRequest();
req.setId(1L);
reqP.setAssetOperationRequests(List.of(reqI));
req.setRequestPayload(reqP);
reqI.setAmount(BigDecimal.ONE);
reqI.setDirection(InOutDirection.in.getKey());
AtomicReference<UUID> uuid = prepareMockServerResponse(HttpStatus.OK, message);
service.requestOnAsset(req);
LimitRequest request = new LimitRequest();
request.setId(uuid.get());
request.setResult(true);
request.setDescription(message);
MvcResult mvcResult = perform(MockMvcRequestBuilders.post(OPERATIONS_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(request)))
.andDo(print())//output to the log request and response
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andReturn();
uuid = prepareMockServerResponse(HttpStatus.BAD_REQUEST, message);
service.requestOnAsset(req);
}
public AtomicReference<UUID> prepareMockServerResponse(HttpStatus responseStatus, String message) {
mockServer.reset();

View file

@ -0,0 +1,629 @@
{
"id": "5ae29407-834a-460d-bf1e-612dda694527",
"type": "DAY_START",
"section": "CURR",
"datetime": "26.04.2024 09:30:00:065",
"currency_specification": [
{
"id": "617f3172-20a9-4f83-b008-db4548a4de44",
"ticker": "CNYRUB_TOD_N",
"name": "Спот-инструмент китайский юань с расчетами сегодня без клиринга и расчетов в АО СПВБ",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "N",
"lot_currency_letter_code": "CNY",
"matched_currency_letter_code": "RUB",
"trading_mode": "NVAD",
"lot_size": 1,
"clearing_organization": "АО СПВБ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "НКО АО ПРЦ",
"number_of_lot_currency": 1,
"start_trading_date": "06.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "2",
"workflow_status": "ACTV"
},
{
"id": "3c0fb45e-2d6c-4ece-9444-13acd7426f5c",
"ticker": "ARSRUB_TOD_C",
"name": "тест",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 2,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ARS",
"matched_currency_letter_code": "RUB",
"trading_mode": "UVAV",
"lot_size": 1000,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "13.03.2024",
"specification_approval_number": "123",
"workflow_status": "BLKD"
},
{
"id": "c019b97e-7480-4b8a-83b9-742afc0f8789",
"ticker": "ALLCVE_TOD_C",
"name": "а",
"exchange_offexchange": "EXCHANGE",
"min_step": 5,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "CVE",
"trading_mode": "UVAV",
"lot_size": 2,
"clearing_organization": "в",
"settlement_organization": "а",
"matched_settlement_organization": "п",
"number_of_lot_currency": 2,
"start_trading_date": "14.03.2024",
"specification_approval_date": "14.03.2024",
"specification_approval_number": "4",
"workflow_status": "BLKD"
},
{
"id": "e3577cd1-4d36-4691-91ae-72536896fc64",
"ticker": "EURRUB_TOD_C",
"name": "Спот-инструмент казахстанский тенге с расчетами сегодня с клирингом в АО СПВБ",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "EUR",
"matched_currency_letter_code": "RUB",
"trading_mode": "UVAV",
"lot_size": 10000,
"clearing_organization": "НКО АО ПРЦ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "СПВБ",
"number_of_lot_currency": 1000,
"start_trading_date": "15.03.2024",
"specification_approval_date": "13.03.2024",
"specification_approval_number": "123",
"workflow_status": "ACTV"
},
{
"id": "45c8205e-14d9-4e0f-9a25-4f07702a8ae5",
"ticker": "KZTRUB_TOD_N",
"name": "Спот-инструмент казахстанский тенге с расчетами сегодня без клиринга и расчетов в АО СПВБ",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "N",
"lot_currency_letter_code": "KZT",
"matched_currency_letter_code": "RUB",
"trading_mode": "NVAD",
"lot_size": 10000,
"clearing_organization": "АО СПВБ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "НКО АО ПРЦ",
"number_of_lot_currency": 100,
"start_trading_date": "06.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "2",
"workflow_status": "ACTV"
},
{
"id": "3f30841f-b138-444d-bd5f-2bfc9cc3a6f7",
"ticker": "CADRUB_TOD_C",
"name": "Канадский доллар Рубль РФ",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "CAD",
"matched_currency_letter_code": "RUB",
"trading_mode": "UVAV",
"lot_size": 1000,
"clearing_organization": "АО СПВБ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "НКО АО ПРЦ",
"number_of_lot_currency": 100000,
"start_trading_date": "22.03.2024",
"specification_approval_date": "20.03.2024",
"specification_approval_number": "566",
"workflow_status": "ACTV"
},
{
"id": "31518ec5-244e-4082-9f9c-29a8e4b6d955",
"ticker": "KZTRUB_TOD_C",
"name": "Спот-инструмент казахстанский тенге с расчетами сегодня с клирингом в АО СПВБ",
"exchange_offexchange": "EXCHANGE",
"min_step": 25,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "KZT",
"matched_currency_letter_code": "RUB",
"trading_mode": "UVAV",
"lot_size": 10000,
"clearing_organization": "АО СПВБ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "НКО АО ПРЦ",
"number_of_lot_currency": 100,
"start_trading_date": "06.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "2",
"workflow_status": "ACTV"
},
{
"id": "0742d050-96e7-444b-9e87-66eb875b5776",
"ticker": "EURRUB_TOD_N",
"name": "тестовый инструмент",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 2,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "N",
"lot_currency_letter_code": "EUR",
"matched_currency_letter_code": "RUB",
"trading_mode": "NVAD",
"lot_size": 1000,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 10,
"start_trading_date": "21.03.2024",
"specification_approval_date": "20.03.2024",
"specification_approval_number": "123",
"workflow_status": "ACTV"
},
{
"id": "115ece73-b658-4f7e-b608-d5f50005ccba",
"ticker": "CNYRUB_TOD_C",
"name": "Спот-инструмент китайский юань с расчетами сегодня с клирингом в АО СПВБ",
"exchange_offexchange": "EXCHANGE",
"min_step": 5,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "CNY",
"matched_currency_letter_code": "RUB",
"trading_mode": "UVAV",
"lot_size": 1000,
"clearing_organization": "АО СПВБ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "НКО АО ПРЦ",
"number_of_lot_currency": 1,
"start_trading_date": "06.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "1",
"workflow_status": "ACTV"
},
{
"id": "c20c7b3d-750b-438c-b2c8-06bd49d02642",
"ticker": "EURUSD_TOD_C",
"name": "тест импорт",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "EUR",
"matched_currency_letter_code": "USD",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 1,
"start_trading_date": "12.03.2024",
"specification_approval_date": "11.03.2024",
"specification_approval_number": "123",
"workflow_status": "ACTV"
},
{
"id": "bf158264-7b03-40d2-a3fe-c404f8f87150",
"ticker": "ALLDZD_TOD_C",
"name": "аааааа",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "B0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "DZD",
"trading_mode": "UVAV",
"lot_size": 5,
"clearing_organization": "ррр",
"settlement_organization": "рррр",
"matched_settlement_organization": "рррр",
"number_of_lot_currency": 1111,
"start_trading_date": "08.04.2024",
"specification_approval_date": "03.04.2024",
"specification_approval_number": "аааа",
"workflow_status": "ACTV"
},
{
"id": "ff2c0881-220a-496e-b7f0-fa4487b9457f",
"ticker": "CNYRUB_TOD_R",
"name": "Спот-инструмент китайский юань с расчетами сегодня с клирингом в АО СПВБ",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "R",
"lot_currency_letter_code": "CNY",
"matched_currency_letter_code": "RUB",
"trading_mode": "NVAV",
"lot_size": 1,
"clearing_organization": "АО СПВБ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "НКО АО ПРЦ",
"number_of_lot_currency": 1,
"start_trading_date": "06.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "2",
"workflow_status": "ACTV"
},
{
"id": "4f41bcc3-d66a-4f56-94d8-4c7c2834a834",
"ticker": "ALLBND_TOD_R",
"name": "проверка",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "R",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "BND",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "a",
"settlement_organization": "b",
"matched_settlement_organization": "c",
"number_of_lot_currency": 1,
"start_trading_date": "31.03.2024",
"specification_approval_date": "07.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
},
{
"id": "093de51b-5d80-4362-b942-ede93dca9cd7",
"ticker": "ALLDZD_TOD_R",
"name": "Тестовый инструмент АЛЛ-ДЗД",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 2,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "R",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "DZD",
"trading_mode": "UVAV",
"lot_size": 1000,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "13.03.2024",
"specification_approval_number": "12345",
"workflow_status": "BLKD"
},
{
"id": "a0be959e-f2f2-4c9e-9230-1a28167d20aa",
"ticker": "ALLBWP_TOD_C",
"name": "проверка",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "BWP",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "a",
"settlement_organization": "b",
"matched_settlement_organization": "c",
"number_of_lot_currency": 1,
"start_trading_date": "05.03.2024",
"specification_approval_date": "05.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
},
{
"id": "d49ce1ea-52d7-49e2-a636-dc791270d32d",
"ticker": "DZDALL_TOD_C",
"name": "проверка удаления",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "DZD",
"matched_currency_letter_code": "ALL",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "14.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
},
{
"id": "0417fd5d-080e-4135-8b26-5c0d61116fe0",
"ticker": "ALLALL_TOD_C",
"name": "тест создание",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 2,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "ALL",
"trading_mode": "UVAV",
"lot_size": 1000,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "13.03.2024",
"specification_approval_number": "123",
"workflow_status": "BLKD"
},
{
"id": "3fecd8e4-4f61-4ba4-8494-3c09b84386c4",
"ticker": "ALLCVE_TOD_C",
"name": "проверка ап",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "CVE",
"trading_mode": "UVAV",
"lot_size": 2,
"clearing_organization": "авы",
"settlement_organization": "ыва",
"matched_settlement_organization": "авы",
"number_of_lot_currency": 3,
"start_trading_date": "14.03.2024",
"specification_approval_date": "14.03.2024",
"specification_approval_number": "34",
"workflow_status": "BLKD"
},
{
"id": "b1f864a0-df55-4061-b1c1-3f569d4cea03",
"ticker": "ALLDZD_TOD_C",
"name": "проверка",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "DZD",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "ко",
"settlement_organization": "ро",
"matched_settlement_organization": "рос",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "14.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
},
{
"id": "53440d91-633b-4171-9820-a280a8f8cd32",
"ticker": "ALLKHR_TOD_C",
"name": "абвгд",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "KHR",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "цц",
"settlement_organization": "цц",
"matched_settlement_organization": "цц",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "14.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
},
{
"id": "515d5ae1-185d-4d04-b353-7fb6f119b2b8",
"ticker": "ALLBTN_TOD_C",
"name": "проверка",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "BTN",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "a",
"settlement_organization": "b",
"matched_settlement_organization": "c",
"number_of_lot_currency": 1,
"start_trading_date": "23.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
},
{
"id": "f73d20ad-77a7-48f2-8a69-816d72755c55",
"ticker": "BSDARS_TOD_C",
"name": "проверка",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "B0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "BSD",
"matched_currency_letter_code": "ARS",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "a",
"settlement_organization": "b",
"matched_settlement_organization": "c",
"number_of_lot_currency": 1,
"start_trading_date": "30.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "2",
"workflow_status": "BLKD"
},
{
"id": "aa9c44e0-6808-4b75-883f-421243e1433f",
"ticker": "ALLARS_TOD_C",
"name": "абырвалг",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 2,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "ARS",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 123,
"start_trading_date": "14.03.2024",
"specification_approval_date": "13.03.2024",
"specification_approval_number": "123",
"workflow_status": "BLKD"
},
{
"id": "dce81fd0-7773-4e7e-bd1a-212bdfa1c9d1",
"ticker": "ALLAUD_TOD_C",
"name": "проверка пр",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "AUD",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "кк",
"settlement_organization": "уу",
"matched_settlement_organization": "тт",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "14.03.2024",
"specification_approval_number": "3",
"workflow_status": "BLKD"
},
{
"id": "712a96d1-3076-4130-a0a1-31a500c13753",
"ticker": "KZTRUB_TOD_R",
"name": "Спот-инструмент казахстанский тенге с расчетами сегодня с клирингом в АО СПВБ",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "R",
"lot_currency_letter_code": "KZT",
"matched_currency_letter_code": "RUB",
"trading_mode": "NVAV",
"lot_size": 10000,
"clearing_organization": "АО СПВБ",
"settlement_organization": "НКО АО ПРЦ",
"matched_settlement_organization": "НКО АО ПРЦ",
"number_of_lot_currency": 100,
"start_trading_date": "06.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "2",
"workflow_status": "ACTV"
},
{
"id": "1faf9210-3d59-4686-9bc1-fd720e4cb240",
"ticker": "ALLARS_TOD_C",
"name": "абвгд",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "ARS",
"trading_mode": "UVAV",
"lot_size": 1,
"clearing_organization": "1",
"settlement_organization": "1",
"matched_settlement_organization": "1",
"number_of_lot_currency": 1,
"start_trading_date": "14.03.2024",
"specification_approval_date": "14.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
},
{
"id": "3a32922a-ee15-47f3-b14c-539cb0ac410f",
"ticker": "ALLBBD_TOD_C",
"name": "проверка",
"exchange_offexchange": "EXCHANGE",
"min_step": 1,
"precision": 4,
"settle_code": "T0",
"value_date": "TOD",
"symbol_trading_mode": "C",
"lot_currency_letter_code": "ALL",
"matched_currency_letter_code": "BBD",
"trading_mode": "UVAV",
"lot_size": 2,
"clearing_organization": "а",
"settlement_organization": "б",
"matched_settlement_organization": "в",
"number_of_lot_currency": 1,
"start_trading_date": "08.03.2024",
"specification_approval_date": "06.03.2024",
"specification_approval_number": "1",
"workflow_status": "BLKD"
}
]
}

View file

@ -0,0 +1,22 @@
package ru.spcex.clearing.historyimdg.index;
import ru.spcex.clearing.historyimdg.index.field.SearchWithClearingDate;
import java.time.LocalDate;
public class SearchProxySession extends SearchProxy implements SearchWithClearingDate {
/**
* clearing_date или created_at
*/
private LocalDate clearingDate;
@Override
public LocalDate getClearingDate() {
return clearingDate;
}
@Override
public void setClearingDate(LocalDate clearingDate) {
this.clearingDate = clearingDate;
}
}

View file

@ -0,0 +1,53 @@
package ru.spcex.clearing.historyimdg.mapstores;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import ru.spcex.clearing.historyimdg.index.SearchProxySession;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@Component
public class SearchSessionMapStore extends AbstractSliceMapLoader<SearchProxySession> {
public SearchSessionMapStore(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
protected String getTableName() {
return "session";
}
@Override
protected String fieldOfDay() {
return "clearing_date"; // or "created_at" ;
}
@Override
public Collection<SearchProxySession> load(Collection<Long> keys) {
Map<String, Collection<Long>> paramMap = Collections.singletonMap("ids", keys);
return namedParameterJdbcTemplate.query("select * from " + getTableName() + " where id in (:ids)", paramMap,
(rs, rowNum) -> {
SearchProxySession proxyFond = new SearchProxySession();
proxyFond.setId(rs.getObject("id", Long.class));
LocalDate date = getLocalDateFromSqlDate(rs, "clearing_date");
if (date == null)
date = getLocalDateFromSqlDate(rs, "created_at");
proxyFond.setClearingDate(date);
return proxyFond;
});
}
@Override
public String getMapName() {
return IMDGDistributedNames.Map_SearchSession;
}
@Override
public String[] getIndexingField() {
return new String[]{"clearingDate"};
}
}

View file

@ -65,10 +65,10 @@ public class UpdateMapService extends AbstractUpdateMapService {
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_Session).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_TradingClearingRegistry).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_AccountSymbols).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_CurrencyPairSecurityHistory).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_ExecutionCurrencyHistory).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_SettlementHousePropertiesHistory).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_TradingClearingRegistryListHistory).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_CurrencyPairSecurity).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_ExecutionCurrency).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_SettlementHouseProperties).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_TradingClearingRegistryList).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
}
@Override

View file

@ -74,10 +74,6 @@ public class CurrencyPairSecurityService extends QueueConsumer implements Initia
callback(CommonDeleteRequest.class)
.setFunction(this::deleteCurrencyPairSecurity)
.forDestination(Consts.DESTINATION_CURRENCY_PAIR_SECURITIES_DELETE, callbacks::put);
//todo DESTINATION_GATEWAY_CURRENCY_PAIR_SECURITY see CLS-612, CLS-663
// callback(CurrencyPairSecurityNewGatewayRequest.class)
// .setFunction(this::newCurrencyPairSecurity)
// .forDestination(Consts.DESTINATION_GATEWAY_CURRENCY_PAIR_SECURITY, callbacks::put);
imdgProvider.waitAvailable();
init();
}
@ -113,6 +109,7 @@ public class CurrencyPairSecurityService extends QueueConsumer implements Initia
currencyPairSecurity.setBaseUnitSize(req.getBaseUnitSize());
currencyPairSecurity.setCurrencyPairId(req.getCurrencyPairId());
//todo currencyPairSecurity.setCode(req.getCode());
//req.getPrecision()
currencyPairSecurity.setSettlementType(req.getSettlementType());
currencyPairSecurity.setClearingOrganization(req.getClearingOrganization());
//todo currencyPairSecurity.setSettlementOrganization(req.getSettlementOrganization());

View file

@ -16,27 +16,27 @@ import ru.clearing.classes.statics.data.instrument.issue.EquitySecurity;
import ru.clearing.classes.statics.data.instrument.issue.FixedIncomeCashFlow;
import ru.clearing.classes.statics.data.instrument.issue.FixedIncomeSecurity;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.security.CurrencyPairSecurity;
import ru.clearing.classes.statics.data.security.MoneyMarketSecurity;
import ru.clearing.classes.statics.data.security.Security;
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
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.company.CurrencyPairSecurityGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.EquitySecurityGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.FixedIncomeGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.SecurityFondGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.*;
import ru.spcex.clearing.platform.messaging.domain.cud.security.CurrencyPairSecurityNewGatewayRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.security.CurrencyPairSecurityNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.security.CurrencyPairSecurityUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.securities.validation.ValidationProvider;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.CompanySymbol;
import ru.spcex.platform.enumeration.InstrumentType;
import ru.spcex.platform.enumeration.UserRole;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
@ -53,11 +53,13 @@ public class GatewaySecurityService extends QueueConsumer implements Initializin
private final Imdg<FixedIncomeSecurity> fixedIncomeSecurityImdg;
private final Imdg<EquitySecurity> equitySecurityImdg;
private final Imdg<MoneyMarketSecurity> moneyMarketSecurityImdg;
private final Imdg<CurrencyPairSecurity> currencyPairSecurityImdg;
private final Imdg<Listing> listingImdg;
private final Imdg<CouponPeriod> couponPeriodImdg;
private final Imdg<FixedIncomeCashFlow> fixedIncomeCashFlowImdg;
private final Imdg<CompanySymbols> companySymbolsImdg;
private final Imdg<Company> companyImdg;
private final Imdg<CurrencyPairDictionary> currencyPairDictionaryImdg;
private final ImdgProvider imdgProvider;
private final ImdgId idGenerator;
@ -97,6 +99,8 @@ public class GatewaySecurityService extends QueueConsumer implements Initializin
this.fixedIncomeSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_FixedIncomeSecurity, FixedIncomeSecurity.class);
this.equitySecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_EquitySecurity, EquitySecurity.class);
this.moneyMarketSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class);
this.currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class);
this.currencyPairDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairDictionary, CurrencyPairDictionary.class);
this.currencyPairSecurityService = currencyPairSecurityService;
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
this.couponPeriodImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CouponPeriod, CouponPeriod.class);
@ -129,9 +133,9 @@ public class GatewaySecurityService extends QueueConsumer implements Initializin
callback(MoneyMarketSecurityNewGatewayRequest.class)
.setFunction(this::newMoneyMarketSecurity)
.forDestination(Consts.DESTINATION_GATEWAY_MONEY_MARKET_SECURITY, callbacks::put);
callback(CurrencyPairSecurityGatewayRequest.class)
.setFunction(this::newSecurities)
.forDestination(Consts.DESTINATION_SECURITY_CURRENCY_GATEWAY, callbacks::put);
callback(CurrencyPairSecurityNewGatewayRequest.class)
.setFunction(this::newSecuritiesCurrencyPair)
.forDestination(Consts.DESTINATION_GATEWAY_CURRENCY_PAIR_SECURITY, callbacks::put);
imdgProvider.waitAvailable();
init();
@ -183,6 +187,97 @@ public class GatewaySecurityService extends QueueConsumer implements Initializin
}
}
private RequestInfoUpdate newSecuritiesCurrencyPair(BaseRequest<?> baseRequest) {
log.debug("CurrencyPairSecurityGatewayRequest id={} received", baseRequest.getId());
CurrencyPairSecurityNewGatewayRequest req = (CurrencyPairSecurityNewGatewayRequest) baseRequest.getRequestPayload();
Security security = null;
Long securityId = null;
try {
CurrencyPairSecurityNewRequest currencyPairRequest = req.getCurrencySecurityNewRequest();
if (currencyPairRequest != null) {
if (StringUtils.isEmpty(currencyPairRequest.getSecuritySymbol())) {
log.warn("Skip creating CurrencyPairSecurity without securityId");
return null;
}
log.debug("Processed request with securitySymbol: {}", currencyPairRequest.getSecuritySymbol());
if (req.getLotCurrencyLetterCode() == null || req.getMatchedCurrencyLetterCode() == null) {
log.warn("Required field was empty: LotCurrencyLetterCode={}, MatchedCurrencyLetterCode={}",
req.getLotCurrencyLetterCode(), req.getMatchedCurrencyLetterCode());
} else {
CurrencyPairDictionary currencyPairD = currencyPairDictionaryImdg.getFirstObjectByFieldValues(Map.of(
"baseCurrency", req.getLotCurrencyLetterCode(),
"quoteCurrency", req.getMatchedCurrencyLetterCode()
));
if (currencyPairD == null) {
log.warn("CurrencyPairDictionary not found by {}/{}",
req.getLotCurrencyLetterCode(), req.getMatchedCurrencyLetterCode());
} else {
log.trace("CurrencyPairId={} by {}/{}", currencyPairD.getId(),
req.getLotCurrencyLetterCode(), req.getMatchedCurrencyLetterCode());
currencyPairRequest.setCurrencyPairId(currencyPairD.getId());
}
}
String securitySymbol = currencyPairRequest.getSecuritySymbol();
security = findSecurityBySecuritySymbol(currencyPairSecurityImdg, securitySymbol);
if (security == null) {
security = currencyPairSecurityService.newCurrencyPairSecurity0(currencyPairRequest);
} else {
CurrencyPairSecurityUpdateRequest updateRequest = toUpdateRequest(security, currencyPairRequest);
security = currencyPairSecurityService.updateCurrencyPairSecurity0(updateRequest);
}
securityId = security.getId();
{
ListingNewRequest listingReq = new ListingNewRequest();
listingReq.setSecurityId(securityId);
listingReq.setMarket(req.getTradeMode());
listingReq.setLotSize(currencyPairRequest.getLotSize());
listingReq.setSymbolCode(currencyPairRequest.getSecuritySymbol());
listingReq.setMinStep(currencyPairRequest.getMinStep());
listingReq.setPrecision(currencyPairRequest.getPrecision());
listingReq.setSymbolName(security.getFullName());
listingReq.setTradingCurrency(CurrencyCode.RUB.getKey());
Listing existListing = findListing(listingReq);
if (existListing == null) {
log.trace("For currency pair security[{}] do new Listing", securityId);
Listing listing = listingService.newListing0(listingReq);
log.debug("New listing.id={}", listing.getId());
} else {
log.trace("For currency pair security[{}] do update Listing[{}]", securityId, existListing.getId());
ListingUpdateRequest partUpdateRequest = toUpdateRequest(existListing, listingReq);
Listing listing = listingService.updateListing0(partUpdateRequest);
log.debug("Has updated listing.id={}", listing.getId());
}
}
} else {
log.warn("currencyPairSecurityGatewayRequest is null");
}
} catch (ValidationException expected) {
if (security == null) {
log.error("Error create or update issue: {}", messageResolver.resolve(expected.getEnumMsg()));
return requestHelper.makeErrorResponse(baseRequest, expected.getEnumMsg());
} else {
log.warn("Error create or update issue: {}. But issue id={} found, try continue...",
messageResolver.resolve(expected.getEnumMsg()), security.getId());
}
}
if (security == null) {
log.error("No new or update security.");
} else {
log.debug("Use security {}.id={} ({} {})", security.getClass().getSimpleName(), securityId, security.getInstrumentType(), security.getShortName());
}
log.debug("successfully processed, request id {}",
baseRequest.getId());
return null; // default success
}
private RequestInfoUpdate newSecurities(BaseRequest<?> baseRequest) {
log.debug("SecurityFondGatewayRequest id={} received", baseRequest.getId());
SecurityFondGatewayRequest req = (SecurityFondGatewayRequest) baseRequest.getRequestPayload();
@ -237,26 +332,7 @@ public class GatewaySecurityService extends QueueConsumer implements Initializin
}
}
if (InstrumentType.CRNC.equalsByKey(req.getSecurityType())) {
// CurrencyPairSecurityGatewayRequest currencyPairSecurityGatewayRequest = (CurrencyPairSecurityGatewayRequest) req;
// CurrencyPairSecurityNewRequest currencyPairRequest = currencyPairSecurityGatewayRequest.getSecurity();
// if (StringUtils.isEmpty(currencyPairRequest.getSecuritySymbol())) {
// log.warn("Skip creating CurrencyPairSecurity without securityId: uuid: {}", req.getUuid());
// return null;
// }
// log.debug("Processed request with securitySymbol: {}", currencyPairRequest.getSecuritySymbol());
// currencyPairRequest.setIssuerId(companyId);
// log.trace("EquitySecurityNewRequest - FOND");
// String securitySymbol = currencyPairRequest.getSecuritySymbol();
// security = findSecurityBySecuritySymbol(currencyPairSecurityImdg, securitySymbol);
//
// if (security == null) {
// security = currencyPairSecurityService.newEquity0(currencyPairRequest);
// } else {
// EquitySecurityUpdateRequest updateRequest = toUpdateRequest(security, currencyPairRequest);
// security = currencyPairSecurityService.updateEquity0(updateRequest);
// }
// //fixme currencypair будет отдельная задача
throw new IllegalStateException("todo CRNC");
throw new IllegalStateException("CRNC support in other function"); // см. другой метод.
}
} catch (ValidationException expected) {
if (security == null) {
@ -460,6 +536,8 @@ public class GatewaySecurityService extends QueueConsumer implements Initializin
updateRequest.setWorkflowStatus(newRequest.getWorkflowStatus());
updateRequest.setSymbolCode(newRequest.getSymbolCode());
updateRequest.setSymbolName(newRequest.getSymbolName());
updateRequest.setMinStep(newRequest.getMinStep());
updateRequest.setPrecision(newRequest.getPrecision());
return updateRequest;
}
@ -536,4 +614,22 @@ public class GatewaySecurityService extends QueueConsumer implements Initializin
return updateRequest;
}
CurrencyPairSecurityUpdateRequest toUpdateRequest(Security currencyPairSecurity, CurrencyPairSecurityNewRequest newRequest) {
var updateRequest = new CurrencyPairSecurityUpdateRequest();
updateRequest.setId(currencyPairSecurity.getId());
updateRequest.setInstrumentType(newRequest.getInstrumentType());
updateRequest.setSecuritySymbol(newRequest.getSecuritySymbol());
updateRequest.setShortName(newRequest.getShortName());
updateRequest.setFullName(newRequest.getFullName());
updateRequest.setCurrencyPairId(newRequest.getCurrencyPairId());
updateRequest.setLotSize(newRequest.getLotSize());
updateRequest.setMinStep(newRequest.getMinStep());
// updateRequest.setPrecision(newRequest.getPrecision());
updateRequest.setBaseUnitSize(newRequest.getBaseUnitSize());
updateRequest.setSettlementType(newRequest.getSettlementType());
updateRequest.setWorkflowStatus(newRequest.getWorkflowStatus());
updateRequest.setClearingOrganization(newRequest.getClearingOrganization());
return updateRequest;
}
}

View file

@ -125,6 +125,8 @@ public class ListingService extends QueueConsumer implements InitializingBean {
} else {
listing.setWorkflowStatus(req.getWorkflowStatus());
}
listing.setMinStep(req.getMinStep());
listing.setPrecision(req.getPrecision());
listingImdg.insert(listing);
return listing;
@ -163,6 +165,8 @@ public class ListingService extends QueueConsumer implements InitializingBean {
if (StringUtils.isNotEmpty(req.getWorkflowStatus())) {
listing.setWorkflowStatus(req.getWorkflowStatus());
}
if (req.getMinStep() != null) listing.setMinStep(req.getMinStep());
if (req.getPrecision() != null) listing.setPrecision(req.getPrecision());
listingImdg.update(listing);
return listing;

View file

@ -45,6 +45,11 @@ public class ImdgPredicateBuilderHazelcast implements ImdgPredicateBuilder {
return new ImdgPredicateHazelcast(Predicates.not(Predicates.equal(key, null)));
}
@Override
public ImdgPredicate isNull(String key) {
return new ImdgPredicateHazelcast(Predicates.equal(key, null));
}
@Override
public ImdgPredicate in(String key, Comparable[] values) {
return new ImdgPredicateHazelcast(Predicates.in(key, values));

View file

@ -223,6 +223,7 @@ public final class IMDGDistributedNames {
public static final String Map_SearchExcludeLiabilitiesRegister = "Map_SearchExcludeLiabilitiesRegister";
public static final String Map_SearchLiabilitiesRegister = "Map_SearchLiabilitiesRegister";
public static final String Map_SearchExecutionRegister = "Map_SearchExecutionRegister";
public static final String Map_SearchSession = "Map_SearchSession";
public static final String MAP_SEQUENCE_NAME = "MAP_SEQUENCE_NAME";
private IMDGDistributedNames() {

View file

@ -7,6 +7,7 @@ public interface ImdgPredicateBuilder {
ImdgPredicate greater(String key, Comparable value);
ImdgPredicate less(String key, Comparable value);
ImdgPredicate notNull(String key);
ImdgPredicate isNull(String key);
ImdgPredicate in(String key, Comparable... values);

View file

@ -47,6 +47,11 @@ public class ImdgPredicateBuilderSqlMock implements ImdgPredicateBuilder {
return new SimpleSQLPredicate(key + " is not null");
}
@Override
public ImdgPredicate isNull(String key) {
return new SimpleSQLPredicate(key + " is null");
}
@Override
public ImdgPredicate in(String key, Comparable[] values) {
String enumiration = Arrays.stream(values).map(this::escape).collect(Collectors.joining(", "));

View file

@ -16,7 +16,7 @@ public interface Consts {
String DESTINATION_SECURITY_BOND_GATEWAY = "security-bond-gateway-request-new";
String DESTINATION_SECURITY_EQTY_GATEWAY = "security-eqty-gateway-request-new";
String DESTINATION_SECURITY_CURRENCY_GATEWAY = "security-currency-pair-gateway-request-new";
String DESTINATION_GATEWAY_CURRENCY_PAIR_SECURITY = "currency-pair-securities-gateway-new"; // "security-currency-pair-gateway-request-new"
String DESTINATION_FIXED_INCOME_CASH_FLOW_NEW = "fixed-income-cash-flow-new";
String DESTINATION_FIXED_INCOME_CASH_FLOW_UPDATE = "fixed-income-cash-flow-update";
@ -188,7 +188,6 @@ public interface Consts {
String DESTINATION_TRADING_CLEARING_REGISTRY_ON_TCRLIST_NEW = "registry-on-trading_clearing_registry_list-new";
String DESTINATION_GATEWAY_CURRENCY_PAIR_SECURITY = "currency-pair-securities-gateway-new";
String DESTINATION_CURRENCY_PAIR_SECURITIES_NEW = "currency-pair-securities-new";
String DESTINATION_CURRENCY_PAIR_SECURITIES_UPDATE = "currency-pair-securities-update";
String DESTINATION_CURRENCY_PAIR_SECURITIES_DELETE = "currency-pair-securities-delete";

View file

@ -2,45 +2,6 @@ package ru.spcex.clearing.platform.messaging.domain.cud.account;
import com.fasterxml.jackson.annotation.JsonProperty;
public class AccountNewRequest {
@JsonProperty
public Long companyId;
@JsonProperty
public String account;
@JsonProperty
public String status;
@JsonProperty
public String accountType;
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
@Deprecated
public class AccountNewRequest extends CorrespondentAccountNewRequest {
}

View file

@ -2,55 +2,7 @@ package ru.spcex.clearing.platform.messaging.domain.cud.account;
import com.fasterxml.jackson.annotation.JsonProperty;
public class AccountUpdateRequest {
@JsonProperty
public Long id;
@JsonProperty
public Long companyId;
@JsonProperty
public String account;
@JsonProperty
public String status;
@JsonProperty
public String accountType;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
@Deprecated
public class AccountUpdateRequest extends CorrespondentAccountUpdateRequest{
}

View file

@ -15,6 +15,9 @@ public class CorrespondentAccountNewRequest {
@JsonProperty
public String accountType;
@JsonProperty
public String currency;
public Long getCompanyId() {
return companyId;
}
@ -46,4 +49,12 @@ public class CorrespondentAccountNewRequest {
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}

View file

@ -12,6 +12,9 @@ public class InformationAccountNewRequest {
@JsonProperty
private String status;
@JsonProperty
private String currency;
@JsonProperty
private String accountType;
@ -39,6 +42,14 @@ public class InformationAccountNewRequest {
this.status = status;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public String getAccountType() {
return accountType;
}

View file

@ -1,24 +0,0 @@
package ru.spcex.clearing.platform.messaging.domain.cud.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import ru.spcex.clearing.platform.messaging.domain.cud.security.CurrencyPairSecurityNewRequest;
public class CurrencyPairSecurityGatewayRequest extends SecurityFondGatewayRequest {
@JsonProperty
private CurrencyPairSecurityNewRequest security;
public CurrencyPairSecurityGatewayRequest() {
}
public CurrencyPairSecurityGatewayRequest(CurrencyPairSecurityNewRequest security) {
this.security = security;
}
public CurrencyPairSecurityNewRequest getSecurity() {
return security;
}
public void setSecurity(CurrencyPairSecurityNewRequest security) {
this.security = security;
}
}

View file

@ -19,6 +19,10 @@ public class ListingNewRequest {
private String symbolCode;
@JsonProperty
private String symbolName;
@JsonProperty
private BigDecimal minStep;
@JsonProperty
private BigDecimal precision;
public Long getSecurityId() {
return securityId;
@ -75,4 +79,20 @@ public class ListingNewRequest {
public void setSymbolName(String symbolName) {
this.symbolName = symbolName;
}
public BigDecimal getMinStep() {
return minStep;
}
public void setMinStep(BigDecimal minStep) {
this.minStep = minStep;
}
public BigDecimal getPrecision() {
return precision;
}
public void setPrecision(BigDecimal precision) {
this.precision = precision;
}
}

View file

@ -22,6 +22,10 @@ public class ListingUpdateRequest implements WithId {
private String symbolCode;
@JsonProperty
private String symbolName;
@JsonProperty
private BigDecimal minStep;
@JsonProperty
private BigDecimal precision;
@Override
public Long getId() {
@ -87,4 +91,20 @@ public class ListingUpdateRequest implements WithId {
public void setSymbolName(String symbolName) {
this.symbolName = symbolName;
}
public BigDecimal getMinStep() {
return minStep;
}
public void setMinStep(BigDecimal minStep) {
this.minStep = minStep;
}
public BigDecimal getPrecision() {
return precision;
}
public void setPrecision(BigDecimal precision) {
this.precision = precision;
}
}

View file

@ -3,18 +3,16 @@ package ru.spcex.clearing.platform.messaging.domain.cud.security;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CurrencyPairSecurityNewGatewayRequest {
@JsonProperty
private String uuid;
@JsonProperty
private CurrencyPairSecurityNewRequest currencySecurityNewRequest;
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
// in currencySecurityNewRequest:
@JsonProperty
private String tradeMode;
@JsonProperty
private String lotCurrencyLetterCode;
@JsonProperty
private String matchedCurrencyLetterCode;
public CurrencyPairSecurityNewRequest getCurrencySecurityNewRequest() {
return currencySecurityNewRequest;
@ -23,4 +21,28 @@ public class CurrencyPairSecurityNewGatewayRequest {
public void setCurrencySecurityNewRequest(CurrencyPairSecurityNewRequest currencySecurityNewRequest) {
this.currencySecurityNewRequest = currencySecurityNewRequest;
}
public String getTradeMode() {
return tradeMode;
}
public void setTradeMode(String tradeMode) {
this.tradeMode = tradeMode;
}
public String getLotCurrencyLetterCode() {
return lotCurrencyLetterCode;
}
public void setLotCurrencyLetterCode(String lotCurrencyLetterCode) {
this.lotCurrencyLetterCode = lotCurrencyLetterCode;
}
public String getMatchedCurrencyLetterCode() {
return matchedCurrencyLetterCode;
}
public void setMatchedCurrencyLetterCode(String matchedCurrencyLetterCode) {
this.matchedCurrencyLetterCode = matchedCurrencyLetterCode;
}
}