From 924a6ec1574405ce6a1fa00258c718f48c4eb6e6 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Wed, 25 Feb 2026 10:46:30 +0300 Subject: [PATCH] http://jira.mfd.msk:8088/browse/CLS-927 --- ...learingMemberCategoryValidationConfig.java | 13 +- .../config/validation/ValidationConfig.java | 2 + .../ProviderMemberCategoryValidationRule.java | 166 ++++++++++++++++++ .../clearing/company/error/CompanyErrors.java | 3 + .../enumeration/ClearingCategory.java | 3 +- 5 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/rules/ProviderMemberCategoryValidationRule.java 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 4abf7396c..a38f6af61 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 @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Configuration; import ru.clearing.classes.statics.data.company.ClearingMemberCategory; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.platform.dictionary.ClearingCategoryDictionary; +import ru.spcex.clearing.company.config.validation.rules.ProviderMemberCategoryValidationRule; import ru.spcex.clearing.company.error.CompanyErrors; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; @@ -50,7 +51,8 @@ public class ClearingMemberCategoryValidationConfig { IMDGDistributedNames.Map_ClearingCategoryDictionary, ClearingCategoryDictionary.class, CompanyErrors.RequiredFieldEmpty, - CompanyErrors.DictionaryNotFound) + CompanyErrors.DictionaryNotFound), + ProviderMemberCategoryValidationRule.NEW ); }; } @@ -66,6 +68,7 @@ public class ClearingMemberCategoryValidationConfig { addImdg.accept(IMDGDistributedNames.Map_Company); addImdg.accept(IMDGDistributedNames.Map_ClearingCategoryDictionary); addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory); + addImdg.accept(IMDGDistributedNames.Map_Registry); return new ValidatorImpl<>(context, IdPresentSpecificRule.instance("id", ClearingMemberCategoryUpdateRequest::getId, @@ -87,7 +90,8 @@ public class ClearingMemberCategoryValidationConfig { ClearingCategoryDictionary.class, CompanyErrors.RequiredFieldEmpty, CompanyErrors.DictionaryNotFound, - false) + false), + ProviderMemberCategoryValidationRule.UPDATE ); }; } @@ -101,13 +105,16 @@ public class ClearingMemberCategoryValidationConfig { context.setValidatedObject(clearingMemberCategoryDeleteRequest); Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory); + addImdg.accept(IMDGDistributedNames.Map_Registry); + addImdg.accept(IMDGDistributedNames.Map_Company); return new ValidatorImpl<>(context, IdPresentRule.instance("id", CommonDeleteRequest::getId, IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class, CompanyErrors.RequiredFieldEmpty, - CompanyErrors.CategoryNotFound) + CompanyErrors.CategoryNotFound), + ProviderMemberCategoryValidationRule.DELETE ); }; } 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 2dcbc91f6..374756b13 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 @@ -8,6 +8,7 @@ import ru.clearing.classes.statics.data.company.*; import ru.clearing.classes.statics.data.company.relation.Relation; import ru.clearing.classes.statics.data.profile.Contact; import ru.clearing.classes.statics.data.profile.ProfileDocument; +import ru.clearing.classes.statics.data.registry.Registry; import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; import ru.clearing.platform.dictionary.*; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -31,6 +32,7 @@ public class ValidationConfig { addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); addImdg.accept(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class); + addImdg.accept(IMDGDistributedNames.Map_Registry, Registry.class); addImdg.accept(IMDGDistributedNames.Map_ClearingCategoryDictionary, ClearingCategoryDictionary.class); addImdg.accept(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class); addImdg.accept(IMDGDistributedNames.Map_DocumentTypeDictionary, DocumentTypeDictionary.class); diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/rules/ProviderMemberCategoryValidationRule.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/rules/ProviderMemberCategoryValidationRule.java new file mode 100644 index 000000000..c84922913 --- /dev/null +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/config/validation/rules/ProviderMemberCategoryValidationRule.java @@ -0,0 +1,166 @@ +package ru.spcex.clearing.company.config.validation.rules; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.Optional; +import ru.clearing.classes.statics.data.company.ClearingMemberCategory; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.registry.Registry; +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.ClearingMemberCategoryUpdateRequest; +import ru.spcex.platform.enumeration.ClearingCategory; +import ru.spcex.platform.enumeration.RegistryStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; +import ru.spcex.platform.utils.validation.IValidationRule; + +public enum ProviderMemberCategoryValidationRule implements IValidationRule> { + NEW() { + @Override + public Optional validate(ImdgValidationContext context) { + ClearingMemberCategoryNewRequest categoryReq = (ClearingMemberCategoryNewRequest) context.getValidatedObject(); + ClearingCategory category = IEnumKey.getEnumByKey(ClearingCategory.class, categoryReq.getClearingMemberCategory()); + Imdg categoryImdg = context.obtainMap(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class); + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder(); + ImdgPredicate predicate; + + if (ClearingCategory.P == category) { + predicate = predicateBuilder.equals("companyId", categoryReq.getCompanyId()); + } else { + predicate = predicateBuilder.and( + predicateBuilder.equals("companyId", categoryReq.getCompanyId()), + predicateBuilder.equals("clearingMemberCategory", ClearingCategory.P.getKey()) + ); + } + + ClearingMemberCategory existCategory = categoryImdg.getFirstObjectByPredicate(predicate); + if (existCategory != null) { + Company company = companyImdg.getSingleObjectByID(categoryReq.getCompanyId()); + return Optional.of(new EnumMessage( + CompanyErrors.ProviderCompanyAlreadyExist, + ClearingCategory.P == category ? categoryReq.getClearingMemberCategory() : existCategory.getClearingMemberCategory(), + company.getShortName()) + ); + } + return Optional.empty(); + } + }, + + UPDATE() { + @Override + public Optional validate(ImdgValidationContext context) { + ClearingMemberCategoryUpdateRequest categoryReq = (ClearingMemberCategoryUpdateRequest) context.getValidatedObject(); + ClearingCategory categoryVal = IEnumKey.getEnumByKey(ClearingCategory.class, categoryReq.getClearingMemberCategory()); + Imdg categoryImdg = context.obtainMap(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class); + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder(); + + ClearingMemberCategory clearingMemberCategory = categoryImdg.getSingleObjectByID(categoryReq.getId()); + + if (ClearingCategory.P == categoryVal) { + Collection categories = categoryImdg.getCollectionIdsByPredicate(predicateBuilder.and( + predicateBuilder.equals("companyId", clearingMemberCategory.getCompanyId()), + predicateBuilder.equals("clearingMemberCategory", ClearingCategory.P.getKey()) + )); + if (!categories.isEmpty()) { + return Optional.of(new EnumMessage( + CompanyErrors.ToManyProviderCompany, + categoryReq.getClearingMemberCategory()) + ); + } + } else { + Collection categories = categoryImdg.getCollectionObjectsByPredicate( + predicateBuilder.equals("companyId", clearingMemberCategory.getCompanyId()) + ); + + boolean hasProvider = false; + boolean hasOtherCategory = false; + + ClearingMemberCategory lastOtherCategory = null; + for (ClearingMemberCategory category : categories) { + ClearingCategory clearingCategory = IEnumKey.getEnumByKey(ClearingCategory.class, category.getClearingMemberCategory()); + if (ClearingCategory.P == clearingCategory) { + hasProvider = true; + } else { + lastOtherCategory = category; + hasOtherCategory = true; + } + if (hasProvider && hasOtherCategory) break; + } + + if (hasProvider) { + if (hasOtherCategory) { + return Optional.of(new EnumMessage( + CompanyErrors.ToManyProviderCompany, + lastOtherCategory.getClearingMemberCategory()) + ); + } + + Imdg registryImdg = context.obtainMap(IMDGDistributedNames.Map_Registry, Registry.class); + ImdgPredicate registryPredicate = predicateBuilder.and( + predicateBuilder.equals("companyId", clearingMemberCategory.getCompanyId()), + predicateBuilder.regex("registryCode", "^O.{2}T"), + predicateBuilder.or( + predicateBuilder.and( + predicateBuilder.not(predicateBuilder.equals("registryStatus", RegistryStatus.CLRD.getKey())), + predicateBuilder.equals("clearingDate", LocalDate.now()) + ), + predicateBuilder.greater("settlementDate", LocalDate.now()) + ) + ); + Collection registryIds = registryImdg.getCollectionIdsByPredicate(registryPredicate); + Company company = companyImdg.getSingleObjectByID(clearingMemberCategory.getCompanyId()); + if (!registryIds.isEmpty()) { + return Optional.of(new EnumMessage( + CompanyErrors.FoundUnfulfilledLiabilities, + company.getShortName()) + ); + } + } + } + return Optional.empty(); + } + }, + DELETE() { + @Override + public Optional validate(ImdgValidationContext context) { + CommonDeleteRequest categoryReq = (CommonDeleteRequest) context.getValidatedObject(); + Imdg categoryImdg = context.obtainMap(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class); + Imdg registryImdg = context.obtainMap(IMDGDistributedNames.Map_Registry, Registry.class); + Imdg companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + + ClearingMemberCategory category = categoryImdg.getSingleObjectByID(categoryReq.getId()); + + ImdgPredicateBuilder predicateBuilder = registryImdg.predicateBuilder(); + ImdgPredicate registryPredicate = predicateBuilder.and( + predicateBuilder.equals("companyId", category.getCompanyId()), + predicateBuilder.regex("registryCode", "^O.{2}T"), + predicateBuilder.or( + predicateBuilder.and( + predicateBuilder.not(predicateBuilder.equals("registryStatus", RegistryStatus.CLRD.getKey())), + predicateBuilder.equals("clearingDate", LocalDate.now()) + ), + predicateBuilder.greater("settlementDate", LocalDate.now()) + ) + ); + Collection registryIds = registryImdg.getCollectionIdsByPredicate(registryPredicate); + Company company = companyImdg.getSingleObjectByID(category.getCompanyId()); + if (!registryIds.isEmpty()) { + return Optional.of(new EnumMessage( + CompanyErrors.FoundUnfulfilledLiabilities, + company.getShortName()) + ); + } + return Optional.empty(); + } + } + +} diff --git a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java index d1703fcfb..6e3c50367 100644 --- a/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java +++ b/clearing-parent/company-service/src/main/java/ru/spcex/clearing/company/error/CompanyErrors.java @@ -32,6 +32,9 @@ public enum CompanyErrors implements IErrorEnumId { CompanyParametersNotFound(3032L), // Параметр компании %s не найден RuCurrencyMayOnlyNKOAOPRC(3033L), CompanyHasNoSETHRole(3034L), // Компания %s не является расчетной организацией + ProviderCompanyAlreadyExist(3035L), + ToManyProviderCompany(3036L), + FoundUnfulfilledLiabilities(3037L), ; private final Long id; diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/ClearingCategory.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/ClearingCategory.java index e9aa5181e..a84a57c59 100644 --- a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/ClearingCategory.java +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/ClearingCategory.java @@ -13,7 +13,8 @@ public enum ClearingCategory implements IEnumKey { I("I"), // Категория «И» - Инициатор по ТБС V("V"), // Категория «В» - Инициатор по ТКС T("T"), // Категория «Т» - Участник товарного рынка - K("K"); // Категория «К» - Участник клиринга - Контроллер + K("K"), // Категория «К» - Участник клиринга - Контроллер + P("P"); // Категория «П» - Провайдер ликвидности private final String key;