Merge remote-tracking branch 'origin/CLS_258_259' into CLS_258_259
This commit is contained in:
commit
7833e7c669
23 changed files with 320 additions and 97 deletions
|
|
@ -4,8 +4,8 @@
|
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>clearing-utils</artifactId> <!-- todo refactor - rename to clearing-validation -->
|
||||
<name>clearing-utils</name>
|
||||
<artifactId>clearing-validation</artifactId> <!-- todo refactor - rename to clearing-validation -->
|
||||
<name>clearing-validation</name>
|
||||
<description>Clearing-module, dependency version of platform-utils</description>
|
||||
<packaging>jar</packaging>
|
||||
<version>SPCEX-1.0.0.0</version>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
* Утилиты с зависимостями от множества модулей clearing-*
|
||||
*/
|
||||
/**
|
||||
* Утилиты с зависимостями от множества модулей clearing-*
|
||||
*/
|
||||
package ru.spcex.clearing.util;
|
||||
|
|
@ -1,66 +1,66 @@
|
|||
package ru.spcex.clearing.util.services.exchangers;
|
||||
|
||||
import org.apache.kafka.clients.consumer.Consumer;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||
|
||||
/**
|
||||
* Синхронный обмен сообщениями с ассинхронным сервисом.
|
||||
* Метод exchange() отправляет сообщение в очередь и дожидается ответа из другой очереди
|
||||
*/
|
||||
public class BiDirectionQueueExchanger<TIn, TOut extends BaseRequest<?>> extends QueueConsumer implements InitializingBean, DisposableBean {
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
protected final Object sync = new Object();
|
||||
protected String outQueue;
|
||||
protected String inQueue;
|
||||
protected Class<TIn> listenClass;
|
||||
protected long timeout;
|
||||
|
||||
/**
|
||||
* Синхронно-ассинхронный обмен сообщениями
|
||||
*
|
||||
* @param kafkaQueue
|
||||
* @param kafkaProducer
|
||||
* @param outQueue отправляет в очередь
|
||||
* @param inQueue слушает очередь, ожидает ответов
|
||||
* @param listenClass типы объектов из inQueue
|
||||
* @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено
|
||||
*/
|
||||
public BiDirectionQueueExchanger(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer,
|
||||
String outQueue,
|
||||
String inQueue, Class<TIn> listenClass,
|
||||
long timeout) {
|
||||
super(kafkaQueue, kafkaProducer);
|
||||
this.outQueue = outQueue;
|
||||
this.inQueue = inQueue;
|
||||
this.listenClass = listenClass;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить сообщение message в outQueue и дождаться ответа из очереди inQueue
|
||||
*
|
||||
* @param message
|
||||
* @return
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public TOut exchange(TIn message) throws InterruptedException {
|
||||
//todo impl BiDirectionQueueExchanger
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
log.debug("Listener {} for async exchange {}-{} close", this, outQueue, inQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
log.debug("Listener {} for async exchange {}-{} ready", this, outQueue, inQueue);
|
||||
}
|
||||
}
|
||||
package ru.spcex.clearing.util.services.exchangers;
|
||||
|
||||
import org.apache.kafka.clients.consumer.Consumer;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||
|
||||
/**
|
||||
* Синхронный обмен сообщениями с ассинхронным сервисом.
|
||||
* Метод exchange() отправляет сообщение в очередь и дожидается ответа из другой очереди
|
||||
*/
|
||||
public class BiDirectionQueueExchanger<TIn, TOut extends BaseRequest<?>> extends QueueConsumer implements InitializingBean, DisposableBean {
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
protected final Object sync = new Object();
|
||||
protected String outQueue;
|
||||
protected String inQueue;
|
||||
protected Class<TIn> listenClass;
|
||||
protected long timeout;
|
||||
|
||||
/**
|
||||
* Синхронно-ассинхронный обмен сообщениями
|
||||
*
|
||||
* @param kafkaQueue
|
||||
* @param kafkaProducer
|
||||
* @param outQueue отправляет в очередь
|
||||
* @param inQueue слушает очередь, ожидает ответов
|
||||
* @param listenClass типы объектов из inQueue
|
||||
* @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено
|
||||
*/
|
||||
public BiDirectionQueueExchanger(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer,
|
||||
String outQueue,
|
||||
String inQueue, Class<TIn> listenClass,
|
||||
long timeout) {
|
||||
super(kafkaQueue, kafkaProducer);
|
||||
this.outQueue = outQueue;
|
||||
this.inQueue = inQueue;
|
||||
this.listenClass = listenClass;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить сообщение message в outQueue и дождаться ответа из очереди inQueue
|
||||
*
|
||||
* @param message
|
||||
* @return
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public TOut exchange(TIn message) throws InterruptedException {
|
||||
//todo impl BiDirectionQueueExchanger
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
log.debug("Listener {} for async exchange {}-{} close", this, outQueue, inQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
log.debug("Listener {} for async exchange {}-{} ready", this, outQueue, inQueue);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ public record FieldRequiredRule<R, V>(
|
|||
String fieldName,
|
||||
Function<R, V> getter,
|
||||
IErrorEnumId errorEmptyRequiredValue,
|
||||
Function<R, IErrorEnumId>[] additionalChecks
|
||||
Function<V, IErrorEnumId>[] additionalChecks
|
||||
) implements IValidationRule<ImdgValidationContext<R>> {
|
||||
|
||||
/**
|
||||
|
|
@ -33,7 +33,7 @@ public record FieldRequiredRule<R, V>(
|
|||
public static <R, V> FieldRequiredRule<R, V> instance(String fieldName,
|
||||
Function<R, V> getter,
|
||||
IErrorEnumId errorEmptyRequiredValue,
|
||||
Function<R, IErrorEnumId> ... additionalChecks) {
|
||||
Function<V, IErrorEnumId> ... additionalChecks) {
|
||||
if (errorEmptyRequiredValue == null) throw new IllegalArgumentException("Empty errorEmptyRequiredValue");
|
||||
return new FieldRequiredRule<>(fieldName, getter, errorEmptyRequiredValue, additionalChecks);
|
||||
}
|
||||
|
|
@ -43,8 +43,8 @@ public record FieldRequiredRule<R, V>(
|
|||
R validatedObject = context.getValidatedObject();
|
||||
V value = getter.apply(validatedObject);
|
||||
if (value == null) return of(errorEmptyRequiredValue, fieldName);
|
||||
for (Function<R, IErrorEnumId> additionalCheck : additionalChecks) {
|
||||
IErrorEnumId validationError = additionalCheck.apply(validatedObject);
|
||||
for (Function<V, IErrorEnumId> additionalCheck : additionalChecks) {
|
||||
IErrorEnumId validationError = additionalCheck.apply(value);
|
||||
if (validationError != null)
|
||||
return of(validationError, fieldName);
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.spcex.clearing</groupId>
|
||||
<artifactId>clearing-utils</artifactId>
|
||||
<artifactId>clearing-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ class ClearingMemberCategoryServiceTest {
|
|||
memberCategoryNewRequest.setCompanyId(TEST_COMPANY.getId());
|
||||
|
||||
ClearingMemberCategory predictableClearingMemberCategory = new ClearingMemberCategory();
|
||||
predictableClearingMemberCategory.setId(ID);
|
||||
predictableClearingMemberCategory.setCompanyId(COMPANY_ID);
|
||||
predictableClearingMemberCategory.setClearingMemberCategory(clearingMemberCategory);
|
||||
|
||||
|
|
@ -117,6 +116,7 @@ class ClearingMemberCategoryServiceTest {
|
|||
//ASSERT
|
||||
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
|
||||
ClearingMemberCategory resultNew = memberCategoryImdg.getSingleObjectBySQL(String.format("clearingMemberCategory = %s", clearingMemberCategory));
|
||||
predictableClearingMemberCategory.setId(resultNew.getId());
|
||||
MEMBER_CATEGORY_MATCHER.assertMatch(resultNew, predictableClearingMemberCategory);
|
||||
}
|
||||
|
||||
|
|
@ -132,28 +132,27 @@ class ClearingMemberCategoryServiceTest {
|
|||
//ARRANGE
|
||||
String clearingMemberCategory = CLEARING_CATEGORY_DICT_CODE;
|
||||
ClearingMemberCategory existsClearingMemberCategory = new ClearingMemberCategory();
|
||||
existsClearingMemberCategory.setId(ID);
|
||||
existsClearingMemberCategory.setClearingMemberCategory("0000");
|
||||
existsClearingMemberCategory.setCompanyId(COMPANY_ID);
|
||||
memberCategoryImdg.insert(existsClearingMemberCategory);
|
||||
Long id = memberCategoryImdg.insert(existsClearingMemberCategory);
|
||||
|
||||
ClearingMemberCategoryUpdateRequest memberCategoryUpdateRequest = new ClearingMemberCategoryUpdateRequest();
|
||||
memberCategoryUpdateRequest.setId(ID);
|
||||
memberCategoryUpdateRequest.setId(id);
|
||||
memberCategoryUpdateRequest.setClearingMemberCategory(clearingMemberCategory);
|
||||
|
||||
ClearingMemberCategory predictableClearingMemberCategory = new ClearingMemberCategory();
|
||||
predictableClearingMemberCategory.setCompanyId(COMPANY_ID);
|
||||
predictableClearingMemberCategory.setId(ID);
|
||||
predictableClearingMemberCategory.setId(id);
|
||||
predictableClearingMemberCategory.setClearingMemberCategory(clearingMemberCategory);
|
||||
|
||||
//ACT
|
||||
String jsonString = getJsonStringForUPDATE(memberCategoryUpdateRequest, ID);
|
||||
String jsonString = getJsonStringForUPDATE(memberCategoryUpdateRequest, id);
|
||||
addRecordToKafka((MockConsumer) clearingMemberCategoryService.getConsumer(), TOPIC_MEMBER_CATEGORY_UPDATE, PARTITION, 0, jsonString);
|
||||
|
||||
//ASSERT
|
||||
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
|
||||
waitingWhenAddedRecordAndCheckIt(id, mockProducer, producerRecord);
|
||||
|
||||
ClearingMemberCategory resultUpdating = memberCategoryImdg.getSingleObjectBySQL(String.format("clearingMemberCategory = %s", clearingMemberCategory));
|
||||
ClearingMemberCategory resultUpdating = memberCategoryImdg.getSingleObjectByID(id);
|
||||
MEMBER_CATEGORY_MATCHER.assertMatch(resultUpdating, predictableClearingMemberCategory);
|
||||
}
|
||||
|
||||
|
|
@ -168,19 +167,18 @@ class ClearingMemberCategoryServiceTest {
|
|||
//ARRANGE
|
||||
String clearingMemberCategory = "0000";
|
||||
ClearingMemberCategory existsClearingMemberCategory = new ClearingMemberCategory();
|
||||
existsClearingMemberCategory.setId(ID);
|
||||
existsClearingMemberCategory.setClearingMemberCategory(clearingMemberCategory);
|
||||
memberCategoryImdg.insert(existsClearingMemberCategory);
|
||||
Long id = memberCategoryImdg.insert(existsClearingMemberCategory);
|
||||
|
||||
CommonDeleteRequest memberCategoryDeleteRequest = new CommonDeleteRequest();
|
||||
memberCategoryDeleteRequest.setId(ID);
|
||||
memberCategoryDeleteRequest.setId(id);
|
||||
|
||||
//ACT
|
||||
String jsonString = getJsonStringForDELETE(memberCategoryDeleteRequest, ID);
|
||||
String jsonString = getJsonStringForDELETE(memberCategoryDeleteRequest, id);
|
||||
addRecordToKafka((MockConsumer) clearingMemberCategoryService.getConsumer(), TOPIC_MEMBER_CATEGORY_DELETE, PARTITION, 0, jsonString);
|
||||
|
||||
//ASSERT
|
||||
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
|
||||
waitingWhenAddedRecordAndCheckIt(id, mockProducer, producerRecord);
|
||||
|
||||
ClearingMemberCategory resultDeleting = memberCategoryImdg.getSingleObjectBySQL(String.format("clearingMemberCategory = %s", clearingMemberCategory));
|
||||
Assertions.assertNull(resultDeleting);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<module>backend-api</module>
|
||||
<module>imdg</module>
|
||||
<module>security-util</module>
|
||||
<module>clearing-utils</module>
|
||||
<module>clearing-validation</module>
|
||||
<module>db-scripts</module>
|
||||
<module>dbf-importer</module>
|
||||
<module>dbf-exporter</module>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.spcex.clearing</groupId>
|
||||
<artifactId>clearing-utils</artifactId>
|
||||
<artifactId>clearing-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.spcex.platform</groupId>
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import org.springframework.context.annotation.Configuration;
|
|||
import ru.clearing.classes.statics.data.instrument.issue.FixedIncomeCashFlow;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.FixedIncomeCashFlowNewRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.FixedIncomeCashFlowUpdateRequest;
|
||||
import ru.spcex.clearing.securities.errors.SecuritiesError;
|
||||
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
|
||||
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
|
||||
import ru.spcex.clearing.validation.common.rules.IsLongValueRule;
|
||||
import ru.spcex.platform.classes.base.SpcexObjectBase;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
|
|
@ -30,7 +32,7 @@ public class FixedIncomeCashFlowValidationConfig {
|
|||
ImdgValidationContext<FixedIncomeCashFlowNewRequest> context = new ImdgValidationContext<>();
|
||||
context.setValidatedObject(fixedIncomeCashFlowNewRequest);
|
||||
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
|
||||
addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory);
|
||||
addImdg.accept(IMDGDistributedNames.Map_FixedIncomeCashFlow);
|
||||
return new ValidatorImpl<>(context,
|
||||
IsLongValueRule.instance("securitySymbol",
|
||||
FixedIncomeCashFlowNewRequest::getSecuritySymbol,
|
||||
|
|
@ -39,18 +41,18 @@ public class FixedIncomeCashFlowValidationConfig {
|
|||
FieldRequiredRule.instance("securitySymbol",
|
||||
FixedIncomeCashFlowNewRequest::getSecuritySymbol,
|
||||
SecuritiesError.RequiredFieldIsEmpty,
|
||||
request -> {
|
||||
securitySymbol -> {
|
||||
Imdg<FixedIncomeCashFlow> fixedIncomeCashFlowImdg = context.obtainMap(
|
||||
IMDGDistributedNames.Map_FixedIncomeCashFlow, FixedIncomeCashFlow.class
|
||||
);
|
||||
Long securityId = Long.valueOf(request.getSecuritySymbol());
|
||||
Long securityId = Long.valueOf(securitySymbol);
|
||||
Collection<FixedIncomeCashFlow> fixedIncomeCashFlows = fixedIncomeCashFlowImdg.getCollectionObjectsByFieldValues(Map.of("securityId", securityId));
|
||||
if (!fixedIncomeCashFlows.isEmpty()) return SecuritiesError.CouponPeriodAlreadyExists;
|
||||
return null;
|
||||
}),
|
||||
FieldRequiredRule.instance("accruedCoupon",
|
||||
FixedIncomeCashFlowNewRequest::getAccruedCoupon,
|
||||
SecuritiesError.RequiredFieldIsEmpty),
|
||||
SecuritiesError.RequiredFieldIsEmpty),
|
||||
FieldRequiredRule.instance("nominalValue",
|
||||
FixedIncomeCashFlowNewRequest::getNominalValue,
|
||||
SecuritiesError.RequiredFieldIsEmpty),
|
||||
|
|
@ -61,4 +63,35 @@ public class FixedIncomeCashFlowValidationConfig {
|
|||
};
|
||||
}
|
||||
|
||||
@Bean("fixedIncomeCashFlowUpdateRequestValidator")
|
||||
public Function<FixedIncomeCashFlowUpdateRequest, IValidator> fixedIncomeCashFlowUpdateRequestValidator(
|
||||
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
|
||||
) {
|
||||
return fixedIncomeCashFlowUpdateRequest -> {
|
||||
ImdgValidationContext<FixedIncomeCashFlowUpdateRequest> context = new ImdgValidationContext<>();
|
||||
context.setValidatedObject(fixedIncomeCashFlowUpdateRequest);
|
||||
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
|
||||
addImdg.accept(IMDGDistributedNames.Map_FixedIncomeCashFlow);
|
||||
return new ValidatorImpl<>(context,
|
||||
IsLongValueRule.instance("securitySymbol",
|
||||
FixedIncomeCashFlowUpdateRequest::getSecuritySymbol,
|
||||
SecuritiesError.RequiredFieldIsEmpty,
|
||||
SecuritiesError.WrongFieldValue,
|
||||
false),
|
||||
IdPresentRule.instance("id",
|
||||
FixedIncomeCashFlowUpdateRequest::getId,
|
||||
IMDGDistributedNames.Map_FixedIncomeCashFlow,
|
||||
FixedIncomeCashFlow.class,
|
||||
SecuritiesError.RequiredFieldIsEmpty,
|
||||
SecuritiesError.CouponPeriodNotFound,
|
||||
fixedIncomeCashFlow -> {
|
||||
if (fixedIncomeCashFlowUpdateRequest.getSecuritySymbol() == null) return null;
|
||||
if (!fixedIncomeCashFlowUpdateRequest.getSecuritySymbol().equalsIgnoreCase(String.valueOf(fixedIncomeCashFlow.getSecurityId())))
|
||||
return SecuritiesError.WrongFieldValue;
|
||||
return null;
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ 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.securitites.FixedIncomeCashFlowNewRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.FixedIncomeCashFlowUpdateRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
|
||||
import ru.spcex.clearing.validation.common.ValidationHelper;
|
||||
|
|
@ -29,16 +30,19 @@ public class FixedIncomeCashFlowService extends QueueConsumer implements Initial
|
|||
private final ValidationHelper validationHelper;
|
||||
|
||||
private final Function<FixedIncomeCashFlowNewRequest, IValidator> fixedIncomeCashFlowNewRequestValidator;
|
||||
private final Function<FixedIncomeCashFlowUpdateRequest, IValidator> fixedIncomeCashFlowUpdateRequestValidator;
|
||||
|
||||
public FixedIncomeCashFlowService(Consumer<String, Object> kafkaQueue,
|
||||
Producer<String, Object> kafkaResponseQueue,
|
||||
ImdgProvider imdgProvider,
|
||||
ValidationHelper validationHelper,
|
||||
@Qualifier("fixedIncomeCashFlowNewRequestValidator") Function<FixedIncomeCashFlowNewRequest, IValidator> fixedIncomeCashFlowNewRequestValidator) {
|
||||
@Qualifier("fixedIncomeCashFlowNewRequestValidator") Function<FixedIncomeCashFlowNewRequest, IValidator> fixedIncomeCashFlowNewRequestValidator,
|
||||
@Qualifier("fixedIncomeCashFlowUpdateRequestValidator") Function<FixedIncomeCashFlowUpdateRequest, IValidator> fixedIncomeCashFlowUpdateRequestValidator) {
|
||||
super(kafkaQueue, kafkaResponseQueue);
|
||||
this.imdgProvider = imdgProvider;
|
||||
this.validationHelper = validationHelper;
|
||||
this.fixedIncomeCashFlowNewRequestValidator = fixedIncomeCashFlowNewRequestValidator;
|
||||
this.fixedIncomeCashFlowUpdateRequestValidator = fixedIncomeCashFlowUpdateRequestValidator;
|
||||
this.fixedIncomeCashFlowImdg = imdgProvider.getImdg(
|
||||
IMDGDistributedNames.Map_FixedIncomeCashFlow, FixedIncomeCashFlow.class
|
||||
);
|
||||
|
|
@ -50,6 +54,9 @@ public class FixedIncomeCashFlowService extends QueueConsumer implements Initial
|
|||
callback(FixedIncomeCashFlowNewRequest.class)
|
||||
.setConsumer(this::fixedIncomeCashFlowNew)
|
||||
.forDestination(Consts.DESTINATION_FIXED_INCOME_CASH_FLOW_NEW, callbacks::put);
|
||||
callback(FixedIncomeCashFlowUpdateRequest.class)
|
||||
.setConsumer(this::fixedIncomeCashFlowUpdate)
|
||||
.forDestination(Consts.DESTINATION_FIXED_INCOME_CASH_FLOW_UPDATE, callbacks::put);
|
||||
init();
|
||||
}
|
||||
|
||||
|
|
@ -72,5 +79,25 @@ public class FixedIncomeCashFlowService extends QueueConsumer implements Initial
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public RequestInfoUpdate fixedIncomeCashFlowUpdate(BaseRequest<FixedIncomeCashFlowUpdateRequest> userRequest) {
|
||||
log.debug("FixedIncomeCashFlowUpdateRequest received {}", userRequest.getId());
|
||||
|
||||
RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, fixedIncomeCashFlowUpdateRequestValidator);
|
||||
if (requestInfoUpdate != null) return requestInfoUpdate;
|
||||
|
||||
FixedIncomeCashFlowUpdateRequest req = userRequest.getRequestPayload();
|
||||
FixedIncomeCashFlow fixedIncomeCashFlow = fixedIncomeCashFlowImdg.getSingleObjectByID(req.getId());
|
||||
|
||||
if (req.getAccruedCoupon() != null) fixedIncomeCashFlow.setAccruedCoupon(req.getAccruedCoupon());
|
||||
if (req.getNominalValue() != null) fixedIncomeCashFlow.setNominalValue(req.getNominalValue());
|
||||
if (req.getNumber() != null) fixedIncomeCashFlow.setNumber(req.getNumber());
|
||||
if (req.getValueDate() != null) fixedIncomeCashFlow.setValueDate(req.getValueDate());
|
||||
|
||||
fixedIncomeCashFlowImdg.update(fixedIncomeCashFlow);
|
||||
log.debug("successfully processed, id {}", fixedIncomeCashFlow.getId());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@Configuration
|
||||
public class ImdgTestConfig {
|
||||
|
||||
public static final AtomicLong currentID = new AtomicLong(0L);
|
||||
private HazelcastInstance hazelcastInstance;
|
||||
|
||||
private static ThreadPoolTaskExecutor createThreadPoolTestTaskExecutor(int maxPoolSz, boolean waitForCompletion) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
package ru.spcex.clearing.securities.service;
|
||||
|
||||
import org.apache.kafka.clients.consumer.MockConsumer;
|
||||
import org.apache.kafka.clients.producer.MockProducer;
|
||||
import org.apache.kafka.clients.producer.ProducerRecord;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import ru.clearing.classes.statics.data.instrument.issue.FixedIncomeCashFlow;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.platform.messaging.domain.Consts;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.FixedIncomeCashFlowNewRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.FixedIncomeCashFlowUpdateRequest;
|
||||
import ru.spcex.clearing.securities.config.ErrorResolverConfig;
|
||||
import ru.spcex.clearing.securities.config.ImdgTestConfig;
|
||||
import ru.spcex.clearing.securities.config.KafkaTestConfig;
|
||||
import ru.spcex.clearing.securities.config.ValidationConfig;
|
||||
import ru.spcex.clearing.securities.config.validation.FixedIncomeCashFlowValidationConfig;
|
||||
import ru.spcex.clearing.securities.service.cud.FixedIncomeCashFlowService;
|
||||
import ru.spcex.clearing.securities.utils.MatcherFactory.Matcher;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static ru.spcex.clearing.securities.config.ImdgTestConfig.currentID;
|
||||
import static ru.spcex.clearing.securities.utils.MatcherFactory.usingIgnoringFieldsComparator;
|
||||
import static ru.spcex.clearing.securities.utils.TestUtils.*;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = {
|
||||
ErrorResolverConfig.class,
|
||||
ValidationConfig.class,
|
||||
FixedIncomeCashFlowService.class,
|
||||
FixedIncomeCashFlowValidationConfig.class,
|
||||
KafkaTestConfig.class,
|
||||
ImdgTestConfig.class})
|
||||
class FixedIncomeCashFlowServiceTest {
|
||||
public static final Matcher<FixedIncomeCashFlow> FIXED_INCOME_CASH_FLOW_MATCHER = usingIgnoringFieldsComparator();
|
||||
|
||||
private static final String TOPIC_FIXED_INCOME_CASH_FLOW_NEW = Consts.DESTINATION_FIXED_INCOME_CASH_FLOW_NEW;
|
||||
private static final String TOPIC_FIXED_INCOME_CASH_FLOW_UPDATE = Consts.DESTINATION_FIXED_INCOME_CASH_FLOW_UPDATE;
|
||||
private static final Long ID = currentID.incrementAndGet();
|
||||
private static final int PARTITION = 0;
|
||||
|
||||
@Autowired
|
||||
FixedIncomeCashFlowService fixedIncomeCashFlowService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("hazelcastServiceTest")
|
||||
private ImdgProvider hazelcastServiceTest;
|
||||
private Imdg<FixedIncomeCashFlow> fixedIncomeCashFlowImdg;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<ProducerRecord> producerRecord;
|
||||
@SpyBean
|
||||
private MockProducer<String, Object> mockProducer;
|
||||
|
||||
private final String SECURITY_SYMBOL_STR = "777";
|
||||
private final Long SECURITY_SYMBOL_LONG = 777L;
|
||||
|
||||
private final LocalDate TEST_DATE = LocalDate.now();
|
||||
|
||||
private final BigDecimal TEST_BIG_DECIMAL = BigDecimal.TEN;
|
||||
|
||||
private final Long TEST_LONG = Long.MAX_VALUE;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
hazelcastServiceTest.waitAvailable();
|
||||
fixedIncomeCashFlowImdg = hazelcastServiceTest.getImdg(
|
||||
IMDGDistributedNames.Map_FixedIncomeCashFlow,
|
||||
FixedIncomeCashFlow.class
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void fixedIncomeCashFlowNewTest() throws InterruptedException {
|
||||
//ARRANGE
|
||||
FixedIncomeCashFlowNewRequest newRequest = new FixedIncomeCashFlowNewRequest();
|
||||
newRequest.setSecuritySymbol(SECURITY_SYMBOL_STR);
|
||||
newRequest.setNominalValue(TEST_BIG_DECIMAL);
|
||||
newRequest.setAccruedCoupon(TEST_BIG_DECIMAL);
|
||||
newRequest.setNumber(TEST_LONG);
|
||||
newRequest.setValueDate(TEST_DATE);
|
||||
|
||||
FixedIncomeCashFlow predictableFixedIncomeCashFlow = new FixedIncomeCashFlow();
|
||||
predictableFixedIncomeCashFlow.setSecurityId(SECURITY_SYMBOL_LONG);
|
||||
predictableFixedIncomeCashFlow.setNominalValue(TEST_BIG_DECIMAL);
|
||||
predictableFixedIncomeCashFlow.setAccruedCoupon(TEST_BIG_DECIMAL);
|
||||
predictableFixedIncomeCashFlow.setNumber(TEST_LONG);
|
||||
predictableFixedIncomeCashFlow.setValueDate(TEST_DATE);
|
||||
|
||||
//ACT
|
||||
String jsonString = getJsonStringForNew(newRequest, ID);
|
||||
|
||||
addRecordToKafka((MockConsumer) fixedIncomeCashFlowService.getConsumer(), TOPIC_FIXED_INCOME_CASH_FLOW_NEW, PARTITION, 0, jsonString);
|
||||
|
||||
//ASSERT
|
||||
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
|
||||
FixedIncomeCashFlow resultNew = fixedIncomeCashFlowImdg.getSingleObjectBySQL(String.format("securityId = %s", SECURITY_SYMBOL_STR));
|
||||
predictableFixedIncomeCashFlow.setId(resultNew.getId());
|
||||
FIXED_INCOME_CASH_FLOW_MATCHER.assertMatch(resultNew, predictableFixedIncomeCashFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void fixedIncomeCashFlowUpdateTest() throws InterruptedException {
|
||||
//ARRANGE
|
||||
FixedIncomeCashFlow existFixedIncomeCashFlow = new FixedIncomeCashFlow();
|
||||
existFixedIncomeCashFlow.setSecurityId(SECURITY_SYMBOL_LONG);
|
||||
existFixedIncomeCashFlow.setNominalValue(BigDecimal.ZERO);
|
||||
existFixedIncomeCashFlow.setAccruedCoupon(BigDecimal.ZERO);
|
||||
existFixedIncomeCashFlow.setNumber(0L);
|
||||
existFixedIncomeCashFlow.setValueDate(LocalDate.now().plusDays(7));
|
||||
Long id = fixedIncomeCashFlowImdg.insert(existFixedIncomeCashFlow);
|
||||
|
||||
FixedIncomeCashFlowUpdateRequest updateRequest = new FixedIncomeCashFlowUpdateRequest();
|
||||
updateRequest.setId(id);
|
||||
updateRequest.setSecuritySymbol(SECURITY_SYMBOL_STR);
|
||||
updateRequest.setNominalValue(TEST_BIG_DECIMAL);
|
||||
updateRequest.setAccruedCoupon(TEST_BIG_DECIMAL);
|
||||
updateRequest.setNumber(TEST_LONG);
|
||||
updateRequest.setValueDate(TEST_DATE);
|
||||
|
||||
FixedIncomeCashFlow predictableFixedIncomeCashFlow = new FixedIncomeCashFlow();
|
||||
predictableFixedIncomeCashFlow.setSecurityId(SECURITY_SYMBOL_LONG);
|
||||
predictableFixedIncomeCashFlow.setNominalValue(TEST_BIG_DECIMAL);
|
||||
predictableFixedIncomeCashFlow.setAccruedCoupon(TEST_BIG_DECIMAL);
|
||||
predictableFixedIncomeCashFlow.setNumber(TEST_LONG);
|
||||
predictableFixedIncomeCashFlow.setValueDate(TEST_DATE);
|
||||
|
||||
//ACT
|
||||
String jsonString = getJsonStringForUPDATE(updateRequest, id);
|
||||
|
||||
addRecordToKafka((MockConsumer) fixedIncomeCashFlowService.getConsumer(), TOPIC_FIXED_INCOME_CASH_FLOW_UPDATE, PARTITION, 0, jsonString);
|
||||
|
||||
//ASSERT
|
||||
waitingWhenAddedRecordAndCheckIt(id, mockProducer, producerRecord);
|
||||
FixedIncomeCashFlow resultUpdate = fixedIncomeCashFlowImdg.getSingleObjectBySQL(String.format("securityId = %s", SECURITY_SYMBOL_STR));
|
||||
predictableFixedIncomeCashFlow.setId(id);
|
||||
FIXED_INCOME_CASH_FLOW_MATCHER.assertMatch(resultUpdate, predictableFixedIncomeCashFlow);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,10 @@ package ru.spcex.clearing.platform.messaging.domain.cud.securitites;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
|
||||
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
|
||||
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
|
||||
import ru.spcex.platform.classes.base.interfaces.WithSecuritySymbol;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
|
@ -24,6 +27,8 @@ public class FixedIncomeCashFlowNewRequest implements WithSecuritySymbol {
|
|||
public Long number;
|
||||
|
||||
@JsonProperty
|
||||
@JsonSerialize(using = LocalDateSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateDeserializer.class)
|
||||
public LocalDate valueDate;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ package ru.spcex.clearing.platform.messaging.domain.cud.securitites;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
|
||||
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
|
||||
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
|
||||
import ru.spcex.platform.classes.base.interfaces.WithSecuritySymbol;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
|
@ -27,6 +30,8 @@ public class FixedIncomeCashFlowUpdateRequest implements WithSecuritySymbol {
|
|||
public Long number;
|
||||
|
||||
@JsonProperty
|
||||
@JsonSerialize(using = LocalDateSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateDeserializer.class)
|
||||
public LocalDate valueDate;
|
||||
|
||||
|
||||
|
|
|
|||
2
pom.xml
2
pom.xml
|
|
@ -96,7 +96,7 @@
|
|||
|
||||
<dependency>
|
||||
<groupId>ru.spcex.clearing</groupId>
|
||||
<artifactId>clearing-utils</artifactId>
|
||||
<artifactId>clearing-validation</artifactId>
|
||||
<version>${global.project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue