diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java index 3e58ab090..00121368a 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java @@ -26,10 +26,7 @@ import ru.spcex.clearing.error.ClearingError; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest; import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeRefundDateRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeStatusExtractRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryReturnDepositRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.*; import ru.spcex.clearing.service.validation.*; import ru.spcex.clearing.util.security.UserRoleVerification; import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule; @@ -369,6 +366,26 @@ public class ValidationConfig { }; } + @Bean("identificationFundsValidator") + public Function identificationFundsValidator() { + return identificationFundsRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(identificationFundsRequest); + context.addImdg(IMDGDistributedNames.Map_Registry, imdgRegistry); + context.addImdg(IMDGDistributedNames.Map_TradingClearingRegistry, imdgTradingClearingRegistry); + context.addImdg(IMDGDistributedNames.Map_Account, imdgAccount); + context.setLogPrefix(LogPrefixId.INSTANCE); + return new ValidatorImpl<>(context, + IdentificationFundsValidationRule.Fields, + new PresentById(IMDGDistributedNames.Map_Registry, ClearingError.RecordNotFound, true), + IdentificationFundsValidationRule.RegistryCodeCheck, + IdentificationFundsValidationRule.BalanceCheck, + IdentificationFundsValidationRule.TcrCheck, + IdentificationFundsValidationRule.AssetsCheck + ); + }; + } + @Bean("splitDepositValidator") public Function splitDepositValidator() { return refundDateRequest -> { diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java index cafd85d1c..31f8818ed 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/EventsReceiver.java @@ -17,10 +17,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.clearing.SessionContinueE import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest; import ru.spcex.clearing.platform.messaging.domain.cud.gateway.AssetOperationApprovalRequest; import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeRefundDateRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeStatusExtractRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryReturnDepositRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.*; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest; import ru.spcex.clearing.platform.messaging.domain.cud.utilities.STradesImportedRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; @@ -159,6 +156,9 @@ public class EventsReceiver extends QueueConsumer implements InitializingBean { callback(RegistryChangeStatusExtractRequest.class) .setFunction(registryService::changeStatusExtract) .forDestination(Consts.REGISTRY_CHANGE_STATUS_EXTRACT_ACTION, callbacks::put); + callback(IdentificationFundsRequest.class) + .setFunction(registryService::identificationFunds) + .forDestination(Consts.REGISTRY_IDENTIFICATION_FUNDS, callbacks::put); callback(RegistryChangeRefundDateRequest.class) .setFunction(registryService::changeRefundDate) .forDestination(Consts.REGISTRY_CHANGE_REFUND_DATE_ACTION, callbacks::put); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/RegistryService.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/RegistryService.java index 907e255ec..cd3a090e1 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/RegistryService.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/RegistryService.java @@ -12,10 +12,7 @@ import ru.spcex.clearing.notification.NotificationSender; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.cud.clearing.AssetOperationRequest; import ru.spcex.clearing.platform.messaging.domain.cud.clearing.CreateRegistryRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeRefundDateRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeStatusExtractRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryReturnDepositRequest; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.*; import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.clearing.service.integration.GatewayRequestCreator; @@ -48,6 +45,7 @@ import java.util.function.Function; import java.util.function.Supplier; import static ru.spcex.clearing.session.stage.impl.GatewayRequester.mapError; +import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD; @Service public class RegistryService { @@ -59,6 +57,7 @@ public class RegistryService { private final Function returnDepositVal; private final Function refundDateVal; private final Function statusExtractVal; + private final Function identificationFundsVal; private final Function splitDepositActionVal; private final GatewayRequester gateway; private final TradingTimeService trdTime; @@ -72,15 +71,22 @@ public class RegistryService { public RegistryService(ImdgProvider imdgProvider, @Qualifier("returnDepositValidator") Function returnDepositVal, @Qualifier("refundDateValidator") Function refundDateVal, + @Qualifier("identificationFundsValidator") Function identificationFundsVal, @Qualifier("splitDepositValidator") Function splitDepositActionVal, @Qualifier("statusExtractValidator") Function statusExtractVal, - GatewayRequester gateway, TradingTimeService tradingTimeService, NotificationSender notification, IMessageResolver msgResolver, - RequestHelper reqHelp, UserRoleVerification rights, AssetTBFProcessing assets) { + GatewayRequester gateway, + TradingTimeService tradingTimeService, + NotificationSender notification, + IMessageResolver msgResolver, + RequestHelper reqHelp, + UserRoleVerification rights, + AssetTBFProcessing assets) { this.imdgProvider = imdgProvider; this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class); this.returnDepositVal = returnDepositVal; this.refundDateVal = refundDateVal; + this.identificationFundsVal = identificationFundsVal; this.splitDepositActionVal = splitDepositActionVal; this.statusExtractVal = statusExtractVal; this.gateway = gateway; @@ -227,6 +233,36 @@ public class RegistryService { return reqHelp.success(req.getId()); } + public RequestInfoUpdate identificationFunds(BaseRequest req) { + if (!rights.userHasRole(req.getUserId(), UserRole.Admin)) { + return reqHelp.error(req.getId(), ClearingError.UserVerifyDenial); + } + IdentificationFundsRequest payload = req.getRequestPayload(); + IValidator validator = identificationFundsVal.apply(payload); + Optional err = validator.tillFirstError(); + if (err.isPresent()) { + log.error("IdentificationFundsRequest.id={} validation error: {}", + req.getId(), + msgResolver.resolve(err.get())); + return reqHelp.error(req.getId(), err.get()); + } + Registry dmau = validator.getStored(Stored.PresentById); + AssetTrio asts = validator.getStored(ValidationStored.IdentificationFundsAssetTrio); + BigDecimal dmauBalance = safeBD(dmau.getBalance()); + BigDecimal reqBalance = payload.getBalance(); + BigDecimal am_tBalance = safeBD(asts.a__t().getBalance()); + + dmau.setBalance(dmauBalance.subtract(reqBalance)); + asts.a__t().setBalance(am_tBalance.add(reqBalance)); + Instant now = Instant.now(); + dmau.setUpdated(now); + asts.a__t().setUpdated(now); + registryImdg.update(dmau); + registryImdg.update(asts.a__t()); + assets.process(asts.a__b(), asts.a__t(), asts.a__f(), BigDecimal.ZERO); + return reqHelp.success(req.getId()); + } + public RequestInfoUpdate changeRefundDate(BaseRequest req) { RegistryChangeRefundDateRequest requestPayload = req.getRequestPayload(); IValidator validator = refundDateVal.apply(requestPayload); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/IdentificationFundsValidationRule.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/IdentificationFundsValidationRule.java new file mode 100644 index 000000000..31f29fafe --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/IdentificationFundsValidationRule.java @@ -0,0 +1,141 @@ +package ru.spcex.clearing.service.validation; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.registry.Registry; +import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; +import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.IdentificationFundsRequest; +import ru.spcex.clearing.service.AnltSearcher; +import ru.spcex.clearing.service.AssetTrio; +import ru.spcex.clearing.service.registry.AssetTBFProcessing; +import ru.spcex.platform.enumeration.AccountType; +import ru.spcex.platform.enumeration.RegistryTradingParams; +import ru.spcex.platform.enumeration.ServiceStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.imdg.validation.Stored; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.math.BigDecimal; +import java.util.Optional; + +import static ru.spcex.clearing.service.registry.RegistryManager.equalsByCode; +import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD; + +public enum IdentificationFundsValidationRule implements IValidationRule> { + Fields() { + @Override + public Optional validate(ImdgValidationContext context) { + IdentificationFundsRequest validatedObject = context.getValidatedObject(); + if (validatedObject.getId() == null) { + return of(ClearingError.WrongField, "id"); + } + if (validatedObject.getTradingClearingRegistryId() == null) { + return of(ClearingError.WrongField, "tradingClearingRegistryId"); + } + if (validatedObject.getBalance() == null || validatedObject.getBalance().compareTo(BigDecimal.ZERO) <= 0) { + return of(ClearingError.WrongField, "balance"); + } + return empty(); + } + }, + RegistryCodeCheck() { + @Override + public Optional validate(ImdgValidationContext context) { + Registry rgs = context.getStoredObject(Stored.PresentById); + if (!equalsByCode(RegistryTradingParams.DMAU, rgs)) { + return of(ClearingError.RgsWrongCode, "%s.id=%d".formatted( + rgs.getRegistryCode(), + rgs.getId())); + } + return empty(); + } + }, + BalanceCheck() { + @Override + public Optional validate(ImdgValidationContext context) { + IdentificationFundsRequest validatedObject = context.getValidatedObject(); + Registry rgs = context.getStoredObject(Stored.PresentById); + if (safeBD(rgs.getBalance()).compareTo(BigDecimal.ZERO) <= 0) { + return of(ClearingError.BalanceInsufficient); + } + if (safeBD(rgs.getBalance()) + .subtract(safeBD(validatedObject.getBalance())) + .compareTo(BigDecimal.ZERO) < 0) { + return of(ClearingError.BalanceInsufficient); + } + return empty(); + } + }, + TcrCheck() { + @Override + public Optional validate(ImdgValidationContext context) { + IdentificationFundsRequest validatedObject = context.getValidatedObject(); + Registry rgs = context.getStoredObject(Stored.PresentById); + if (rgs == null) { + return of(ClearingError.GeneralError); + } + + Imdg tcrImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class); + TradingClearingRegistry tcr = tcrImdg.getSingleObjectByID(validatedObject.getTradingClearingRegistryId()); + if (tcr == null) { + return of(ClearingError.TCRegistryNotFound, validatedObject.getTradingClearingRegistryId()); + } + if (!ServiceStatus.Active.equalsByKey(tcr.getStatus())) { + return of(ClearingError.TradingClearingRegistryNotActive, tcr.getCode()); + } + + if (tcr.getMoneyAccountId() == null) { + return of(ClearingError.AccountNotFoundB, "null"); //mb other error + } + + Imdg accImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class); + Account acc = accImdg.getSingleObjectByID(tcr.getMoneyAccountId()); + if (acc == null) { + return of(ClearingError.AccountNotFoundB, tcr.getMoneyAccountId()); + } + if (!AccountType.Info.equalsByKey(acc.getAccountType())) { + return of(ClearingError.AccountWrongType, acc.getAccountType()); + } + + Imdg cmpImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); + Company company = cmpImdg.getSingleObjectByID(tcr.getCompanyId()); + if (company == null) { + return of(ClearingError.CompanyNotFoundB, tcr.getCompanyId()); + } + + AnltSearcher.AnltSearch res = new AnltSearcher.AnltSearch(acc, company, tcr); + context.storeObject(ValidationStored.IdentificationFundsTcrSearch, res); + return empty(); + } + }, + AssetsCheck() { + @Override + public Optional validate(ImdgValidationContext context) { + AnltSearcher.AnltSearch tcrSearch = context.getStoredObject(ValidationStored.IdentificationFundsTcrSearch); + if (tcrSearch == null) { + return of(ClearingError.RecordNotFound, "AM*T"); + } + Imdg rgsImdg = context.obtainMap(IMDGDistributedNames.Map_Registry, Registry.class); + AssetTBFProcessing assets = new AssetTBFProcessing(rgsImdg); + Optional assetTrio = assets.searchMoneyByAccAndCompany(tcrSearch.getCompany().getId(), tcrSearch.getAccount().getId()); + if (assetTrio.isEmpty()) { + return of(ClearingError.RecordNotFound, "AM*T"); + } + context.storeObject(ValidationStored.IdentificationFundsAssetTrio, assetTrio.get()); + return Optional.empty(); + } + } + ; + private final static Logger log = LoggerFactory.getLogger(IdentificationFundsValidationRule.class); + + @Override + public String ruleName() { + return "IdentificationFundsValidationRule." + name(); + } +} \ No newline at end of file diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java index 7892f4d0c..471106a79 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/ValidationStored.java @@ -20,6 +20,8 @@ public enum ValidationStored { ReturnDepositDmx, + IdentificationFundsTcrSearch, IdentificationFundsAssetTrio, + RefundDateChangeRegistries, CompanyByTradingCode,