diff --git a/clearing-parent/clearing-utils/pom.xml b/clearing-parent/clearing-validation/pom.xml similarity index 95% rename from clearing-parent/clearing-utils/pom.xml rename to clearing-parent/clearing-validation/pom.xml index 580382cc7..60ad3b00b 100644 --- a/clearing-parent/clearing-utils/pom.xml +++ b/clearing-parent/clearing-validation/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - clearing-utils - clearing-utils + clearing-validation + clearing-validation Clearing-module, dependency version of platform-utils jar SPCEX-1.0.0.0 diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/util/package-info.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/package-info.java similarity index 97% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/util/package-info.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/package-info.java index 636322526..4077b07c4 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/util/package-info.java +++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/package-info.java @@ -1,4 +1,4 @@ -/** - * Утилиты с зависимостями от множества модулей clearing-* - */ +/** + * Утилиты с зависимостями от множества модулей clearing-* + */ package ru.spcex.clearing.util; \ No newline at end of file diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java similarity index 97% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java index 0f08fe624..f8aef7bf6 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java +++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/exchangers/BiDirectionQueueExchanger.java @@ -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> 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 listenClass; - protected long timeout; - - /** - * Синхронно-ассинхронный обмен сообщениями - * - * @param kafkaQueue - * @param kafkaProducer - * @param outQueue отправляет в очередь - * @param inQueue слушает очередь, ожидает ответов - * @param listenClass типы объектов из inQueue - * @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено - */ - public BiDirectionQueueExchanger(Consumer kafkaQueue, Producer kafkaProducer, - String outQueue, - String inQueue, Class 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> 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 listenClass; + protected long timeout; + + /** + * Синхронно-ассинхронный обмен сообщениями + * + * @param kafkaQueue + * @param kafkaProducer + * @param outQueue отправляет в очередь + * @param inQueue слушает очередь, ожидает ответов + * @param listenClass типы объектов из inQueue + * @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено + */ + public BiDirectionQueueExchanger(Consumer kafkaQueue, Producer kafkaProducer, + String outQueue, + String inQueue, Class 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); + } +} diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/ValidationHelper.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/ValidationHelper.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/ValidationHelper.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/ValidationHelper.java diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DateNotBeforeRule.java diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EndDtAfterStartDtRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EndDtAfterStartDtRule.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EndDtAfterStartDtRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EndDtAfterStartDtRule.java diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java similarity index 93% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java index 2cef88c89..b9f5bb89c 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java +++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java @@ -19,7 +19,7 @@ public record FieldRequiredRule( String fieldName, Function getter, IErrorEnumId errorEmptyRequiredValue, - Function[] additionalChecks + Function[] additionalChecks ) implements IValidationRule> { /** @@ -33,7 +33,7 @@ public record FieldRequiredRule( public static FieldRequiredRule instance(String fieldName, Function getter, IErrorEnumId errorEmptyRequiredValue, - Function ... additionalChecks) { + Function ... additionalChecks) { if (errorEmptyRequiredValue == null) throw new IllegalArgumentException("Empty errorEmptyRequiredValue"); return new FieldRequiredRule<>(fieldName, getter, errorEmptyRequiredValue, additionalChecks); } @@ -43,8 +43,8 @@ public record FieldRequiredRule( R validatedObject = context.getValidatedObject(); V value = getter.apply(validatedObject); if (value == null) return of(errorEmptyRequiredValue, fieldName); - for (Function additionalCheck : additionalChecks) { - IErrorEnumId validationError = additionalCheck.apply(validatedObject); + for (Function additionalCheck : additionalChecks) { + IErrorEnumId validationError = additionalCheck.apply(value); if (validationError != null) return of(validationError, fieldName); } diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IsLongValueRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IsLongValueRule.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IsLongValueRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/IsLongValueRule.java diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java similarity index 100% rename from clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java rename to clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/validation/common/rules/TimeNotBeforeRule.java diff --git a/clearing-parent/company-service/pom.xml b/clearing-parent/company-service/pom.xml index 9913e8df4..ee17025df 100644 --- a/clearing-parent/company-service/pom.xml +++ b/clearing-parent/company-service/pom.xml @@ -38,7 +38,7 @@ ru.spcex.clearing - clearing-utils + clearing-validation org.springframework.boot diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClearingMemberCategoryServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClearingMemberCategoryServiceTest.java index 4d78b455d..b864b48a7 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClearingMemberCategoryServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ClearingMemberCategoryServiceTest.java @@ -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); diff --git a/clearing-parent/pom.xml b/clearing-parent/pom.xml index e71a79d1a..7f495921e 100644 --- a/clearing-parent/pom.xml +++ b/clearing-parent/pom.xml @@ -21,7 +21,7 @@ backend-api imdg security-util - clearing-utils + clearing-validation db-scripts dbf-importer dbf-exporter diff --git a/clearing-parent/securities-service/pom.xml b/clearing-parent/securities-service/pom.xml index 63e85f10a..ae27be76c 100644 --- a/clearing-parent/securities-service/pom.xml +++ b/clearing-parent/securities-service/pom.xml @@ -26,7 +26,7 @@ ru.spcex.clearing - clearing-utils + clearing-validation ru.spcex.platform diff --git a/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/config/validation/FixedIncomeCashFlowValidationConfig.java b/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/config/validation/FixedIncomeCashFlowValidationConfig.java index 179b29106..815d779bf 100644 --- a/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/config/validation/FixedIncomeCashFlowValidationConfig.java +++ b/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/config/validation/FixedIncomeCashFlowValidationConfig.java @@ -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 context = new ImdgValidationContext<>(); context.setValidatedObject(fixedIncomeCashFlowNewRequest); Consumer 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 fixedIncomeCashFlowImdg = context.obtainMap( IMDGDistributedNames.Map_FixedIncomeCashFlow, FixedIncomeCashFlow.class ); - Long securityId = Long.valueOf(request.getSecuritySymbol()); + Long securityId = Long.valueOf(securitySymbol); Collection 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 fixedIncomeCashFlowUpdateRequestValidator( + Map> imdgForValidation + ) { + return fixedIncomeCashFlowUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(fixedIncomeCashFlowUpdateRequest); + Consumer 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; + }) + ); + }; + } + } diff --git a/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/cud/FixedIncomeCashFlowService.java b/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/cud/FixedIncomeCashFlowService.java index bf227b425..ab17cf7ed 100644 --- a/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/cud/FixedIncomeCashFlowService.java +++ b/clearing-parent/securities-service/src/main/java/ru/spcex/clearing/securities/service/cud/FixedIncomeCashFlowService.java @@ -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 fixedIncomeCashFlowNewRequestValidator; + private final Function fixedIncomeCashFlowUpdateRequestValidator; public FixedIncomeCashFlowService(Consumer kafkaQueue, Producer kafkaResponseQueue, ImdgProvider imdgProvider, ValidationHelper validationHelper, - @Qualifier("fixedIncomeCashFlowNewRequestValidator") Function fixedIncomeCashFlowNewRequestValidator) { + @Qualifier("fixedIncomeCashFlowNewRequestValidator") Function fixedIncomeCashFlowNewRequestValidator, + @Qualifier("fixedIncomeCashFlowUpdateRequestValidator") Function 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 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; + } } diff --git a/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/config/ImdgTestConfig.java b/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/config/ImdgTestConfig.java index 95f01963c..839542afd 100644 --- a/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/config/ImdgTestConfig.java +++ b/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/config/ImdgTestConfig.java @@ -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) { diff --git a/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/service/FixedIncomeCashFlowServiceTest.java b/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/service/FixedIncomeCashFlowServiceTest.java new file mode 100644 index 000000000..18214b4a2 --- /dev/null +++ b/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/service/FixedIncomeCashFlowServiceTest.java @@ -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 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 fixedIncomeCashFlowImdg; + + @Captor + private ArgumentCaptor producerRecord; + @SpyBean + private MockProducer 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); + } + + +} \ No newline at end of file diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowNewRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowNewRequest.java index eaca2e32b..dc4ae3c0e 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowNewRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowNewRequest.java @@ -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; diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowUpdateRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowUpdateRequest.java index e5d1c2d50..50d6f0c8c 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowUpdateRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/securitites/FixedIncomeCashFlowUpdateRequest.java @@ -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; diff --git a/pom.xml b/pom.xml index 6d9c0427c..b5e15a784 100644 --- a/pom.xml +++ b/pom.xml @@ -96,7 +96,7 @@ ru.spcex.clearing - clearing-utils + clearing-validation ${global.project.version}