securities-service http://jira.mfd.msk:8088/browse/CLS-326 Listing-валидация.
This commit is contained in:
parent
14915bf450
commit
53a574f34f
6 changed files with 343 additions and 99 deletions
|
|
@ -0,0 +1,77 @@
|
||||||
|
package ru.spcex.clearing.validation.common.rules;
|
||||||
|
|
||||||
|
import ru.clearing.platform.dictionary.AbstractDictionary;
|
||||||
|
import ru.spcex.platform.classes.base.SpcexObjectBase;
|
||||||
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
|
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
|
||||||
|
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
|
||||||
|
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
|
||||||
|
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||||
|
import ru.spcex.platform.utils.enumeration.IErrorEnumId;
|
||||||
|
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверка поля с кодом из таблицы (аналог IdPresentRule / DictionaryPresentRule)
|
||||||
|
*
|
||||||
|
* @param <R> Класс проверяемого объекта
|
||||||
|
* @param <T> Класс искомого объекта (mapName)
|
||||||
|
*/
|
||||||
|
public record SpecialIdPresentRule<R, T extends SpcexObjectBase>(String fieldName,
|
||||||
|
Function<R, String> getter,
|
||||||
|
String keyName,
|
||||||
|
String mapName,
|
||||||
|
Class<T> mapClass,
|
||||||
|
IErrorEnumId errorEmptyRequiredValue,
|
||||||
|
IErrorEnumId errorWrongDictionaryValue,
|
||||||
|
boolean required,
|
||||||
|
Function<T, IErrorEnumId>[] additionalChecks) implements IValidationRule<ImdgValidationContext<R>> {
|
||||||
|
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <R, T extends SpcexObjectBase> SpecialIdPresentRule<R, T> instance(String fieldName,
|
||||||
|
Function<R, String> getter,
|
||||||
|
String keyName,
|
||||||
|
String mapName,
|
||||||
|
Class<T> mapClass,
|
||||||
|
IErrorEnumId errorEmptyRequiredValue,
|
||||||
|
IErrorEnumId errorWrongDictionaryValue,
|
||||||
|
boolean required,
|
||||||
|
Function<T, IErrorEnumId>... additionalChecks) {
|
||||||
|
return new SpecialIdPresentRule<>(fieldName, getter,
|
||||||
|
keyName, mapName, mapClass,
|
||||||
|
errorEmptyRequiredValue, errorWrongDictionaryValue,
|
||||||
|
required, additionalChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<EnumMessage> validate(ImdgValidationContext<R> context) {
|
||||||
|
R validatedObject = context.getValidatedObject();
|
||||||
|
String kValue = getter.apply(validatedObject);
|
||||||
|
if (kValue == null) return required ? of(errorEmptyRequiredValue, fieldName) : empty();
|
||||||
|
Imdg<T> dictImdg = context.obtainMap(mapName, mapClass);
|
||||||
|
Collection<T> fromMap = dictImdg.getCollectionObjectsByFieldValues(Map.of(keyName, kValue));
|
||||||
|
if (fromMap.isEmpty()) {
|
||||||
|
return of(errorWrongDictionaryValue, fieldName);
|
||||||
|
}
|
||||||
|
T oFromMap = fromMap.iterator().next();
|
||||||
|
if (oFromMap == null) {
|
||||||
|
return of(errorWrongDictionaryValue, fieldName);
|
||||||
|
}
|
||||||
|
for (Function<T, IErrorEnumId> additionalCheck : additionalChecks) {
|
||||||
|
IErrorEnumId validationError = additionalCheck.apply(oFromMap);
|
||||||
|
if (validationError != null)
|
||||||
|
return of(validationError, fieldName);
|
||||||
|
}
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String ruleName() {
|
||||||
|
return getClass().getSimpleName() + "{" + fieldName + " - " + mapName + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,10 @@ public enum SecuritiesError implements IErrorEnumId {
|
||||||
CouponPeriodNotFound(1014L),
|
CouponPeriodNotFound(1014L),
|
||||||
CurrencyAlreadyExists(1015L),
|
CurrencyAlreadyExists(1015L),
|
||||||
CurrencyNotFound(1016L),
|
CurrencyNotFound(1016L),
|
||||||
|
ListingAlreadyExist(1017L), // Инструмент на режиме %s уже существует
|
||||||
|
ListingNotFound(1017L), // Инструмент на режиме %s не найден
|
||||||
|
MarketNotFound(1020L), // Режим %s не найден
|
||||||
|
ListingOnMMSCreatedBySystem(1021L), // Информиция об инструментах Денежного рынка на режимах добавляется автоматически
|
||||||
;
|
;
|
||||||
private final Long id;
|
private final Long id;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,7 @@ import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.clearing.classes.statics.data.instrument.issue.EquitySecurity;
|
|
||||||
import ru.clearing.classes.statics.data.instrument.issue.FixedIncomeSecurity;
|
|
||||||
import ru.clearing.classes.statics.data.misc.Listing;
|
import ru.clearing.classes.statics.data.misc.Listing;
|
||||||
import ru.clearing.classes.statics.data.security.MoneyMarketSecurity;
|
|
||||||
import ru.clearing.classes.statics.data.security.Security;
|
import ru.clearing.classes.statics.data.security.Security;
|
||||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||||
|
|
@ -21,7 +18,8 @@ import ru.spcex.clearing.platform.messaging.domain.cud.securitites.ListingNewReq
|
||||||
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.ListingUpdateRequest;
|
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.ListingUpdateRequest;
|
||||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||||
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
|
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
|
||||||
import ru.spcex.clearing.securities.validation.ValidationProvider;
|
import ru.spcex.clearing.util.security.SecuritySelector;
|
||||||
|
import ru.spcex.clearing.securities.validation.ListingValidationProvider;
|
||||||
import ru.spcex.clearing.util.security.UserRoleVerification;
|
import ru.spcex.clearing.util.security.UserRoleVerification;
|
||||||
import ru.spcex.clearing.validation.common.ValidationHelper;
|
import ru.spcex.clearing.validation.common.ValidationHelper;
|
||||||
import ru.spcex.platform.enumeration.UserRole;
|
import ru.spcex.platform.enumeration.UserRole;
|
||||||
|
|
@ -29,7 +27,6 @@ import ru.spcex.platform.enumeration.WorkflowStatus;
|
||||||
import ru.spcex.platform.imdg.api.Imdg;
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
import ru.spcex.platform.imdg.api.ImdgId;
|
import ru.spcex.platform.imdg.api.ImdgId;
|
||||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||||
import ru.spcex.platform.imdg.api.ImdgTransaction;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
|
|
@ -37,29 +34,25 @@ import java.time.Instant;
|
||||||
public class ListingService extends QueueConsumer implements InitializingBean {
|
public class ListingService extends QueueConsumer implements InitializingBean {
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private final Imdg<FixedIncomeSecurity> fixedIncomeSecurityImdg;
|
|
||||||
private final Imdg<MoneyMarketSecurity> moneyMarketSecurityImdg;
|
|
||||||
private final Imdg<EquitySecurity> equitySecurity;
|
|
||||||
|
|
||||||
private final Imdg<Listing> listingImdg;
|
private final Imdg<Listing> listingImdg;
|
||||||
private final ImdgProvider imdgProvider;
|
private final ImdgProvider imdgProvider;
|
||||||
private final ImdgId idGenerator;
|
private final ImdgId idGenerator;
|
||||||
private final ValidationProvider validation;
|
private final ListingValidationProvider validation;
|
||||||
private final UserRoleVerification userRoleVerification;
|
private final UserRoleVerification userRoleVerification;
|
||||||
private final ValidationHelper validationHelper;
|
private final ValidationHelper validationHelper;
|
||||||
|
private final SecuritySelector securitySelector;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ListingService(Consumer<String, Object> kafkaQueue,
|
public ListingService(Consumer<String, Object> kafkaQueue,
|
||||||
Producer<String, Object> kafkaProducer,
|
Producer<String, Object> kafkaProducer,
|
||||||
ImdgProvider imdgProvider,
|
ImdgProvider imdgProvider,
|
||||||
ValidationProvider validation,
|
ListingValidationProvider validation,
|
||||||
UserRoleVerification userRoleVerification,
|
UserRoleVerification userRoleVerification,
|
||||||
ValidationHelper validationHelper) {
|
ValidationHelper validationHelper,
|
||||||
|
SecuritySelector securitySelector) {
|
||||||
super(kafkaQueue, kafkaProducer);
|
super(kafkaQueue, kafkaProducer);
|
||||||
this.validation = validation;
|
this.validation = validation;
|
||||||
this.fixedIncomeSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_FixedIncomeSecurity, FixedIncomeSecurity.class);
|
this.securitySelector = securitySelector;
|
||||||
this.moneyMarketSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class);
|
|
||||||
this.equitySecurity = imdgProvider.getImdg(IMDGDistributedNames.Map_EquitySecurity, EquitySecurity.class);
|
|
||||||
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
||||||
this.imdgProvider = imdgProvider;
|
this.imdgProvider = imdgProvider;
|
||||||
this.idGenerator = imdgProvider.getImdgIdGenerator();
|
this.idGenerator = imdgProvider.getImdgIdGenerator();
|
||||||
|
|
@ -82,42 +75,18 @@ public class ListingService extends QueueConsumer implements InitializingBean {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Security selectSecurityById(Long securityId) {
|
private synchronized RequestInfoUpdate newListing(BaseRequest<ListingNewRequest> userRequest) {
|
||||||
Security security = fixedIncomeSecurityImdg.getSingleObjectByID(securityId);
|
|
||||||
if (security != null) return security;
|
|
||||||
security = moneyMarketSecurityImdg.getSingleObjectByID(securityId);
|
|
||||||
if (security != null) return security;
|
|
||||||
security = equitySecurity.getSingleObjectByID(securityId);
|
|
||||||
if (security != null) return security;
|
|
||||||
|
|
||||||
return security;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RequestInfoUpdate newListing(BaseRequest<ListingNewRequest> userRequest) {
|
|
||||||
ImdgTransaction transaction = imdgProvider.newTransaction();
|
|
||||||
ListingNewRequest req = userRequest.getRequestPayload();
|
ListingNewRequest req = userRequest.getRequestPayload();
|
||||||
|
log.debug("newListing received, id={}", userRequest.getId());
|
||||||
|
|
||||||
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
|
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
|
||||||
if (requestInfoUpdate != null) return requestInfoUpdate;
|
if (requestInfoUpdate != null) return requestInfoUpdate;
|
||||||
// RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, validation.listingNewValidator());
|
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, validation.listingNewValidator());
|
||||||
// if (requestInfoUpdate != null) return requestInfoUpdate;
|
if (requestInfoUpdate != null) return requestInfoUpdate;
|
||||||
/*
|
|
||||||
todo
|
|
||||||
3. Проверяем значения полученных параметров:
|
|
||||||
3.1. Необходимо выполнить ряд проверок, стандартных для всех методов (проверка на обязательность параметров исключена).
|
|
||||||
3.2. Проверить, что в таблице security есть инструмент, для которого нужно добавить листинг по security.id = securityId из очереди. Если такой записи нет, вернуть ошибку (1011) «Инструмент %s не найден».
|
|
||||||
3.3. Проверить, что в таблице security тип инструмента instrumentType ≠ RATE (см. справочник instrumentType). Если тип инструмента другой, вернуть ошибку (1021) «Информиция об инструментах Денежного рынка на режимах добавляется автоматически».
|
|
||||||
3.4. Проверить, что в таблице market есть режим, с которым нужно добавить листинг по market.code = market из очереди. Если такой записи нет, вернуть ошибку (1020) «Режим %s не найден».
|
|
||||||
3.5. Проверить, что еще нет такой же записи в таблице listing по ключу securityId И market И со статусом listing.workflowStatus=ACTV (см. справочник workflowStatus). Если запись существует, вернуть ошибку (1017) «Инструмент на режиме %s уже существует».
|
|
||||||
*/
|
|
||||||
|
|
||||||
log.debug("newListing received");
|
Security security = securitySelector.selectSecurityById(req.getSecurityId());
|
||||||
|
if (security == null) { // never
|
||||||
Security security = selectSecurityById(req.getSecurityId());
|
|
||||||
if (security == null) {
|
|
||||||
log.error("Security not found {}", req.getSecurityId());
|
log.error("Security not found {}", req.getSecurityId());
|
||||||
//return validationHelper.getMessageResolver()
|
|
||||||
//todo error!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Listing listing = new Listing();
|
Listing listing = new Listing();
|
||||||
|
|
@ -141,28 +110,24 @@ public class ListingService extends QueueConsumer implements InitializingBean {
|
||||||
return null; // default success
|
return null; // default success
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestInfoUpdate updateListing(BaseRequest<ListingUpdateRequest> userRequest) {
|
private synchronized RequestInfoUpdate updateListing(BaseRequest<ListingUpdateRequest> userRequest) {
|
||||||
ListingUpdateRequest req = userRequest.getRequestPayload();
|
ListingUpdateRequest req = userRequest.getRequestPayload();
|
||||||
log.debug("updateListing received id = {}", req.getId());
|
log.debug("updateListing received id = {}", req.getId());
|
||||||
|
|
||||||
|
|
||||||
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
|
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
|
||||||
if (requestInfoUpdate != null) return requestInfoUpdate;
|
if (requestInfoUpdate != null) return requestInfoUpdate;
|
||||||
// RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
|
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, validation.listingUpdateValidator());
|
||||||
// if (requestInfoUpdate != null) return requestInfoUpdate;
|
if (requestInfoUpdate != null) return requestInfoUpdate;
|
||||||
|
|
||||||
Listing listing = listingImdg.getSingleObjectByID(req.getId());
|
Listing listing = listingImdg.getSingleObjectByID(req.getId());
|
||||||
|
|
||||||
Security security = selectSecurityById(req.getSecurityId());
|
Security security = securitySelector.selectSecurityById(req.getSecurityId());
|
||||||
if (security == null) {
|
if (security == null) { // never
|
||||||
log.error("Security not found {}", req.getSecurityId());
|
log.error("Security not found {}", req.getSecurityId());
|
||||||
//return validationHelper.getMessageResolver()
|
|
||||||
//todo error!
|
|
||||||
}
|
}
|
||||||
if (listing == null) {
|
if (listing == null) { //never
|
||||||
log.error("listing not found {}", req.getId());
|
log.error("listing not found {}", req.getId());
|
||||||
//return validationHelper.getMessageResolver()
|
|
||||||
//todo error!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listing.setUpdated(Instant.now());
|
listing.setUpdated(Instant.now());
|
||||||
|
|
@ -178,14 +143,14 @@ public class ListingService extends QueueConsumer implements InitializingBean {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestInfoUpdate deleteListing(BaseRequest<CommonDeleteRequest> userRequest) {
|
private synchronized RequestInfoUpdate deleteListing(BaseRequest<CommonDeleteRequest> userRequest) {
|
||||||
CommonDeleteRequest req = userRequest.getRequestPayload();
|
CommonDeleteRequest req = userRequest.getRequestPayload();
|
||||||
log.debug("CommonDeleteRequest received id = {}", req.getId());
|
log.debug("CommonDeleteRequest received id = {}", req.getId());
|
||||||
|
|
||||||
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
|
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
|
||||||
if (requestInfoUpdate != null) return requestInfoUpdate;
|
if (requestInfoUpdate != null) return requestInfoUpdate;
|
||||||
// requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, validation.listingDeleteValidator());
|
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, validation.listingDeleteValidator());
|
||||||
// if (requestInfoUpdate != null) return requestInfoUpdate;
|
if (requestInfoUpdate != null) return requestInfoUpdate;
|
||||||
|
|
||||||
Instant updateTime = Instant.now();
|
Instant updateTime = Instant.now();
|
||||||
Listing listing = listingImdg.getSingleObjectByID(req.getId());
|
Listing listing = listingImdg.getSingleObjectByID(req.getId());
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ public class MoneyMarketSecurityService extends QueueConsumer implements Initial
|
||||||
private final UserRoleVerification userRoleVerification;
|
private final UserRoleVerification userRoleVerification;
|
||||||
private final ValidationHelper validationHelper;
|
private final ValidationHelper validationHelper;
|
||||||
private final IMessageResolver messageResolver;
|
private final IMessageResolver messageResolver;
|
||||||
|
private final ListingService listingService; // для синхронизации
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MoneyMarketSecurityService(Consumer<String, Object> kafkaQueue,
|
public MoneyMarketSecurityService(Consumer<String, Object> kafkaQueue,
|
||||||
|
|
@ -59,7 +60,8 @@ public class MoneyMarketSecurityService extends QueueConsumer implements Initial
|
||||||
ValidationProvider validation,
|
ValidationProvider validation,
|
||||||
UserRoleVerification userRoleVerification,
|
UserRoleVerification userRoleVerification,
|
||||||
ValidationHelper validationHelper,
|
ValidationHelper validationHelper,
|
||||||
IMessageResolver messageResolver) {
|
IMessageResolver messageResolver,
|
||||||
|
ListingService listingService) {
|
||||||
super(kafkaQueue, kafkaProducer);
|
super(kafkaQueue, kafkaProducer);
|
||||||
this.userRoleVerification = userRoleVerification.setRoleForVerification(UserRole.Admin);
|
this.userRoleVerification = userRoleVerification.setRoleForVerification(UserRole.Admin);
|
||||||
this.validationHelper = validationHelper;
|
this.validationHelper = validationHelper;
|
||||||
|
|
@ -69,6 +71,7 @@ public class MoneyMarketSecurityService extends QueueConsumer implements Initial
|
||||||
this.imdgProvider = imdgProvider;
|
this.imdgProvider = imdgProvider;
|
||||||
this.idGenerator = imdgProvider.getImdgIdGenerator();
|
this.idGenerator = imdgProvider.getImdgIdGenerator();
|
||||||
this.messageResolver = messageResolver;
|
this.messageResolver = messageResolver;
|
||||||
|
this.listingService = listingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -139,24 +142,26 @@ public class MoneyMarketSecurityService extends QueueConsumer implements Initial
|
||||||
mms.setWorkflowStatus(req.getWorkflowStatus());
|
mms.setWorkflowStatus(req.getWorkflowStatus());
|
||||||
}
|
}
|
||||||
ImdgTransaction transaction = imdgProvider.newTransaction();
|
ImdgTransaction transaction = imdgProvider.newTransaction();
|
||||||
try {
|
synchronized (listingService) {
|
||||||
transaction.beginTransaction();
|
try {
|
||||||
Imdg<MoneyMarketSecurity> moneyMarketSecurityTxMap = transaction.getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class);
|
transaction.beginTransaction();
|
||||||
Imdg<Listing> listingTxMap = transaction.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
Imdg<MoneyMarketSecurity> moneyMarketSecurityTxMap = transaction.getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class);
|
||||||
//одним скопом выполняем реквест
|
Imdg<Listing> listingTxMap = transaction.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
||||||
moneyMarketSecurityTxMap.insert(mms);
|
//одним скопом выполняем реквест
|
||||||
Listing listing = ListingBuilder.builder()
|
moneyMarketSecurityTxMap.insert(mms);
|
||||||
.append(mms).append(req).build();
|
Listing listing = ListingBuilder.builder()
|
||||||
listingTxMap.insert(listing);
|
.append(mms).append(req).build();
|
||||||
transaction.commitTransaction();
|
listingTxMap.insert(listing);
|
||||||
} catch (Throwable e) {
|
transaction.commitTransaction();
|
||||||
log.error("Error at create security, rollback transaction. {}", ExceptionUtils.getStackTrace(e));
|
} catch (Throwable e) {
|
||||||
transaction.rollbackTransaction();
|
log.error("Error at create security, rollback transaction. {}", ExceptionUtils.getStackTrace(e));
|
||||||
String errorMsg = messageResolver.resolve(new EnumMessage(SecuritiesError.GeneralError));
|
transaction.rollbackTransaction();
|
||||||
return new RequestInfoUpdate()
|
String errorMsg = messageResolver.resolve(new EnumMessage(SecuritiesError.GeneralError));
|
||||||
.setId(userRequest.getId())
|
return new RequestInfoUpdate()
|
||||||
.setStatus(Status.Error)
|
.setId(userRequest.getId())
|
||||||
.setMessage(errorMsg);
|
.setStatus(Status.Error)
|
||||||
|
.setMessage(errorMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.debug("successfully processed, request id {}, new object id {}", userRequest.getId(), mms.getId());
|
log.debug("successfully processed, request id {}, new object id {}", userRequest.getId(), mms.getId());
|
||||||
return null; // default success
|
return null; // default success
|
||||||
|
|
@ -205,18 +210,20 @@ public class MoneyMarketSecurityService extends QueueConsumer implements Initial
|
||||||
mms.setWorkflowStatus(req.getWorkflowStatus());
|
mms.setWorkflowStatus(req.getWorkflowStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.beginTransaction();
|
synchronized (listingService) {
|
||||||
Imdg<MoneyMarketSecurity> moneyMarketSecurityTxMap = transaction.getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class);
|
transaction.beginTransaction();
|
||||||
Imdg<Listing> listingTxMap = transaction.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
Imdg<MoneyMarketSecurity> moneyMarketSecurityTxMap = transaction.getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class);
|
||||||
|
Imdg<Listing> listingTxMap = transaction.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
||||||
|
|
||||||
moneyMarketSecurityTxMap.update(mms);
|
moneyMarketSecurityTxMap.update(mms);
|
||||||
Listing listing = listingTxMap.getSingleObjectByFieldValues(Map.of("securityId", mms.getId()));
|
Listing listing = listingTxMap.getSingleObjectByFieldValues(Map.of("securityId", mms.getId()));
|
||||||
if (listing == null) {
|
if (listing == null) {
|
||||||
log.error("MoneyMarketSecurityUpdateRequest id {} couldn't find listing with securityId {}", req.getId(), mms.getId());
|
log.error("MoneyMarketSecurityUpdateRequest id {} couldn't find listing with securityId {}", req.getId(), mms.getId());
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
listing = updateListingByMms(mms, listing);
|
||||||
|
listingTxMap.update(listing);
|
||||||
}
|
}
|
||||||
listing = updateListingByMms(mms, listing);
|
|
||||||
listingTxMap.update(listing);
|
|
||||||
transaction.commitTransaction();
|
transaction.commitTransaction();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
log.error("Error at update security {}, rollback transaction. {}", req.getId(), ExceptionUtils.getStackTrace(e));
|
log.error("Error at update security {}, rollback transaction. {}", req.getId(), ExceptionUtils.getStackTrace(e));
|
||||||
|
|
@ -251,17 +258,35 @@ public class MoneyMarketSecurityService extends QueueConsumer implements Initial
|
||||||
Instant updateTime = Instant.now();
|
Instant updateTime = Instant.now();
|
||||||
MoneyMarketSecurity mms = validator.getStored(Stored.PresentById);
|
MoneyMarketSecurity mms = validator.getStored(Stored.PresentById);
|
||||||
if (mms == null) log.error("Validator return null stored mms object.");
|
if (mms == null) log.error("Validator return null stored mms object.");
|
||||||
mms.setWorkflowStatus(ru.spcex.platform.enumeration.Status.Blocked.getKey());
|
ImdgTransaction transaction = imdgProvider.newTransaction();
|
||||||
mms.setUpdated(updateTime);
|
try {
|
||||||
moneyMarketSecurityMap.update(mms);
|
synchronized (listingService) {
|
||||||
// Listing listing = listingImdg.getSingleObjectByFieldValues(Map.of("securityId", mms.getId()));
|
transaction.beginTransaction();
|
||||||
// if (listing == null) {
|
Imdg<MoneyMarketSecurity> moneyMarketSecurityTxMap = transaction.getImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, MoneyMarketSecurity.class);
|
||||||
// log.error("CommonDeleteRequest id {} couldn't find listing with securityId {}", req.getId(), mms.getId());
|
Imdg<Listing> listingTxMap = transaction.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
||||||
// return null;
|
|
||||||
// }
|
mms.setWorkflowStatus(WorkflowStatus.Blocked.getKey());
|
||||||
// listing.setWorkflowStatus(ru.spcex.platform.enumeration.Status.Blocked.getKey());
|
mms.setUpdated(updateTime);
|
||||||
// listing.setUpdated(updateTime);
|
moneyMarketSecurityTxMap.update(mms);
|
||||||
// listingImdg.update(listing);
|
Listing listing = listingTxMap.getSingleObjectByFieldValues(Map.of("securityId", mms.getId()));
|
||||||
|
if (listing == null) {
|
||||||
|
log.error("CommonDeleteRequest id {} couldn't find listing with securityId {}", req.getId(), mms.getId());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
listing.setWorkflowStatus(WorkflowStatus.Blocked.getKey());
|
||||||
|
listing.setUpdated(updateTime);
|
||||||
|
listingTxMap.update(listing);
|
||||||
|
}
|
||||||
|
transaction.commitTransaction();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("Error at block security {}, rollback transaction. {}", req.getId(), ExceptionUtils.getStackTrace(e));
|
||||||
|
transaction.rollbackTransaction();
|
||||||
|
String errorMsg = messageResolver.resolve(new EnumMessage(SecuritiesError.GeneralError));
|
||||||
|
return new RequestInfoUpdate()
|
||||||
|
.setId(userRequest.getId())
|
||||||
|
.setStatus(Status.Error)
|
||||||
|
.setMessage(errorMsg);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
package ru.spcex.clearing.securities.validation;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.clearing.classes.statics.data.misc.Listing;
|
||||||
|
import ru.clearing.classes.statics.data.security.Security;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.*;
|
||||||
|
import ru.spcex.clearing.util.security.SecuritySelector;
|
||||||
|
import ru.spcex.clearing.securities.errors.SecuritiesError;
|
||||||
|
import ru.spcex.clearing.validation.common.rules.SpecialIdPresentRule;
|
||||||
|
import ru.spcex.platform.classes.base.SpcexObjectBase;
|
||||||
|
import ru.spcex.platform.enumeration.InstrumentType;
|
||||||
|
import ru.spcex.platform.enumeration.WorkflowStatus;
|
||||||
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
|
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||||
|
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
|
||||||
|
import ru.spcex.platform.imdg.validation.rule.PresentById;
|
||||||
|
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||||
|
import ru.spcex.platform.utils.enumeration.IErrorEnumId;
|
||||||
|
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||||
|
import ru.spcex.platform.utils.validation.IValidator;
|
||||||
|
import ru.spcex.platform.utils.validation.ValidatorImpl;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ListingValidationProvider {
|
||||||
|
final Imdg<SpcexObjectBase> workflowStatusDictionaryImdg;
|
||||||
|
final Imdg<Listing> listingImdg;
|
||||||
|
final SecuritySelector securitySelector;
|
||||||
|
|
||||||
|
|
||||||
|
public ListingValidationProvider(ImdgProvider imdgProvider, SecuritySelector securitySelector) {
|
||||||
|
this.securitySelector = securitySelector;
|
||||||
|
this.workflowStatusDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_WorkflowStatusDictionary, SpcexObjectBase.class);
|
||||||
|
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Function<ListingNewRequest, IValidator> listingNewValidator() {
|
||||||
|
return listingRequest -> {
|
||||||
|
ImdgValidationContext<ListingNewRequest> context = new ImdgValidationContext<>();
|
||||||
|
context.setValidatedObject(listingRequest);
|
||||||
|
context.addImdg(IMDGDistributedNames.Map_WorkflowStatusDictionary, workflowStatusDictionaryImdg);
|
||||||
|
context.addImdg(IMDGDistributedNames.Map_Listing, listingImdg);
|
||||||
|
return new ValidatorImpl<ImdgValidationContext<ListingNewRequest>>(context,
|
||||||
|
new SecurityIdPresentRule<ListingNewRequest>("securityId", ListingNewRequest::getSecurityId,
|
||||||
|
(Security security) ->
|
||||||
|
InstrumentType.RATE.equalsByKey(security.getInstrumentType()) ? SecuritiesError.ListingOnMMSCreatedBySystem : null
|
||||||
|
),
|
||||||
|
SpecialIdPresentRule.instance("market", (ListingNewRequest l) -> l.getMarket(),
|
||||||
|
"market", IMDGDistributedNames.Map_Market,
|
||||||
|
ru.clearing.classes.statics.data.misc.Market.class,
|
||||||
|
SecuritiesError.RequiredFieldIsEmpty, SecuritiesError.MarketNotFound,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
new NotSameActiveListing<>(ListingNewRequest::getSecurityId, ListingNewRequest::getMarket)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<ListingUpdateRequest, IValidator> listingUpdateValidator() {
|
||||||
|
return mmsRequest -> {
|
||||||
|
ImdgValidationContext<ListingUpdateRequest> context = new ImdgValidationContext<>();
|
||||||
|
context.setValidatedObject(mmsRequest);
|
||||||
|
context.addImdg(IMDGDistributedNames.Map_WorkflowStatusDictionary, workflowStatusDictionaryImdg);
|
||||||
|
context.addImdg(IMDGDistributedNames.Map_Listing, listingImdg);
|
||||||
|
return new ValidatorImpl<>(context,
|
||||||
|
new PresentById(IMDGDistributedNames.Map_Listing, SecuritiesError.ListingNotFound, true),
|
||||||
|
new SecurityIdPresentRule<ListingNewRequest>("securityId", ListingNewRequest::getSecurityId,
|
||||||
|
(Security security) ->
|
||||||
|
InstrumentType.RATE.equalsByKey(security.getInstrumentType()) ? SecuritiesError.ListingOnMMSCreatedBySystem : null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<CommonDeleteRequest, IValidator> listingDeleteValidator() {
|
||||||
|
return listingRequest -> {
|
||||||
|
ImdgValidationContext<CommonDeleteRequest> context = new ImdgValidationContext<>();
|
||||||
|
context.setValidatedObject(listingRequest);
|
||||||
|
context.addImdg(IMDGDistributedNames.Map_Listing, listingImdg);
|
||||||
|
return new ValidatorImpl<>(context,
|
||||||
|
new PresentById(IMDGDistributedNames.Map_Listing, SecuritiesError.ListingNotFound, true),
|
||||||
|
new SecurityIdPresentRule<ListingNewRequest>("securityId", ListingNewRequest::getSecurityId,
|
||||||
|
(Security security) ->
|
||||||
|
InstrumentType.RATE.equalsByKey(security.getInstrumentType()) ? SecuritiesError.ListingOnMMSCreatedBySystem : null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class SecurityIdPresentRule<R> implements IValidationRule<ImdgValidationContext<R>> {
|
||||||
|
final String fieldName;
|
||||||
|
final Function<R, Long> idGetter;
|
||||||
|
final boolean required;
|
||||||
|
final IErrorEnumId errorEmptyField = SecuritiesError.RequiredFieldIsEmpty;
|
||||||
|
final IErrorEnumId errorIdNotPresent = SecuritiesError.InstrumentNotFound;
|
||||||
|
List<Function<Security, IErrorEnumId>> additionalChecks = new ArrayList<>();
|
||||||
|
|
||||||
|
public SecurityIdPresentRule(String fieldName, Function<R, Long> idGetter) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
this.idGetter = idGetter;
|
||||||
|
this.required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityIdPresentRule(String fieldName, Function<R, Long> idGetter, Function<Security, IErrorEnumId>... additional) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
this.idGetter = idGetter;
|
||||||
|
this.required = true;
|
||||||
|
additionalChecks = Arrays.asList(additional);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<EnumMessage> validate(ImdgValidationContext<R> context) {
|
||||||
|
R validatedObject = context.getValidatedObject();
|
||||||
|
Long id = idGetter.apply(validatedObject);
|
||||||
|
if (id == null) return required ? of(errorEmptyField, fieldName) : empty();
|
||||||
|
Security fromMap = securitySelector.selectSecurityById(id);
|
||||||
|
if (fromMap == null) {
|
||||||
|
return of(errorIdNotPresent, fieldName);
|
||||||
|
}
|
||||||
|
for (Function<Security, IErrorEnumId> additionalCheck : additionalChecks) {
|
||||||
|
IErrorEnumId validationError = additionalCheck.apply(fromMap);
|
||||||
|
if (validationError != null)
|
||||||
|
return of(validationError, fieldName);
|
||||||
|
}
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String ruleName() {
|
||||||
|
return getClass().getSimpleName() + "{" + fieldName + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NotSameActiveListing<R> implements IValidationRule<ImdgValidationContext<R>> {
|
||||||
|
final Function<R, Long> securityIdGetter;
|
||||||
|
final Function<R, String> marketGetter;
|
||||||
|
|
||||||
|
public NotSameActiveListing(Function<R, Long> securityIdGetter, Function<R, String> marketGetter) {
|
||||||
|
this.securityIdGetter = securityIdGetter;
|
||||||
|
this.marketGetter = marketGetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<EnumMessage> validate(ImdgValidationContext<R> context) {
|
||||||
|
R validatedObject = context.getValidatedObject();
|
||||||
|
Long securityId = securityIdGetter.apply(validatedObject);
|
||||||
|
if (securityId == null) return empty();
|
||||||
|
String market = marketGetter.apply(validatedObject);
|
||||||
|
if (market == null) return empty();
|
||||||
|
Imdg<Listing> listingImdg = context.obtainMap(IMDGDistributedNames.Map_Listing, Listing.class);
|
||||||
|
Listing fromMap = listingImdg.getSingleObjectByFieldValues(Map.of(
|
||||||
|
"securityId", securityId,
|
||||||
|
"market", market,
|
||||||
|
"workflowStatus", WorkflowStatus.Active.getKey()
|
||||||
|
));
|
||||||
|
if (fromMap == null) {
|
||||||
|
return empty();
|
||||||
|
} else {
|
||||||
|
return of(SecuritiesError.ListingAlreadyExist, market, securityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String ruleName() {
|
||||||
|
return getClass().getSimpleName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,6 +37,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv
|
||||||
EquitySecurityService.class,
|
EquitySecurityService.class,
|
||||||
FixedIncomeSecurityService.class,
|
FixedIncomeSecurityService.class,
|
||||||
MoneyMarketSecurityService.class,
|
MoneyMarketSecurityService.class,
|
||||||
|
ListingService.class,
|
||||||
ImdgTestConfig.class,
|
ImdgTestConfig.class,
|
||||||
KafkaTestConfig.class,
|
KafkaTestConfig.class,
|
||||||
ValidationProvider.class,
|
ValidationProvider.class,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue