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 cded567f6..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; @@ -50,7 +52,7 @@ public class FixedIncomeCashFlowValidationConfig { }), FieldRequiredRule.instance("accruedCoupon", FixedIncomeCashFlowNewRequest::getAccruedCoupon, - SecuritiesError.RequiredFieldIsEmpty), + SecuritiesError.RequiredFieldIsEmpty), FieldRequiredRule.instance("nominalValue", FixedIncomeCashFlowNewRequest::getNominalValue, SecuritiesError.RequiredFieldIsEmpty), @@ -61,43 +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", -// FixedIncomeCashFlowNewRequest::getSecuritySymbol, -// SecuritiesError.RequiredFieldIsEmpty, -// SecuritiesError.WrongFieldValue), -// FieldRequiredRule.instance("securitySymbol", -// FixedIncomeCashFlowNewRequest::getSecuritySymbol, -// SecuritiesError.RequiredFieldIsEmpty, -// request -> { -// Imdg fixedIncomeCashFlowImdg = context.obtainMap( -// IMDGDistributedNames.Map_FixedIncomeCashFlow, FixedIncomeCashFlow.class -// ); -// Long securityId = Long.valueOf(request.getSecuritySymbol()); -// Collection fixedIncomeCashFlows = fixedIncomeCashFlowImdg.getCollectionObjectsByFieldValues(Map.of("securityId", securityId)); -// if (!fixedIncomeCashFlows.isEmpty()) return SecuritiesError.CouponPeriodAlreadyExists; -// return null; -// }), -// FieldRequiredRule.instance("accruedCoupon", -// FixedIncomeCashFlowNewRequest::getAccruedCoupon, -// SecuritiesError.RequiredFieldIsEmpty), -// FieldRequiredRule.instance("nominalValue", -// FixedIncomeCashFlowNewRequest::getNominalValue, -// SecuritiesError.RequiredFieldIsEmpty), -// FieldRequiredRule.instance("number", -// FixedIncomeCashFlowNewRequest::getNumber, -// SecuritiesError.RequiredFieldIsEmpty) -// ); -// }; -// } + @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/service/FixedIncomeCashFlowServiceTest.java b/clearing-parent/securities-service/src/test/java/ru/spcex/clearing/securities/service/FixedIncomeCashFlowServiceTest.java index 27fc8ce30..18214b4a2 100644 --- 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 @@ -16,6 +16,7 @@ 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; @@ -110,4 +111,43 @@ class FixedIncomeCashFlowServiceTest { 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/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;