diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/RequestHelperConfiguration.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/RequestHelperConfiguration.java new file mode 100644 index 000000000..8cc622cde --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/RequestHelperConfiguration.java @@ -0,0 +1,15 @@ +package ru.spcex.clearing.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.util.services.RequestHelper; +import ru.spcex.platform.utils.enumeration.IMessageResolver; + +@Configuration +public class RequestHelperConfiguration { + @Bean + public RequestHelper reqHelper(IMessageResolver msgRslv) { + return new RequestHelper(msgRslv, ClearingError.GeneralError); + } +} 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 15c4245f1..50f136111 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 @@ -25,6 +25,7 @@ import ru.spcex.clearing.error.ClearingError; import ru.spcex.clearing.imdg.IMDGDistributedNames; 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.service.validation.*; @@ -343,6 +344,22 @@ public class ValidationConfig { }; } + @Bean("statusExtractValidator") + public Function statusExtractValidator() { + return statusExtractRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(statusExtractRequest); + context.addImdg(IMDGDistributedNames.Map_Registry, imdgRegistry); + context.setLogPrefix(LogPrefixId.INSTANCE); + return new ValidatorImpl<>(context, + StatusExtractValidationRule.Fields, + new PresentById(IMDGDistributedNames.Map_Registry, ClearingError.RecordNotFound, true), + StatusExtractValidationRule.ContractCheck, + StatusExtractValidationRule.RegistryStatusValid + ); + }; + } + @Bean("splitDepositValidator") public Function splitDepositValidator() { return refundDateRequest -> { 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 d471f9e4d..6460275a0 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 @@ -6,10 +6,12 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; 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.BaseRequest; 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.service.RequestInfoUpdate; @@ -17,6 +19,7 @@ import ru.spcex.clearing.platform.messaging.service.Status; import ru.spcex.clearing.service.validation.ValidationStored; import ru.spcex.clearing.session.stage.util.RegistryUtil; import ru.spcex.clearing.util.security.UserRoleVerification; +import ru.spcex.clearing.util.services.RequestHelper; import ru.spcex.platform.enumeration.*; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; @@ -46,24 +49,29 @@ public class RegistryService { private final Imdg registryImdg; private final Function returnDepositVal; private final Function refundDateVal; + private final Function statusExtractVal; private final Function splitDepositActionVal; private final IMessageResolver msgResolver; + private final RequestHelper reqHelp; private final UserRoleVerification rights; public RegistryService(ImdgProvider imdgProvider, @Qualifier("returnDepositValidator") Function returnDepositVal, @Qualifier("refundDateValidator") Function refundDateVal, @Qualifier("splitDepositValidator") Function splitDepositActionVal, + @Qualifier("statusExtractValidator") Function statusExtractVal, IMessageResolver msgResolver, - UserRoleVerification rights) { + RequestHelper reqHelp, UserRoleVerification rights) { 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.splitDepositActionVal = splitDepositActionVal; + this.statusExtractVal = statusExtractVal; this.msgResolver = msgResolver; + this.reqHelp = reqHelp; this.rights = rights; rights.setRoleForVerification(UserRole.Admin); } @@ -156,6 +164,26 @@ public class RegistryService { return new RequestInfoUpdate(req.getId(), Status.Success, null); } + public RequestInfoUpdate changeStatusExtract(BaseRequest req) { + if (!rights.userHasRole(req.getUserId(), UserRole.Admin)) { + return reqHelp.error(req.getId(), ClearingError.UserVerifyDenial); + } + RegistryChangeStatusExtractRequest payload = req.getRequestPayload(); + IValidator validator = statusExtractVal.apply(payload); + Optional err = validator.tillFirstError(); + if (err.isPresent()) { + log.error("RegistryChangeStatusExtractRequest.id={} validation error: {}", + req.getId(), + msgResolver.resolve(err.get())); + return reqHelp.error(req.getId(), err.get()); + } + Registry registry = validator.getStored(Stored.PresentById); + registry.setRegistryStatus(payload.getRegistryStatus()); + log.debug("changing registry.id={} status to {}", registry.getId(), payload.getRegistryStatus()); + registryImdg.update(registry); + 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/registry/AssetTBFProcessing.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/registry/AssetTBFProcessing.java index 707c1cb8f..28e0fcffa 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/registry/AssetTBFProcessing.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/registry/AssetTBFProcessing.java @@ -155,6 +155,18 @@ public class AssetTBFProcessing { return new AssetTrio(asf, asb, ast); } + public Optional searchByTcrCompanyAccount(Registry rgs, + RegistryTradingParams params) { + ImdgPredicateBuilder pb = rgsImdg.predicateBuilder(); + ImdgPredicate prdct = pb.and( + pb.sql(RegistryCodeSqlBuilder.getInstance(params).build()), + pb.equals("tradingClearingRegistryId", rgs.getTradingClearingRegistryId()), + pb.equals("companyId", rgs.getCompanyId()), + pb.equals("accountId", rgs.getAccountId()) + ); + return Optional.ofNullable(rgsImdg.getFirstObjectByPredicate(prdct)); + } + public Optional searchMoneyByAccAndCompany(Long companyId, Long accountId) { ImdgPredicateBuilder pb = rgsImdg.predicateBuilder(); Function prdct = rgsCode -> pb.and( diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/StatusExtractValidationRule.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/StatusExtractValidationRule.java new file mode 100644 index 000000000..c97a56646 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/validation/StatusExtractValidationRule.java @@ -0,0 +1,72 @@ +package ru.spcex.clearing.service.validation; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.clearing.classes.statics.data.registry.Registry; +import ru.spcex.clearing.error.ClearingError; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeStatusExtractRequest; +import ru.spcex.platform.enumeration.RegistryStatus; +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.enumeration.IEnumKey; +import ru.spcex.platform.utils.text.TextUtil; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Objects; +import java.util.Optional; + +public enum StatusExtractValidationRule implements IValidationRule> { + Fields() { + @Override + public Optional validate(ImdgValidationContext context) { + RegistryChangeStatusExtractRequest validatedObject = context.getValidatedObject(); + if (validatedObject.getId() == null) { + return of(ClearingError.WrongField, "id"); + } + if (TextUtil.isEmpty(validatedObject.getRegistryStatus())) { + return of(ClearingError.WrongField, "registryStatus"); + } + return empty(); + } + }, + ContractCheck() { + @Override + public Optional validate(ImdgValidationContext context) { + RegistryChangeStatusExtractRequest validatedObject = context.getValidatedObject(); + if (TextUtil.isEmpty(validatedObject.getContract())) { + return empty(); + } + Registry rgs = context.getStoredObject(Stored.PresentById); + if (rgs == null) { + log.error("PresentById check passed, yet not Stored.PresentById is present"); + return of(ClearingError.WrongField, "id"); + } + if (!Objects.equals(rgs.getContract(), validatedObject.getContract())) { + return of(ClearingError.WrongField, "contract"); + } + return empty(); + } + }, + RegistryStatusValid() { + @Override + public Optional validate(ImdgValidationContext context) { + RegistryChangeStatusExtractRequest validatedObject = context.getValidatedObject(); + if (TextUtil.isEmpty(validatedObject.getRegistryStatus())) { + return empty(); + } + RegistryStatus rgsStatus = IEnumKey.getEnumByKey(RegistryStatus.class, validatedObject.getRegistryStatus()); + if (rgsStatus == null) { + return of(ClearingError.WrongField, "registryStatus"); + } + return empty(); + } + } + ; + private final static Logger log = LoggerFactory.getLogger(StatusExtractValidationRule.class); + + @Override + public String ruleName() { + return "StatusExtractValidationRule." + name(); + } +} \ No newline at end of file diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/InspectionObligations.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/InspectionObligations.java index 777175ca8..0e6cbc444 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/InspectionObligations.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/InspectionObligations.java @@ -18,6 +18,7 @@ import ru.spcex.clearing.session.stage.ISessionStage; import ru.spcex.clearing.session.stage.StageResult; import ru.spcex.clearing.session.stage.Task; import ru.spcex.clearing.session.stage.task.InspectionPoolPayload; +import ru.spcex.clearing.session.stage.util.RegistryUtil; import ru.spcex.platform.enumeration.*; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; @@ -145,38 +146,29 @@ public class InspectionObligations implements ISessionStage { Instant now = Instant.now(); //по каждому регистру OM*T, TM*T, OS*T, TS*T из одной группы for (Registry registry : group) {//TODO CLRNWORM проверка на пустой blockedRegistry - Registry blockedRegistry = null; - if (IEnumKey.getEnumByKey(RegistryInstrumentType.class, registry.getRegistryInstrumentType()) == RegistryInstrumentType.M) { - String moneyBAssetSql = searchMoneyBAssetsSql(registry); - log.debug("search money asset by registry.id={} sql {}", registry.getId(), moneyBAssetSql); - blockedRegistry = registryImdg.getFirstObjectBySQL(moneyBAssetSql); - if (IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation()) == RegistryDesignation.O) { - blockedRegistry.setBalance(blockedRegistry.getBalance().add(registry.getBalance())); - } else if (IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation()) == RegistryDesignation.T) { - blockedRegistry.setBalance(blockedRegistry.getBalance().subtract(registry.getBalance())); - } - blockedRegistry.setSessionId(sessionId); - blockedRegistry.setUpdated(now); - registryImdg.update(blockedRegistry); - } else if (section != null && section == Section.FOND && - IEnumKey.getEnumByKey(RegistryInstrumentType.class, registry.getRegistryInstrumentType()) == RegistryInstrumentType.S) { - String securityBAssetSql = searchSecurityBAssetsSql(registry); - log.debug("search security asset by registry.id={} sql {}", registry.getId(), securityBAssetSql); - blockedRegistry = registryImdg.getFirstObjectBySQL(securityBAssetSql); - if (IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation()) == RegistryDesignation.O) { - blockedRegistry.setBalance(blockedRegistry.getBalance().add(registry.getBalance())); - } else if (IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation()) == RegistryDesignation.T) { - blockedRegistry.setBalance(blockedRegistry.getBalance().subtract(registry.getBalance())); - } - blockedRegistry.setSessionId(sessionId); - blockedRegistry.setUpdated(now); - registryImdg.update(blockedRegistry); - } - if (blockedRegistry != null) { - Optional registryUnitF = registryManager.findRegByUnit(registry.getCompanyId(), registry.getAccountId(), registry.getContract(), blockedRegistry, RegistryUnit.F); - Optional registryUnitT = registryManager.findRegByUnit(registry.getCompanyId(), registry.getAccountId(), registry.getContract(), blockedRegistry, RegistryUnit.T); - if (registryUnitF.isPresent() && registryUnitT.isPresent()) { - assets.process(blockedRegistry, registryUnitT.get(), registryUnitF.get(), BigDecimal.ZERO); + { + RegistryInstrumentType mOrS = IEnumKey.getEnumByKey(RegistryInstrumentType.class, registry.getRegistryInstrumentType()); + if (mOrS == null) continue; + Optional a__t = assets.searchByTcrCompanyAccount(registry, A__T.type(mOrS)); + Optional a__b = a__t.map(a__tFound -> assets + .searchByTcrCompanyAccount(a__tFound, A__B.type(mOrS)) + .orElse(copyB(a__tFound))); + Optional a__f = a__t.map(a__tFound -> assets + .searchByTcrCompanyAccount(a__tFound, A__F.type(mOrS)) + .orElse(copyF(a__tFound))); + log.debug("registry {}.id={}: {}", registry.getRegistryCode(), registry.getId(), + a__t.map(r -> "A**T.id=%d/A**B.id=%d/A**F.id=%d" + .formatted(a__t.get().getId(), a__b.get().getId(), a__f.get().getId())) + .orElse("not found")); + if (a__t.isPresent()) { + BigDecimal amount = safeBD(registry.getBalance()); + if (IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation()) == RegistryDesignation.O) { + amount = amount.negate(); + } else if (IEnumKey.getEnumByKey(RegistryDesignation.class, registry.getRegistryDesignation()) == RegistryDesignation.T) { + amount = amount; + } + a__b.get().setSessionId(sessionId); + assets.process(a__b.get(), a__t.get(), a__f.get(), amount); } } } @@ -253,28 +245,24 @@ foreach( at: rgsAT) obligation.getCompanyId()); } - private String searchMoneyBAssetsSql(Registry obligation) { - return String.format("%s and " + - "tradingClearingRegistryId = '%s' and " + - "companyId = '%s' and " + - "accountId = %s", - RegistryCodeSqlBuilder.getInstance(AM_B).build(), - obligation.getTradingClearingRegistryId(), - obligation.getCompanyId(), - obligation.getAccountId()); + private Registry copyF(Registry rgs) { + Registry rgsF = rgs.clone(); + RegistryManager.zeroState(rgsF); + rgsF.setRegistryUnit(RegistryUnit.F.getKey()); + rgsF.setRegistryCode(RegistryUtil.clearingCode(rgsF)); + registryImdg.insert(rgsF); + log.debug("created {}.id={} by {}.id={}", rgsF.getRegistryCode(), rgsF.getId(), rgs.getRegistryCode(), rgs.getId()); + return rgsF; } - private String searchSecurityBAssetsSql(Registry registry) { - return String.format("%s and " + - "tradingClearingRegistryId = '%s' and " + - "companyId = '%s' and " + - "securitySymbol = '%s' and " + - "accountId = %s", - RegistryCodeSqlBuilder.getInstance(AS_B).build(), - registry.getTradingClearingRegistryId(), - registry.getCompanyId(), - registry.getSecuritySymbol(), - registry.getAccountId()); + private Registry copyB(Registry rgs) { + Registry rgsB = rgs.clone(); + RegistryManager.zeroState(rgsB); + rgsB.setRegistryUnit(RegistryUnit.B.getKey()); + rgsB.setRegistryCode(RegistryUtil.clearingCode(rgsB)); + registryImdg.insert(rgsB); + log.debug("created {}.id={} by {}.id={}", rgsB.getRegistryCode(), rgsB.getId(), rgs.getRegistryCode(), rgs.getId()); + return rgsB; } private void defineStatusAndUpdateRegistry(List checkResults, List registries) { diff --git a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/RequestHelper.java b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/RequestHelper.java index 04decd8a7..c14458175 100644 --- a/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/RequestHelper.java +++ b/clearing-parent/clearing-validation/src/main/java/ru/spcex/clearing/util/services/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.IErrorEnumId; import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.error.ClearingBaseException; @@ -102,4 +103,17 @@ public class RequestHelper { this.log = log; return this; } + + public RequestInfoUpdate success(Long id) { + return new RequestInfoUpdate(id, Status.Success, null); + } + + public RequestInfoUpdate error(Long id, EnumMessage err) { + return new RequestInfoUpdate(id, Status.Error, messageResolver.resolve(err)); + } + + public RequestInfoUpdate error(Long id, IEnumId sbj, Object... args) { + EnumMessage error = new EnumMessage(sbj, args); + return new RequestInfoUpdate(id, Status.Error, messageResolver.resolve(error)); + } } diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java index 4d3d5919f..b427a4aa2 100644 --- a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/RegistryTradingParams.java @@ -88,6 +88,7 @@ public record RegistryTradingParams(RegistryDesignation registryDesignation, public final static RegistryTradingParams AM_T; public final static RegistryTradingParams AM_B; public final static RegistryTradingParams A__B; + public final static RegistryTradingParams A__F; public final static RegistryTradingParams A__T; public final static RegistryTradingParams AS_T; public final static RegistryTradingParams DS_I; @@ -153,6 +154,10 @@ public record RegistryTradingParams(RegistryDesignation registryDesignation, null, null, RegistryUnit.B); + A__F = new RegistryTradingParams(RegistryDesignation.A, + null, + null, + RegistryUnit.F); A__T = new RegistryTradingParams(RegistryDesignation.A, null, null, diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/RegistryChangeStatusExtractRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/RegistryChangeStatusExtractRequest.java index 260d4f430..8d45d9ced 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/RegistryChangeStatusExtractRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/registry/RegistryChangeStatusExtractRequest.java @@ -1,10 +1,11 @@ package ru.spcex.clearing.platform.messaging.domain.cud.registry; import com.fasterxml.jackson.annotation.JsonProperty; +import ru.spcex.platform.classes.base.interfaces.WithId; import java.math.BigDecimal; -public class RegistryChangeStatusExtractRequest { +public class RegistryChangeStatusExtractRequest implements WithId { @JsonProperty public Long id; @JsonProperty