From adf57e7b00b3451e1266b0090aafd7933a391551 Mon Sep 17 00:00:00 2001 From: akulikov Date: Tue, 4 Apr 2023 15:56:24 +0300 Subject: [PATCH 1/4] updateProfileDocument --- .../common/rules/DictionaryPresentRule.java | 2 +- ...learingMemberCategoryValidationConfig.java | 4 +- .../ProfileDocumentValidationConfig.java | 51 ++++++++++++ .../service/ProfileDocumentService.java | 76 ++++++++++++++++- .../service/ProfileDocumentServiceTest.java | 83 ++++++++++++++++++- 5 files changed, 207 insertions(+), 9 deletions(-) diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java index 67b6586c9..8fed6e5ed 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java +++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java @@ -48,8 +48,8 @@ public record DictionaryPresentRule(String fiel getter, dictionaryName, dictionaryClass, - errorWrongDictionaryValue, errorEmptyRequiredValue, + errorWrongDictionaryValue, required); } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClearingMemberCategoryValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClearingMemberCategoryValidationConfig.java index c41e4283d..d1c44aa66 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClearingMemberCategoryValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ClearingMemberCategoryValidationConfig.java @@ -84,6 +84,7 @@ public class ClearingMemberCategoryValidationConfig { EnumPresentRule.instance("clearingMemberCategory", ClearingMemberCategoryUpdateRequest::getClearingMemberCategory, ClearingCategory.values(), + false, CompanyErrors.WrongFieldValue, CompanyErrors.RequiredFieldEmpty), DictionaryPresentRule.instance("clearingMemberCategory", @@ -91,7 +92,8 @@ public class ClearingMemberCategoryValidationConfig { IMDGDistributedNames.Map_ClearingCategoryDictionary, ClearingCategoryDictionary.class, CompanyErrors.RequiredFieldEmpty, - CompanyErrors.WrongFieldValue)); + CompanyErrors.WrongFieldValue, + false)); }; } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java index 00024133f..7dbbc420a 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ProfileDocumentValidationConfig.java @@ -3,10 +3,12 @@ package ru.spcex.clearing.company.config.validation; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.profile.ProfileDocument; import ru.clearing.platform.dictionary.DocumentTypeDictionary; import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentUpdateRequest; import ru.spcex.clearing.validation.common.rules.*; import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.enumeration.DocumentTypes; @@ -79,4 +81,53 @@ public class ProfileDocumentValidationConfig { ); }; } + + @Bean("profileDocumentUpdateRequestValidation") + public Function profileDocumentUpdateRequestValidator( + Map> imdgForValidation + ) { + return profileDocumentUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(profileDocumentUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_DocumentTypeDictionary); + addImdg.accept(IMDGDistributedNames.Map_ProfileDocument); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + ProfileDocumentUpdateRequest::getId, + IMDGDistributedNames.Map_ProfileDocument, + ProfileDocument.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.RecordNotFound), + IdPresentRule.instance("companyId", + ProfileDocumentUpdateRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.CompanyNotFound, + false, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled), + EnumPresentRule.instance("documentType", + ProfileDocumentUpdateRequest::getDocumentType, + DocumentTypes.values(), + false, + CompanyErrors.WrongFieldValue, + CompanyErrors.RequiredFieldEmpty), + DictionaryPresentRule.instance("documentType", + ProfileDocumentUpdateRequest::getDocumentType, + IMDGDistributedNames.Map_DocumentTypeDictionary, + DocumentTypeDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue, + false), + EndDtAfterStartDtRule.instance("validFromDate", "validToDate", + ProfileDocumentUpdateRequest::getValidFromDate, + ProfileDocumentUpdateRequest::getValidToDate, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue, + false) + ); + }; + } } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java index a5deb9f63..8204af83a 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/ProfileDocumentService.java @@ -15,11 +15,11 @@ import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; import ru.spcex.clearing.validation.common.ValidationHelper; -import ru.spcex.platform.enumeration.DocumentTypes; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.utils.validation.IValidator; @@ -35,6 +35,7 @@ public class ProfileDocumentService extends QueueConsumer implements Initializin private KafkaSender kafkaReqProducer; private final Function profileDocumentNewRequestValidator; + private final Function profileDocumentUpdateRequestValidator; private final ValidationHelper validationHelper; @Autowired @@ -43,11 +44,13 @@ public class ProfileDocumentService extends QueueConsumer implements Initializin KafkaSender kafkaReqProducer, ImdgProvider imdgProvider, @Qualifier("profileDocumentNewRequestValidation") Function profileDocumentNewRequestValidator, + @Qualifier("profileDocumentUpdateRequestValidation") Function profileDocumentUpdateRequestValidator, ValidationHelper validationHelper) { super(kafkaQueue, kafkaProducer); this.imdgProvider = imdgProvider; this.kafkaReqProducer = kafkaReqProducer; this.profileDocumentNewRequestValidator = profileDocumentNewRequestValidator; + this.profileDocumentUpdateRequestValidator = profileDocumentUpdateRequestValidator; this.validationHelper = validationHelper; } @@ -59,6 +62,9 @@ public class ProfileDocumentService extends QueueConsumer implements Initializin callback(ProfileDocumentNewRequest.class) .setConsumer(this::profileDocumentNew) .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_NEW, callbacks::put); + callback(ProfileDocumentUpdateRequest.class) + .setConsumer(this::profileDocumentUpdate) + .forDestination(Consts.DESTINATION_PROFILE_DOCUMENT_UPDATE, callbacks::put); init(); } @@ -88,9 +94,71 @@ public class ProfileDocumentService extends QueueConsumer implements Initializin profileDocument.setLink(profileDocumentNewRequest.getLink()); profileDocumentMap.insert(profileDocument); - if (profileDocument.getDocumentType().equalsIgnoreCase(DocumentTypes.xcnt.getKey())) { -// kafkaReqProducer.sendRequestToQueue(Consts.EXPORT_PROCESS, exportRequest); - } +// if (profileDocument.getDocumentType().equalsIgnoreCase(DocumentTypes.xcnt.getKey())) { + // todo create request for update and check request for new account (something wrong) +// kafkaReqProducer.sendRequestToQueue(Consts.ACCOUNT_UPDATE, ) +// } + + return null; + } + + @NonNull + private RequestInfoUpdate profileDocumentUpdate(BaseRequest profileDocumentUpdateRequestBaseRequest) { + log.trace("Start processing ProfileDocumentUpdateRequest!"); + + RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError( + profileDocumentUpdateRequestBaseRequest, + profileDocumentUpdateRequestValidator + ); + if (requestInfoUpdate != null) return requestInfoUpdate; + + ProfileDocumentUpdateRequest profileDocumentUpdateRequest = profileDocumentUpdateRequestBaseRequest.getRequestPayload(); + ProfileDocument profileDocument = profileDocumentMap.getSingleObjectByID(profileDocumentUpdateRequest.getId()); + + if (profileDocumentUpdateRequest.getCompanyId() != null) + profileDocument.setCompanyId(profileDocumentUpdateRequest.getCompanyId()); + + if (profileDocumentUpdateRequest.getDocumentType() != null) + profileDocument.setDocumentType(profileDocumentUpdateRequest.getDocumentType()); + + if (profileDocumentUpdateRequest.getIssueDate() != null) + profileDocument.setIssueDate(profileDocumentUpdateRequest.getIssueDate()); + + if (profileDocumentUpdateRequest.getIssuePlace() != null) + profileDocument.setIssuePlace(profileDocumentUpdateRequest.getIssuePlace()); + + if (profileDocumentUpdateRequest.getIssuer() != null) + profileDocument.setIssuer(profileDocumentUpdateRequest.getIssuer()); + + if (profileDocumentUpdateRequest.getIssuerCode() != null) + profileDocument.setIssuerCode(profileDocumentUpdateRequest.getIssuerCode()); + + if (profileDocumentUpdateRequest.getName() != null) + profileDocument.setName(profileDocumentUpdateRequest.getName()); + + if (profileDocumentUpdateRequest.getNumber() != null) + profileDocument.setNumber(profileDocumentUpdateRequest.getNumber()); + + if (profileDocumentUpdateRequest.getPlace() != null) + profileDocument.setPlace(profileDocumentUpdateRequest.getPlace()); + + if (profileDocumentUpdateRequest.getValidFromDate() != null) + profileDocument.setValidFromDate(profileDocumentUpdateRequest.getValidFromDate()); + + if (profileDocumentUpdateRequest.getValidToDate() != null) + profileDocument.setValidToDate(profileDocumentUpdateRequest.getValidToDate()); + + if (profileDocumentUpdateRequest.getLink() != null) + profileDocument.setLink(profileDocumentUpdateRequest.getLink()); + + profileDocumentMap.insert(profileDocument); + + log.trace("successfully processed, id {}", profileDocument.getId()); + +// if (profileDocument.getDocumentType().equalsIgnoreCase(DocumentTypes.xcnt.getKey())) { + // todo if update profileDocument with documentType == XCNT... need send? +// kafkaReqProducer.sendRequestToQueue(Consts.ACCOUNT_UPDATE, ) +// } return null; } diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ProfileDocumentServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ProfileDocumentServiceTest.java index 89d058cef..c2ed53986 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ProfileDocumentServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/ProfileDocumentServiceTest.java @@ -25,6 +25,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.company.ProfileDocumentNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentUpdateRequest; import ru.spcex.platform.enumeration.DocumentTypes; import ru.spcex.platform.enumeration.WorkflowStatus; import ru.spcex.platform.imdg.api.Imdg; @@ -51,6 +52,8 @@ class ProfileDocumentServiceTest { public static final MatcherFactory.Matcher PROFILE_DOCUMENT_MATCHER = usingIgnoringFieldsComparator(); private static final int PARTITION = 0; private static final String TOPIC_DESTINATION_PROFILE_DOCUMENT_NEW = Consts.DESTINATION_PROFILE_DOCUMENT_NEW; + private static final String TOPIC_DESTINATION_PROFILE_DOCUMENT_UPDATE = Consts.DESTINATION_PROFILE_DOCUMENT_UPDATE; + private static final Long ID = currentID.getAndIncrement(); @Autowired ProfileDocumentService profileDocumentService; @@ -71,6 +74,11 @@ class ProfileDocumentServiceTest { private DocumentTypes TEST_DOCUMENT_TYPE = DocumentTypes.cio; private String TEST_DOCUMENT_TYPE_ID = TEST_DOCUMENT_TYPE.getKey(); + private DocumentTypes NEW_TEST_DOCUMENT_TYPE = DocumentTypes.edoc; + private String NEW_TEST_DOCUMENT_TYPE_ID = NEW_TEST_DOCUMENT_TYPE.getKey(); + + private final long PROFILE_DOCUMENT_ID = ID; + @PostConstruct private void init() { hazelcastServiceTest.waitAvailable(); @@ -82,15 +90,22 @@ class ProfileDocumentServiceTest { TEST_COMPANY.setWorkflowStatus(WorkflowStatus.Active.getKey()); companyMap.insert(TEST_COMPANY); - DocumentTypeDictionary documentTypeDictionary = new DocumentTypeDictionary(); - documentTypeDictionary.setCode(TEST_DOCUMENT_TYPE.getKey()); - documentTypeDictionary.setName("test_name"); Imdg documentTypeDictionaryImdg = hazelcastServiceTest.getImdg( IMDGDistributedNames.Map_DocumentTypeDictionary, DocumentTypeDictionary.class ); + + DocumentTypeDictionary documentTypeDictionary = new DocumentTypeDictionary(); + documentTypeDictionary.setCode(TEST_DOCUMENT_TYPE.getKey()); + documentTypeDictionary.setName("test_name"); documentTypeDictionaryImdg.insert(documentTypeDictionary); + DocumentTypeDictionary documentTypeDictionary1 = new DocumentTypeDictionary(); + documentTypeDictionary1.setCode(NEW_TEST_DOCUMENT_TYPE.getKey()); + documentTypeDictionary1.setName("new_test_name"); + documentTypeDictionaryImdg.insert(documentTypeDictionary1); + + } /** @@ -116,6 +131,7 @@ class ProfileDocumentServiceTest { profileDocumentNewRequest.setLink("link"); ProfileDocument predictableProfileDocument = new ProfileDocument(); + predictableProfileDocument.setId(PROFILE_DOCUMENT_ID); predictableProfileDocument.setCompanyId(profileDocumentNewRequest.getCompanyId()); predictableProfileDocument.setDocumentType(profileDocumentNewRequest.getDocumentType()); predictableProfileDocument.setIssueDate(profileDocumentNewRequest.getIssueDate()); @@ -140,4 +156,65 @@ class ProfileDocumentServiceTest { predictableProfileDocument.setId(resultNew.getId()); PROFILE_DOCUMENT_MATCHER.assertMatch(resultNew, predictableProfileDocument); } + + @Test + void updateProfileDocument() { + //ARRANGE + ProfileDocument existsProfileDocument = new ProfileDocument(); + existsProfileDocument.setId(ID); + existsProfileDocument.setCompanyId(COMPANY_ID); + existsProfileDocument.setDocumentType(TEST_DOCUMENT_TYPE_ID); + existsProfileDocument.setIssueDate(LocalDate.now()); + existsProfileDocument.setIssuePlace("place"); + existsProfileDocument.setIssuer("issuer"); + existsProfileDocument.setIssuerCode("issuerCode"); + existsProfileDocument.setName("name"); + existsProfileDocument.setNumber("number"); + existsProfileDocument.setPlace("place"); + existsProfileDocument.setValidFromDate(LocalDate.now()); + existsProfileDocument.setValidToDate(LocalDate.now().plus(1, ChronoUnit.DAYS)); + existsProfileDocument.setLink("link"); + profileDocumentMap.insert(existsProfileDocument); + + ProfileDocument predictableProfileDocument = new ProfileDocument(); + predictableProfileDocument.setId(PROFILE_DOCUMENT_ID); + predictableProfileDocument.setCompanyId(COMPANY_ID); + predictableProfileDocument.setDocumentType(NEW_TEST_DOCUMENT_TYPE_ID); + predictableProfileDocument.setIssueDate(LocalDate.now()); + predictableProfileDocument.setIssuePlace("new_place"); + predictableProfileDocument.setIssuer("new_issuer"); + predictableProfileDocument.setIssuerCode("new_issuerCode"); + predictableProfileDocument.setName("new_name"); + predictableProfileDocument.setNumber("new_number"); + predictableProfileDocument.setPlace("new_place"); + predictableProfileDocument.setValidFromDate(LocalDate.now()); + predictableProfileDocument.setValidToDate(LocalDate.now().plus(1, ChronoUnit.DAYS)); + predictableProfileDocument.setLink("new_link"); + + ProfileDocumentUpdateRequest profileDocumentUpdateRequest = new ProfileDocumentUpdateRequest(); + profileDocumentUpdateRequest.setId(PROFILE_DOCUMENT_ID); + profileDocumentUpdateRequest.setCompanyId(COMPANY_ID); + profileDocumentUpdateRequest.setDocumentType(NEW_TEST_DOCUMENT_TYPE_ID); + profileDocumentUpdateRequest.setIssueDate(LocalDate.now()); + profileDocumentUpdateRequest.setIssuePlace("new_place"); + profileDocumentUpdateRequest.setIssuer("new_issuer"); + profileDocumentUpdateRequest.setIssuerCode("new_issuerCode"); + profileDocumentUpdateRequest.setName("new_name"); + profileDocumentUpdateRequest.setNumber("new_number"); + profileDocumentUpdateRequest.setPlace("new_place"); + profileDocumentUpdateRequest.setValidFromDate(LocalDate.now()); + profileDocumentUpdateRequest.setValidToDate(LocalDate.now().plus(1, ChronoUnit.DAYS)); + profileDocumentUpdateRequest.setLink("new_link"); + + //ACT + String jsonString = getJsonStringForUPDATE(profileDocumentUpdateRequest, ID); + + addRecordToKafka((MockConsumer) profileDocumentService.getConsumer(), TOPIC_DESTINATION_PROFILE_DOCUMENT_UPDATE, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + ProfileDocument resultUpdate = profileDocumentMap.getSingleObjectBySQL(String.format("companyId = %d", COMPANY_ID)); +// predictableProfileDocument.setId(resultUpdate.getId()); + PROFILE_DOCUMENT_MATCHER.assertMatch(resultUpdate, predictableProfileDocument); + } } \ No newline at end of file From 96dc0d031343208d8ffb40f6cc3199d5fc900462 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Tue, 4 Apr 2023 17:23:59 +0300 Subject: [PATCH 2/4] =?UTF-8?q?clearing-utils=20=D1=83=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D1=88=D0=B8=D0=BB=20=D1=87=D0=B8=D1=82=D0=B0=D0=B5=D0=BC=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clearing-parent/clearing-utils/pom.xml | 5 +++-- .../validation/common/rules/DictionaryPresentRule.java | 5 +++++ .../clearing/validation/common/rules/EnumPresentRule.java | 5 +++++ .../clearing/validation/common/rules/FieldRequiredRule.java | 5 +++++ .../clearing/validation/common/rules/IdPresentRule.java | 5 +++++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/clearing-parent/clearing-utils/pom.xml b/clearing-parent/clearing-utils/pom.xml index 4b9ecb09b..580382cc7 100644 --- a/clearing-parent/clearing-utils/pom.xml +++ b/clearing-parent/clearing-utils/pom.xml @@ -4,8 +4,9 @@ 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-module, dependency version of platform-utils + clearing-utils + clearing-utils + 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/validation/common/rules/DictionaryPresentRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java index 8fed6e5ed..ab42f8bc0 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java +++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/DictionaryPresentRule.java @@ -99,4 +99,9 @@ public record DictionaryPresentRule(String fiel } return empty(); } + + @Override + public String ruleName() { + return getClass().getSimpleName() + "{" + fieldName + " - " + dictionaryName + "}"; + } } diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java index a819a26e6..13a3494ff 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java +++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/EnumPresentRule.java @@ -69,4 +69,9 @@ public record EnumPresentRule(String fieldName, } return of(errorWrongEnumValue, fieldName); } + + @Override + public String ruleName() { + return getClass().getSimpleName() + "{" + fieldName + "}"; + } } diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java index 93473976a..2e215648e 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java +++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/FieldRequiredRule.java @@ -40,4 +40,9 @@ public record FieldRequiredRule( if (value == null) return of(errorEmptyRequiredValue, fieldName); return empty(); } + + @Override + public String ruleName() { + return getClass().getSimpleName() + "{" + fieldName + "}"; + } } diff --git a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java index 02db04c3e..5ce3c570f 100644 --- a/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java +++ b/clearing-parent/clearing-utils/src/main/java/ru/spcex/clearing/validation/common/rules/IdPresentRule.java @@ -103,4 +103,9 @@ public record IdPresentRule( } return empty(); } + + @Override + public String ruleName() { + return getClass().getSimpleName() + "{" + fieldName + "}"; + } } From ba4a7140d6ab65239350473eb0dff68ae1c58877 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Tue, 4 Apr 2023 17:57:56 +0300 Subject: [PATCH 3/4] http://jira.mfd.msk:8088/browse/CLS-259 CompanyService --- .../company/config/BeanConfiguration.java | 7 + .../validation/CompanyValidationConfig.java | 94 ++++- .../config/validation/ValidationConfig.java | 4 + .../company/service/CompanyService.java | 343 +++++++++++++----- .../clearing/company/util/RequestHelper.java | 24 +- .../company/config/BeanConfiguration.java | 21 ++ .../company/service/CompanyServiceTest.java | 81 ++++- 7 files changed, 466 insertions(+), 108 deletions(-) create mode 100644 clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/config/BeanConfiguration.java diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java index c77296e64..cec73efc2 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/BeanConfiguration.java @@ -2,6 +2,8 @@ package ru.spcex.clearing.company.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.util.security.UserRoleVerification; +import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.enumeration.SimpleMessageResolver; @@ -11,4 +13,9 @@ public class BeanConfiguration { public IMessageResolver messageResolver() { return new SimpleMessageResolver(); } + + @Bean + UserRoleVerification userRoleVerification(ImdgProvider imdg) { + return new UserRoleVerification(imdg); + } } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/CompanyValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/CompanyValidationConfig.java index 5c80d1569..2d3a63605 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/CompanyValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/CompanyValidationConfig.java @@ -2,9 +2,19 @@ package ru.spcex.clearing.company.config.validation; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.platform.dictionary.CompanySymbolDictionary; +import ru.clearing.platform.dictionary.WorkflowStatusDictionary; +import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.company.CompanyNewRequest; +import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule; +import ru.spcex.clearing.validation.common.rules.FieldRequiredRule; +import ru.spcex.clearing.validation.common.rules.IdPresentRule; import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.WorkflowStatus; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.utils.validation.IValidator; @@ -23,24 +33,84 @@ public class CompanyValidationConfig { ImdgValidationContext context = new ImdgValidationContext<>(); context.setValidatedObject(companyNewRequest); Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); -// addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); -// addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_CompanySymbolDictionary); + addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary); addImdg.accept(IMDGDistributedNames.Map_Company); -// addImdg.accept(IMDGDistributedNames.Map_Security); return new ValidatorImpl<>(context - // , -// FieldRequiredRule.instance("shortName", CompanyNewRequest::getShortName, CompanyErrors.RequiredFieldEmpty), -// FieldRequiredRule.instance("companySymbol", CompanyNewRequest::getCompanySymbol, CompanyErrors.RequiredFieldEmpty), -// FieldRequiredRule.instance("companySymbolValue", CompanyNewRequest::getCompanySymbolValue, CompanyErrors.RequiredFieldEmpty), -// FieldRequiredRule.instance("workflowStatus", CompanyNewRequest::getWorkflowStatus, CompanyErrors.RequiredFieldEmpty), + , + FieldRequiredRule.instance("shortName", CompanyNewRequest::getShortName, CompanyErrors.RequiredFieldEmpty), + FieldRequiredRule.instance("companySymbol", CompanyNewRequest::getCompanySymbol, CompanyErrors.RequiredFieldEmpty), + FieldRequiredRule.instance("companySymbolValue", CompanyNewRequest::getCompanySymbolValue, CompanyErrors.RequiredFieldEmpty), +// FieldRequiredRule.instance("workflowStatus", CompanyNewRequest::getWorkflowStatus, CompanyErrors.RequiredFieldEmpty), -// DictionaryPresentRule.instance("workflowStatus", -// CompanyNewRequest::getWorkflowStatus, -// IMDGDistributedNames.Map_WorkflowStatus, -// WorkflowStatusDictionary.class), + DictionaryPresentRule.instance("workflowStatus", + CompanyNewRequest::getWorkflowStatus, + IMDGDistributedNames.Map_WorkflowStatusDictionary, + WorkflowStatusDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue), + DictionaryPresentRule.instance("companySymbol", + CompanyNewRequest::getCompanySymbol, + IMDGDistributedNames.Map_CompanySymbolDictionary, + CompanySymbolDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue) + ); + }; + } + + @Bean("companyUpdateRequestValidator")//todo type of request + public Function companyUpdateRequestValidator(Map> imdgForValidation) { + return companyNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(companyNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_CompanySymbolDictionary); + addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + return new ValidatorImpl<>(context, + FieldRequiredRule.instance("id", CompanyNewRequest::getId, CompanyErrors.RequiredFieldEmpty), + + FieldRequiredRule.instance("shortName", CompanyNewRequest::getShortName, CompanyErrors.RequiredFieldEmpty), +// FieldRequiredRule.instance("companySymbol", CompanyNewRequest::getCompanySymbol, CompanyErrors.RequiredFieldEmpty), +// FieldRequiredRule.instance("companySymbolValue", CompanyNewRequest::getCompanySymbolValue, CompanyErrors.RequiredFieldEmpty), + FieldRequiredRule.instance("workflowStatus", CompanyNewRequest::getWorkflowStatus, CompanyErrors.RequiredFieldEmpty), + + DictionaryPresentRule.instance("workflowStatus", + CompanyNewRequest::getWorkflowStatus, + IMDGDistributedNames.Map_WorkflowStatusDictionary, + WorkflowStatusDictionary.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.WrongFieldValue) +// DictionaryPresentRule.instance("companySymbol", +// CompanyNewRequest::getCompanySymbol, +// IMDGDistributedNames.Map_CompanySymbolDictionary, +// CompanySymbolDictionary.class, +// CompanyErrors.RequiredFieldEmpty, +// CompanyErrors.WrongFieldValue) ); }; } + @Bean("CompanyDeleteRequestValidator") + public Function companyDeleteRequestValidator(Map> imdgForValidation) { + return companyDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(companyDeleteRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + return new ValidatorImpl<>(context, +// FieldRequiredRule.instance("id", CommonDeleteRequest::getId, CompanyErrors.RequiredFieldEmpty), + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_Company, + Company.class, + CompanyErrors.RequiredFieldEmpty, + CompanyErrors.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled) + ); + }; + } + } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ValidationConfig.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ValidationConfig.java index 9ce392c5d..20ce51e01 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ValidationConfig.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/ValidationConfig.java @@ -32,6 +32,10 @@ public class ValidationConfig { addImdg.accept(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class); addImdg.accept(IMDGDistributedNames.Map_DocumentTypeDictionary, DocumentTypeDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary, DocumentTypeDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_CompanySymbolDictionary, DocumentTypeDictionary.class); + + return imdg; } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java index 9a38c614d..69af48acd 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/service/CompanyService.java @@ -9,6 +9,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.company.CompanySymbols; +import ru.clearing.classes.statics.data.company.relation.Relation; +import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.company.util.RequestHelper; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; @@ -16,116 +19,101 @@ import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.company.CompanyNewRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; -import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.util.security.UserRoleVerification; +import ru.spcex.clearing.validation.common.ValidationHelper; +import ru.spcex.platform.enumeration.*; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgId; import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.error.ValidationException; import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; -import java.util.Optional; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; import java.util.function.Function; @Service public class CompanyService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); + private final RequestHelper requestHelper; private final Imdg companyMap; + private final Imdg companySymnbolsMap; + private final Imdg relationMap; private final ImdgId idSequence; -// protected UserRoleVerification userRoleVerification; - protected IMessageResolver messageResolver; + protected UserRoleVerification userRoleVerification; + protected IMessageResolver messageResolver; + private ValidationHelper validationHelper; private Function companyNewRequestValidator; + private Function companyUpdateRequestValidator; + private Function companyDeleteRequestValidator; + + // Синхронизация обновлений + public final Object lockCompany = new Object(); // Company, CompanySymbol, @Autowired public CompanyService(Consumer kafkaQueue, Producer kafkaProducer, ImdgProvider imdgProvider, - IMessageResolver messageResolver, -// , UserRoleVerification userRoleVerification + IMessageResolver messageResolver, + UserRoleVerification userRoleVerification, + ValidationHelper validationHelper, @Qualifier("companyNewRequestValidator") - Function companyNewRequestValidator + Function companyNewRequestValidator, + @Qualifier("companyUpdateRequestValidator") + Function companyUpdateRequestValidator, + @Qualifier("CompanyDeleteRequestValidator") + Function companyDeleteRequestValidator ) { super(kafkaQueue, kafkaProducer); this.messageResolver = messageResolver; + this.requestHelper = new RequestHelper(log, messageResolver); this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + this.relationMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); + this.companySymnbolsMap = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); this.idSequence = imdgProvider.getImdgIdGenerator(); -// this.userRoleVerification = userRoleVerification; + this.userRoleVerification = userRoleVerification; + this.validationHelper = validationHelper; this.companyNewRequestValidator = companyNewRequestValidator; + this.companyUpdateRequestValidator = companyUpdateRequestValidator; + this.companyDeleteRequestValidator = companyDeleteRequestValidator; } @Override public void afterPropertiesSet() { - RequestHelper requestHelper = new RequestHelper(log, messageResolver); callback(CommonDeleteRequest.class) - .setConsumer(this::deleteCompany) + .setConsumer(request -> requestHelper.requestFunction(this::deleteCompany, request)) .forDestination(Consts.DESTINATION_COMPANY_DELETE, callbacks::put); callback(CompanyNewRequest.class) - .setFunction( request -> requestHelper.requestFunction(this::createCompany, request)) + .setFunction(request -> requestHelper.requestFunction(this::createCompany, request)) .forDestination(Consts.DESTINATION_COMPANY_NEW, callbacks::put); callback(CompanyNewRequest.class) - .setConsumer(this::updateCompany) + .setConsumer(request -> requestHelper.requestFunction(this::updateCompany, request)) .forDestination(Consts.DESTINATION_COMPANY_UPDATE, callbacks::put); - //todo IV - сообщения на добавления документа расторжения договора - см. Документ расторжения договора. profileDocument): необходимо обновить запись в company согласно описанию с тэгом "При обработке расторжения". -// callback(CompanyNewRequest.class) -// .setConsumer(this::updateCompany) -// .forDestination(Consts.DESTINATION_COMPANY_UPDATE, callbacks::put); init(); } -// -// interface RequestCommand { -// Long command(T arg) throws ClearingBaseException; -// } -// -// protected > Object requestFunction(RequestCommand command, T userRequest) { -// try { -// Long itemAffected = command.command(userRequest); -// log.trace("Item affected: {}", itemAffected); -// return null; -// } catch (ClearingBaseException expectedE) { -// log.trace("{} return expected exception: {}", command, expectedE.toString()); -// return new RequestInfoUpdate() -// .setId(userRequest.getId()) -// .setStatus(Status.Error) -// .setMessage(expectedE.getMessage()); -// } catch (Exception unexpectedE) { -// log.error("Error at {}: {} ", command, ExceptionUtils.getStackTrace(unexpectedE)); -// String message = messageResolver.resolve(new EnumMessage(CompanyErrors.GeneralError)); -// return new RequestInfoUpdate() -// .setId(userRequest.getId()) -// .setStatus(Status.Error) -// .setMessage(message); -// } -// } - protected void validateRole(BaseRequest req) throws ValidationException { - Long requestor = null; // todo требуется передавать это значение из frontendapi! req.getUserId(); -// if (!userRoleVerification.userHasRole(requestor, UserRole.Admin)) { -// -// }; - } - - void validate(CompanyNewRequest object) throws ValidationException { - IValidator validator = companyNewRequestValidator.apply(object); - Optional error = validator.tillFirstError(); - if (error.isPresent()) { - log.warn("CompanyNewRequest validation error: {}", error.get()); - throw new ValidationException(error.get()); -// String errorMsg = messageResolver.resolve(error.get()); -// return new RequestInfoUpdate() // todo reply message -// .setId(userRequest.getId()) -// .setStatus(Status.Error) -// .setMessage(errorMsg); + protected void validateRole(BaseRequest req) throws ValidationException { + Long requestor = req.getUserId(); + if (requestor != null && !userRoleVerification.userHasRole(requestor, UserRole.Admin)) { + log.trace("User {} has no role to allow this action", requestor); + throw new ValidationException(CompanyErrors.UserVerifyDenial); + } else { + log.trace("Request without userId"); } } - private Long createCompany(BaseRequest companyNewRequestBaseRequest) throws ValidationException { + + private synchronized RequestInfoUpdate createCompany(BaseRequest companyNewRequestBaseRequest) throws ValidationException { CompanyNewRequest req = companyNewRequestBaseRequest.getRequestPayload(); log.debug("company-new request received, BaseRequest.id = {}", companyNewRequestBaseRequest.getId()); { // Валидация, ValidationException validateRole(companyNewRequestBaseRequest); - validate(req); + RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(companyNewRequestBaseRequest, companyNewRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; } Company company = new Company(); company.setId(idSequence.nextId()); @@ -135,46 +123,223 @@ public class CompanyService extends QueueConsumer implements InitializingBean { company.setShortName(req.getShortName()); company.setFullName(req.getFullName()); - company.setTradingCode(req.getTradingCode()); - company.setClearingCode(req.getClearingCode()); - company.setRegistrationCode(req.getRegistrationCode()); + + if (req.getCompanySymbol() != null) { + CompanySymbols newSymbol = createCompanySymbol(company, req); + updateCompanyBySymbol(company, newSymbol); + log.debug("Created new companySymbols.id={} for company {}", newSymbol.getId(), company.getId()); + companySymnbolsMap.insert(newSymbol); + } company.setWorkflowStatus(WorkflowStatus.Active.getKey()); -// if (WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) { -// -// } else if (WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus())) { -// -// } companyMap.insert(company); log.debug("company-new request processed, BaseRequest.id = {}, company.id={}", companyNewRequestBaseRequest.getId(), company.getId()); + createNewRelation(company); - return company.getId(); + return null; + } + + protected CompanySymbols createCompanySymbol(Company forCompany, CompanyNewRequest request) { + //todo see CompanySymbolService + CompanySymbols newSymbol = new CompanySymbols(); + newSymbol.setId(idSequence.nextId()); + newSymbol.setCompanyId(forCompany.getId()); + newSymbol.setCompanySymbol(request.getCompanySymbol()); + newSymbol.setCompanySymbolValue(request.getCompanySymbolValue()); + return newSymbol; } - private void updateCompany(BaseRequest companyNewRequestBaseRequest) { - //todo update -// CompanyUpdateRequest req = companyUpdateRequestBaseRequest.getRequestPayload(); -// log.debug("company-update request received, BaseRequest.id = {}", companyNewRequestBaseRequest.getId()); -// Company company = new Company(); -// company.setShortName(req.getShortName()); -// company.setFullName(req.getFullName()); -// company.setTradingCode(req.getTradingCode()); -// company.setClearingCode(req.getClearingCode()); -// company.setRegistrationCode(req.getRegistrationCode()); -// companyMap.insert(company); -// log.debug("company-update request processed, BaseRequest.id = {}, company.id={}", -// companyNewRequestBaseRequest.getId(), company.getId()); + private synchronized RequestInfoUpdate updateCompany(BaseRequest companyUpdateRequestBaseRequest) throws ValidationException { + CompanyNewRequest updateRequest = companyUpdateRequestBaseRequest.getRequestPayload(); + { // Валидация, ValidationException + validateRole(companyUpdateRequestBaseRequest); + RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(companyUpdateRequestBaseRequest, companyUpdateRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + } + Company company = companyMap.getSingleObjectByID(updateRequest.getId()); // todo use validationContext. + if (company == null) { + log.trace("Company {} not found", updateRequest.getId()); + return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyNotFound, updateRequest.getId()); + } + if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) { + log.trace("Company {} not active: {}", company.getId(), company.getWorkflowStatus()); + return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyDisabled, updateRequest.getId()); + } + + company.setUpdated(Instant.now()); + company.setShortName(updateRequest.getShortName()); + company.setFullName(updateRequest.getFullName()); + + if (updateRequest.getCompanySymbol() != null || updateRequest.getCompanySymbolValue() != null) { + log.trace("Request field CompanySymbol, CompanySymbolValue ignore for update company request."); + } + CompanySymbols companySymbol = companySymnbolsMap.getSingleObjectByFieldValues(Map.of("companyId", company.getId())); + if (companySymbol == null) { + log.warn("CompanySymbols not found for companyId={}", company.getId()); + } else { + log.trace("Found CompanySymbols.id={} for companyId={}", companySymbol.getId(), company.getId()); + updateCompanyBySymbol(company, companySymbol); + } + + +// String prevStatus = company.getWorkflowStatus(); +// if (updateRequest.getWorkflowStatus() != null) { +// company.setWorkflowStatus(updateRequest.getWorkflowStatus()); +// if (!Objects.equals(prevStatus, company.getWorkflowStatus())) { +// onChangeWorkflowStatus(company, prevStatus, company.getWorkflowStatus()); +// } else { +// log.trace("Status was not changed"); +// } +// } else { +// log.trace("Null new WorkflowStatus"); +// } + return null; + } + + protected void updateCompanyBySymbol(Company company, CompanySymbols companySymbol) { + assert company.getId().equals(companySymbol.getCompanyId()); + if (CompanySymbol.TRDC.equalsByKey(companySymbol.getCompanySymbol())) { + company.setTradingCode(companySymbol.getCompanySymbolValue()); + } else { + company.setTradingCode(null); + } + if (CompanySymbol.CLRC.equalsByKey(companySymbol.getCompanySymbol())) { + company.setClearingCode(companySymbol.getCompanySymbolValue()); + } else { + company.setClearingCode(null); + } + if (CompanySymbol.RGRC.equalsByKey(companySymbol.getCompanySymbol())) { + company.setRegistrationCode(companySymbol.getCompanySymbolValue()); + } else { + company.setRegistrationCode(null); + } } + protected static final Long SPVB_ID = 1L; // СПВБ - private void deleteCompany(BaseRequest userRequest) { - CommonDeleteRequest req = userRequest.getRequestPayload(); - log.debug("CommonDeleteRequest received id = {}", req.getId()); - Company company = companyMap.getSingleObjectByID(req.getId()); - companyMap.delete(company); + private void createNewRelation(Company company) { + Relation relation = new Relation(); + relation.setId(idSequence.nextId()); + relation.setCreated(Instant.now()); + relation.setUpdated(relation.getCreated()); + + relation.setConsumerId(company.getId()); + relation.setSupplierId(SPVB_ID); // 1 СПВБ + relation.setServiceStatus(WorkflowStatus.Active.getKey()); + relation.setService(ru.spcex.platform.enumeration.Service.MKR.getKey()); // MKR + relation.setServiceProduct(ServiceProduct.ZERO.getKey()); + log.debug("New Relation[{}] created.", relation.getId()); + relationMap.insert(relation); // todo use transaction! + } + + /** + * @param company + * @param oldStatus + * @param newStatus WorkflowStatus.Active - при возобналвении; WorkflowStatus.Blocked - при блокировки/расторжении + */ + private void onChangeWorkflowStatus(Company company, String oldStatus, String newStatus) { + //todo в ТЗ упоминается: ри изменении (relation/put): //из соответствующего параметра полученного метода, если значение отличается от сохраненного ране + log.debug("Company id={} status changed from {} to {}", + company.getId(), oldStatus, company.getWorkflowStatus()); + assert Objects.equals(newStatus, company.getWorkflowStatus()); + String query = String.format("consumerId=%s", company.getId()); + Collection relations = relationMap.getCollectionObjectsBySQL(query); + log.trace("Selected {} Relation by query: {}", relations.size(), query); + Instant now = Instant.now(); + for (Relation relation : relations) { + boolean modified = false; + if (WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) { + if (!ServiceStatus.Reopened.equalsByKey(relation.getServiceStatus())) { + relation.setServiceStatus(ServiceStatus.Reopened.getKey()); + modified = true; + } + } else if (WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus())) { + if (!ServiceStatus.Closed.equalsByKey(relation.getServiceStatus())) { + relation.setServiceStatus(ServiceStatus.Closed.getKey()); + modified = true; + } + } + if (modified) { + relation.setUpdated(now); + log.debug("Relation id={} updated", relation.getId()); + relationMap.update(relation); + } + } + + } + + + /** + * Блокировка компании + * + * @param companyBlockRequestBaseRequest + * @return + */ + private synchronized RequestInfoUpdate deleteCompany(BaseRequest companyBlockRequestBaseRequest) throws ValidationException { + CommonDeleteRequest request = companyBlockRequestBaseRequest.getRequestPayload(); + log.debug("CommonDeleteRequest (block request) received id = {}", request.getId()); + { // Валидация, ValidationException + validateRole(companyBlockRequestBaseRequest); + RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(companyBlockRequestBaseRequest, companyDeleteRequestValidator); + if (requestInfoUpdate != null) return requestInfoUpdate; + } + Company company = companyMap.getSingleObjectByID(request.getId()); + if (company == null) { + log.warn("Company {} not found", request.getId()); + return requestHelper.makeErrorResponse(companyBlockRequestBaseRequest, CompanyErrors.CompanyNotFound, request.getId()); + } +// if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) { +// log.trace("Company {} not active: {}", company.getId(), company.getWorkflowStatus()); +// return requestHelper.makeErrorResponse(companyBlockRequestBaseRequest, CompanyErrors.CompanyDisabled, request.getId()); +// } + + company.setUpdated(Instant.now()); + + CompanySymbols companySymbol = companySymnbolsMap.getSingleObjectByFieldValues(Map.of("companyId", company.getId())); + if (companySymbol == null) { + log.warn("CompanySymbols not found for companyId={}", company.getId()); + } else { + log.trace("Found CompanySymbols.id={} for companyId={}", companySymbol.getId(), company.getId()); + updateCompanyBySymbol(company, companySymbol); + } + + String prevStatus = company.getWorkflowStatus(); + company.setWorkflowStatus(WorkflowStatus.Blocked.getKey()); + onChangeWorkflowStatus(company, prevStatus, company.getWorkflowStatus()); + log.debug("Update company.id={}", company.getId()); + companyMap.update(company); + + // todo kafka send !!! Account. + return null; + +// Company company = companyMap.getSingleObjectByID(req.getId()); +// companyMap.delete(company); + } + + + /** + * IV - сообщения на добавления документа расторжения договора + * + * @param companyId + */ + public synchronized void onRastorjeniye(Long companyId) { + Company company = companyMap.getSingleObjectByID(companyId); + if (company == null) { + log.warn("Company {} not found", companyId); + return; + } + + if (!WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus())) { + log.debug("Update company.id={}", company.getId()); + company.setWorkflowStatus(WorkflowStatus.Blocked.getKey()); + company.setUpdated(Instant.now()); + companyMap.update(company); + } else { + log.trace("Company {} already has blocked.", companyId); + } } } diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java index 5cbb5d6da..1b810e700 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/util/RequestHelper.java @@ -6,6 +6,7 @@ import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumId; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.error.ClearingBaseException; import ru.spcex.platform.utils.log.ExceptionUtils; @@ -42,9 +43,10 @@ public class RequestHelper { */ public > RequestInfoUpdate requestFunction(RequestCommand command, T userRequest) { try { - Long itemAffected = command.command(userRequest); - log.trace("Item affected: {}", itemAffected); - return null; + log.debug("{} request received, BaseRequest.id = {}", userRequest.getClass().getSimpleName(), userRequest.getId()); + RequestInfoUpdate reply = command.command(userRequest); + log.trace("Reply on request {}: {}" , userRequest.getId(), reply); + return reply; } catch (ClearingBaseException expectedE) { log.trace("{} return expected exception: {}", command, expectedE.toString()); String message = expectedE.getEnumMsg() == null @@ -64,7 +66,21 @@ public class RequestHelper { } } + public RequestInfoUpdate makeErrorResponse(BaseRequest request, EnumMessage msg) { + String errorMsg = msg == null? "" : messageResolver.resolve(msg); + return new RequestInfoUpdate() + .setId(request.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + + + public RequestInfoUpdate makeErrorResponse(BaseRequest request, IEnumId error, Object ... args) { + //todo должны уточнить интерфейс IEnumId в CompanyErrors, вечером проверить код. + return makeErrorResponse(request, new EnumMessage(error, args)); + } + public interface RequestCommand { - Long command(T arg) throws ClearingBaseException; + RequestInfoUpdate command(T arg) throws ClearingBaseException; } } diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/config/BeanConfiguration.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/config/BeanConfiguration.java new file mode 100644 index 000000000..cec73efc2 --- /dev/null +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/config/BeanConfiguration.java @@ -0,0 +1,21 @@ +package ru.spcex.clearing.company.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.util.security.UserRoleVerification; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.enumeration.SimpleMessageResolver; + +@Configuration +public class BeanConfiguration { + @Bean + public IMessageResolver messageResolver() { + return new SimpleMessageResolver(); + } + + @Bean + UserRoleVerification userRoleVerification(ImdgProvider imdg) { + return new UserRoleVerification(imdg); + } +} diff --git a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java index b8cd3e7e2..84ce45c8a 100644 --- a/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java +++ b/clearing-parent/company-service/src/test/java/ru/spcex/clearing/company/service/CompanyServiceTest.java @@ -14,33 +14,47 @@ 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.company.Company; +import ru.clearing.classes.statics.data.company.CompanySymbols; import ru.clearing.classes.statics.data.generated.ClearingMemberCategory; +import ru.clearing.platform.dictionary.CompanySymbolDictionary; +import ru.clearing.platform.dictionary.WorkflowStatusDictionary; +import ru.spcex.clearing.company.config.BeanConfiguration; import ru.spcex.clearing.company.config.HazelcastServiceTestConfiguration; import ru.spcex.clearing.company.config.KafkaConfigTest; +import ru.spcex.clearing.company.config.validation.CompanyValidationConfig; +import ru.spcex.clearing.company.config.validation.ValidationConfig; import ru.spcex.clearing.company.utils.MatcherFactory; 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.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.company.CompanyNewRequest; +import ru.spcex.platform.enumeration.CompanySymbol; +import ru.spcex.platform.enumeration.WorkflowStatus; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; import javax.annotation.PostConstruct; +import java.util.Map; + import static ru.spcex.clearing.company.utils.MatcherFactory.usingIgnoringFieldsComparator; import static ru.spcex.clearing.company.utils.TestUtils.*; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { CompanyService.class, + CompanyValidationConfig.class, + ValidationConfig.class, + KafkaConfigTest.class, - HazelcastServiceTestConfiguration.class}) + HazelcastServiceTestConfiguration.class, + BeanConfiguration.class}) class CompanyServiceTest { public static final MatcherFactory.Matcher COMPANY_MATCHER = usingIgnoringFieldsComparator(); private static final int PARTITION = 0; private static final String TOPIC_COMPANY_DELETE = Consts.DESTINATION_COMPANY_DELETE; - private static final Long ID = 0L; @Autowired CompanyService companyService; @@ -48,6 +62,7 @@ class CompanyServiceTest { @Qualifier("hazelcastServiceTest") private HazelcastService hazelcastServiceTest; private Imdg companyImdg; + private Imdg workflowStatusDictionaryImdg; @Captor private ArgumentCaptor producerRecord; @@ -58,6 +73,28 @@ class CompanyServiceTest { private void init() { hazelcastServiceTest.waitAvailable(); companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + + workflowStatusDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_WorkflowStatusDictionary, WorkflowStatusDictionary.class); + WorkflowStatusDictionary ws1 = new WorkflowStatusDictionary(); + ws1.setId(1L); + ws1.setCode(WorkflowStatus.Active.getKey()); + ws1.setName("Active"); + workflowStatusDictionaryImdg.insert(ws1); + WorkflowStatusDictionary ws2 = new WorkflowStatusDictionary(); + ws2.setId(2L); + ws2.setCode(WorkflowStatus.Blocked.getKey()); + ws2.setName("Blocked"); + workflowStatusDictionaryImdg.insert(ws2); + + Imdg companySymbolDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_CompanySymbolDictionary, CompanySymbolDictionary.class); + { + CompanySymbolDictionary cSymbol = new CompanySymbolDictionary(); + cSymbol.setId(11L); + cSymbol.setCode(CompanySymbol.CLRC.getKey()); + cSymbol.setName(CompanySymbol.CLRC.getKey()); + cSymbol.setShortname(" CLRC key"); + companySymbolDictionaryImdg.insert(cSymbol); + } } /** @@ -69,8 +106,10 @@ class CompanyServiceTest { @Test void deleteCompany() throws InterruptedException { //ARRANGE + final Long ID = 101L; Company existsCompany = new Company(); existsCompany.setId(ID); + existsCompany.setWorkflowStatus(WorkflowStatus.Active.getKey()); companyImdg.insert(existsCompany); CommonDeleteRequest commonDeleteRequest = new CommonDeleteRequest(); @@ -84,6 +123,42 @@ class CompanyServiceTest { waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); Company resultDeleting = companyImdg.getSingleObjectByID(ID); - Assertions.assertNull(resultDeleting); + Assertions.assertEquals(WorkflowStatus.Blocked.getKey(), resultDeleting.getWorkflowStatus()); + //Assertions.assertNull(resultDeleting); + } + + + /** + * {@link CompanyService#createCompany(BaseRequest)}
+ * Тест проверяет удаление сущности {@link Company} в Hazelcast при передаче из Apache Kafka.
+ * Входной запрос {@link CommonDeleteRequest}:
+ * {@link CommonDeleteRequest#id} - Идентификатор записи
+ */ + @Test + void newCompany() throws InterruptedException { + //ARRANGE + final Long ID = 102L; + final String DESTINATION_COMPANY_NEW = Consts.DESTINATION_COMPANY_NEW; + companyImdg.size(); + + CompanyNewRequest companyNewRequest = new CompanyNewRequest(); +// companyNewRequest.setId(ID); + companyNewRequest.setCompanySymbol(CompanySymbol.CLRC.getKey()); + companyNewRequest.setCompanySymbolValue("CLR-symbol ipo"); + companyNewRequest.setShortName("ClrIPO"); + companyNewRequest.setFullName("Clearing IPO"); + companyNewRequest.setWorkflowStatus(WorkflowStatus.Active.getKey()); + + //ACT + String jsonString = getJsonStringForNew(companyNewRequest, ID); + addRecordToKafka((MockConsumer) companyService.getConsumer(), DESTINATION_COMPANY_NEW, PARTITION, 0, jsonString); + + //ASSERT + waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord); + + Company resultNew = companyImdg.getSingleObjectByFieldValues(Map.of("ShortName", "ClrIPO")); + Assertions.assertNotNull(resultNew); + Assertions.assertEquals("ClrIPO", resultNew.getShortName()); + Assertions.assertEquals(WorkflowStatus.Active.getKey(), resultNew.getWorkflowStatus()); } } \ No newline at end of file From d07674e2c6997362f5c77f60488d261de3443289 Mon Sep 17 00:00:00 2001 From: akulikov Date: Tue, 4 Apr 2023 16:21:13 +0300 Subject: [PATCH 4/4] ContactNewRequest --- .../platform/messaging/domain/Consts.java | 1 + .../domain/cud/company/ContactNewRequest.java | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/ContactNewRequest.java diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java index 7e768cc99..5ee689fce 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/Consts.java @@ -35,6 +35,7 @@ public interface Consts { String DESTINATION_COMPANY_BLOCK = "company-block"; String DESTINATION_COMPANY_INFO_UPDATE = "company-info-update"; String DESTINATION_COMPANY_SYMBOL_UPDATE = "company-symbol-update"; + String DESTINATION_CONTACT_NEW = "contact-new"; String DESTINATION_CONTACT_UPDATE = "contact-update"; String DESTINATION_CLEARING_MEMBER_CATEGORY_NEW = "clearing-member-category-new"; String DESTINATION_CLEARING_MEMBER_CATEGORY_UPDATE = "clearing-member-category-update"; diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/ContactNewRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/ContactNewRequest.java new file mode 100644 index 000000000..8df5eea1c --- /dev/null +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/company/ContactNewRequest.java @@ -0,0 +1,36 @@ +package ru.spcex.clearing.platform.messaging.domain.cud.company; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ContactNewRequest { + @JsonProperty + private Long companyId; + @JsonProperty + private String contactType; + @JsonProperty + private String contactValue; + + public Long getCompanyId() { + return companyId; + } + + public void setCompanyId(Long companyId) { + this.companyId = companyId; + } + + public String getContactType() { + return contactType; + } + + public void setContactType(String contactType) { + this.contactType = contactType; + } + + public String getContactValue() { + return contactValue; + } + + public void setContactValue(String contactValue) { + this.contactValue = contactValue; + } +}