This commit is contained in:
AKurakin 2023-08-29 16:37:34 +03:00
parent 6237f534f2
commit 5cdf12a323
4 changed files with 89 additions and 76 deletions

View file

@ -64,6 +64,7 @@ public class ValidationConfig {
Imdg<Session> imdgSession; Imdg<Session> imdgSession;
Imdg<SectionDictionary> imdgSectionDictionary; Imdg<SectionDictionary> imdgSectionDictionary;
Imdg<Statement> imdgStatement; Imdg<Statement> imdgStatement;
Imdg<InOutDirectionDictionary> imdgInOutDirection;
ImdgProvider imdgProvider; ImdgProvider imdgProvider;
public ValidationConfig(ImdgProvider imdgProvider) { public ValidationConfig(ImdgProvider imdgProvider) {
@ -82,6 +83,7 @@ public class ValidationConfig {
this.equitySecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_EquitySecurity, EquitySecurity.class); this.equitySecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_EquitySecurity, EquitySecurity.class);
this.imdgStatement = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class); this.imdgStatement = imdgProvider.getImdg(IMDGDistributedNames.Map_Statement, Statement.class);
this.imdgDepoAccount = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class); this.imdgDepoAccount = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class);
this.imdgInOutDirection = imdgProvider.getImdg(IMDGDistributedNames.Map_InOutDirectionDictionary, InOutDirectionDictionary.class);
this.imdgProvider = imdgProvider; this.imdgProvider = imdgProvider;
} }
@ -346,7 +348,8 @@ public class ValidationConfig {
ImdgValidationContext<RegistrySplitDepositActionRequest> context = new ImdgValidationContext<>(); ImdgValidationContext<RegistrySplitDepositActionRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(refundDateRequest); context.setValidatedObject(refundDateRequest);
context.addImdg(IMDGDistributedNames.Map_Registry, imdgRegistry); context.addImdg(IMDGDistributedNames.Map_Registry, imdgRegistry);
context.setLogPrefix(r -> "contract=%d refundDate=%s".formatted(r.getContract(), r.getRefundDate())); context.addImdg(IMDGDistributedNames.Map_InOutDirectionDictionary, imdgInOutDirection);
context.setLogPrefix(r -> "contract=%s refundDate=%s".formatted(r.getContract(), r.getRefundDate()));
return new ValidatorImpl<>(context, return new ValidatorImpl<>(context,
FieldRequiredRule.instance("contract", RegistrySplitDepositActionRequest::getContract, ClearingError.RequiredFieldEmpty), FieldRequiredRule.instance("contract", RegistrySplitDepositActionRequest::getContract, ClearingError.RequiredFieldEmpty),
FieldRequiredRule.instance("refundDate", RegistrySplitDepositActionRequest::getRefundDate, ClearingError.RequiredFieldEmpty), FieldRequiredRule.instance("refundDate", RegistrySplitDepositActionRequest::getRefundDate, ClearingError.RequiredFieldEmpty),

View file

@ -6,7 +6,6 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.registry.Registry; import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.error.ClearingError;
import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest; 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.clearing.CreateRegistryRequest;
@ -66,6 +65,7 @@ public class RegistryService {
this.splitDepositActionVal = splitDepositActionVal; this.splitDepositActionVal = splitDepositActionVal;
this.msgResolver = msgResolver; this.msgResolver = msgResolver;
this.rights = rights; this.rights = rights;
rights.setRoleForVerification(UserRole.Admin);
} }
public void createRegistry(CreateRegistryRequest createRegistryRequest) { public void createRegistry(CreateRegistryRequest createRegistryRequest) {
@ -213,24 +213,15 @@ public class RegistryService {
RegistryTradingParams registryInfo = null; RegistryTradingParams registryInfo = null;
//todo спросить про дубль C и T //todo спросить про дубль C и T
switch (registryType) { switch (registryType) {
case Owner_A -> case Owner_A -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.M, RegistryCapacity.A, RegistryUnit.T);
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.M, RegistryCapacity.A, RegistryUnit.T); case Client_B -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.M, RegistryCapacity.B, RegistryUnit.T);
case Client_B -> case Trustee_C, DepoOfShares_T -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.A, RegistryUnit.T);
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.M, RegistryCapacity.B, RegistryUnit.T); case TrusteeManager_D -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.A, RegistryUnit.A);
case Trustee_C, DepoOfShares_T -> case Issuer_E -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.E, RegistryUnit.R);
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.A, RegistryUnit.T); case ToThePlacementOrRedeem_Z -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.Z, RegistryUnit.R);
case TrusteeManager_D -> case DepoBond_H -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.A, RegistryUnit.R);
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.A, RegistryUnit.A); case DepoOfTrustedBond_N -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.C, RegistryUnit.R);
case Issuer_E -> case DepoOfTrustedShares_S -> registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.C, RegistryUnit.T);
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.E, RegistryUnit.R);
case ToThePlacementOrRedeem_Z ->
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.Z, RegistryUnit.R);
case DepoBond_H ->
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.A, RegistryUnit.R);
case DepoOfTrustedBond_N ->
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.C, RegistryUnit.R);
case DepoOfTrustedShares_S ->
registryInfo = new RegistryTradingParams(RegistryDesignation.A, RegistryInstrumentType.S, RegistryCapacity.C, RegistryUnit.T);
} }
return registryInfo; return registryInfo;
} }
@ -295,7 +286,7 @@ public class RegistryService {
if (roleCheck != null) { if (roleCheck != null) {
return roleCheck; return roleCheck;
} }
Registry baseRegistry; Collection<Registry> baseRegistrys;
{ {
IValidator validator = splitDepositActionVal.apply(requestPayload); IValidator validator = splitDepositActionVal.apply(requestPayload);
Optional<EnumMessage> err = validator.tillFirstError(); Optional<EnumMessage> err = validator.tillFirstError();
@ -305,7 +296,7 @@ public class RegistryService {
msgResolver.resolve(err.get())); msgResolver.resolve(err.get()));
return new RequestInfoUpdate(req.getId(), Status.Error, msgResolver.resolve(err.get())); return new RequestInfoUpdate(req.getId(), Status.Error, msgResolver.resolve(err.get()));
} }
baseRegistry = validator.getStored(ValidationStored.RegistryByContract); baseRegistrys = validator.getStored(ValidationStored.RegistrysByContract);
} }
ImdgTransaction txCtx = imdgProvider.newTransaction(); ImdgTransaction txCtx = imdgProvider.newTransaction();
@ -319,43 +310,56 @@ public class RegistryService {
direction = InOutDirection.out; direction = InOutDirection.out;
log.debug("Direction not set. Use default: {}", direction); log.debug("Direction not set. Use default: {}", direction);
} }
// 1. Первая группа log.debug("Process {} for {} registry", direction, baseRegistrys.size());
Registry firstRegistry = baseRegistry.clone(); Long groupId = null;
firstRegistry.setId(null); for (Registry baseRegistry : baseRegistrys) {
firstRegistry.setCreated(now); log.trace("Registry[{}], groupId={}, ClearingCode={}", baseRegistry.getId(), baseRegistry.getGroupId(), baseRegistry.getClearingCode());
firstRegistry.setUpdated(null); if (groupId == null)
if (InOutDirection.out == direction) { groupId = baseRegistry.getGroupId();
firstRegistry.setBalance(baseRegistry.getBalance().subtract(requestPayload.getOutboundAmount())); else if (!groupId.equals(baseRegistry.getGroupId())) {
} else if (InOutDirection.in == direction) { log.warn("Group id different: groupId={}; registry[{}].groupId={}", groupId, baseRegistry.getId(), baseRegistry.getGroupId());
firstRegistry.setBalance(baseRegistry.getBalance().add(requestPayload.getOutboundAmount())); }
} else { // 1. Первая группа
log.warn("Direction not set, do not change Balance"); Registry firstRegistry = baseRegistry.clone();
} firstRegistry.setId(null);
firstRegistry.setContract(baseRegistry.getContract() + "~1"); firstRegistry.setCreated(now);
registryTMap.insert(firstRegistry); firstRegistry.setUpdated(null);
if (InOutDirection.out == direction) {
firstRegistry.setBalance(baseRegistry.getBalance().subtract(requestPayload.getOutboundAmount()));
} else if (InOutDirection.in == direction) {
firstRegistry.setBalance(baseRegistry.getBalance().add(requestPayload.getOutboundAmount()));
} else {
log.warn("Direction not set, do not change Balance");
}
firstRegistry.setContract(baseRegistry.getContract() + "~1");
registryTMap.insert(firstRegistry);
// 2. Вторая группа // 2. Вторая группа
Registry secondRegistry = null; Registry secondRegistry = null;
if (InOutDirection.out == direction) { if (InOutDirection.out == direction) {
secondRegistry.setId(null); secondRegistry = baseRegistry.clone();
secondRegistry.setCreated(now); secondRegistry.setId(null);
secondRegistry.setUpdated(null); secondRegistry.setCreated(now);
secondRegistry.setBalance(requestPayload.getOutboundAmount()); secondRegistry.setUpdated(null);
secondRegistry.setContract(baseRegistry.getContract() + "~2"); secondRegistry.setBalance(requestPayload.getOutboundAmount());
registryTMap.insert(secondRegistry); secondRegistry.setContract(baseRegistry.getContract() + "~2");
} secondRegistry.setRefundDate(requestPayload.getRefundDate());
secondRegistry.setSettlementDate(requestPayload.getRefundDate());
registryTMap.insert(secondRegistry);
}
// 3. Текущим обязательствам установить статус SPLT // 3. Текущим обязательствам установить статус SPLT
baseRegistry.setRegistryStatus(RegistryStatus.SPLT.getKey()); baseRegistry.setRegistryStatus(RegistryStatus.SPLT.getKey());
baseRegistry.setUpdated(Instant.now()); baseRegistry.setUpdated(Instant.now());
registryTMap.update(baseRegistry); registryTMap.update(baseRegistry);
log.debug("Registry[{}] groupId={} split to: id1={} {}, id2={} {}",
baseRegistry.getId(), baseRegistry.getGroupId(),
firstRegistry == null ? null : firstRegistry.getId(), firstRegistry == null ? null : firstRegistry.getContract(),
secondRegistry == null ? null : secondRegistry.getId(), secondRegistry == null ? null : secondRegistry.getContract()
);
}
txOk = true; txOk = true;
log.debug("Registry[{}] groupId={} split to: id1={} {}, id2={} {}",
baseRegistry.getId(), baseRegistry.getGroupId(),
firstRegistry == null ? null : firstRegistry.getId(), firstRegistry == null ? null : firstRegistry.getContract(),
secondRegistry == null ? null : secondRegistry.getId(), secondRegistry == null ? null : secondRegistry.getContract()
);
} finally { } finally {
if (txOk) { if (txOk) {
txCtx.commitTransaction(); txCtx.commitTransaction();

View file

@ -6,18 +6,20 @@ import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.error.ClearingError; import ru.spcex.clearing.error.ClearingError;
import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest; import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest;
import ru.spcex.platform.enumeration.RegistryDesignation;
import ru.spcex.platform.enumeration.RegistryStatus; import ru.spcex.platform.enumeration.RegistryStatus;
import ru.spcex.platform.enumeration.RegistryTradingParams; import ru.spcex.platform.enumeration.RegistryUnit;
import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule; import ru.spcex.platform.utils.validation.IValidationRule;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
public enum SplitDepositRequestValidationRule implements IValidationRule<ImdgValidationContext<RegistrySplitDepositActionRequest>> { public enum SplitDepositRequestValidationRule implements IValidationRule<ImdgValidationContext<RegistrySplitDepositActionRequest>> {
CrossvalidateByRegistry() { CrossvalidateByRegistry() {
@ -30,32 +32,36 @@ public enum SplitDepositRequestValidationRule implements IValidationRule<ImdgVal
// Поиск регистра // Поиск регистра
ImdgPredicateBuilder prdBldr = registryImdg.predicateBuilder(); ImdgPredicateBuilder prdBldr = registryImdg.predicateBuilder();
ImdgPredicate query = prdBldr.and( ImdgPredicate query = prdBldr.and(
RegistryCodeSqlBuilder.getInstance(RegistryTradingParams.OM_T).buildPredicate(prdBldr), prdBldr.or(prdBldr.equals("registryStatus", RegistryStatus.PROC.getKey()), prdBldr.equals("registryStatus", RegistryStatus.MNG.getKey())),
prdBldr.equals("contract", request.getContract())); prdBldr.or(prdBldr.equals("registryDesignation", RegistryDesignation.O.getKey()), prdBldr.equals("registryDesignation", RegistryDesignation.T.getKey())),
Registry registry = registryImdg.getSingleObjectByPredicate(query); prdBldr.equals("registryUnit", RegistryUnit.T.getKey()),
if (registry == null) { prdBldr.equals("contract", request.getContract())
log.debug("Registry not found by query \"{}\"", query); );
Collection<Registry> registrys = registryImdg.getCollectionObjectsByPredicate(query);
registrys = registrys.stream()
.filter(r->r.getValueDate()!=null && r.getSettlementDate()!=null && r.getValueDate().isBefore(r.getSettlementDate()))
.collect(Collectors.toList());
Registry registryO = registrys.stream()
.filter(r -> RegistryDesignation.O.equalsByKey(r.getRegistryDesignation()))
.findAny().orElse(null);
log.trace("Found registry {}. Crossvalidate for {}", registrys, registryO);
if (registryO == null) {
log.debug("Registry not found by query \"{}\" and valueDate < settlementDate", query);
return of(ClearingError.TCRegistryNotFound, request.getContract()); return of(ClearingError.TCRegistryNotFound, request.getContract());
} else {
log.trace("Registry.id={} found by query \"{}\"", registry.getId(), query);
} }
context.storeObject(ValidationStored.RegistryByContract, registry); context.storeObject(ValidationStored.RegistrysByContract, registrys);
// кросс-валидация // кросс-валидация
if (!RegistryStatus.PROC.equalsByKey(registry.getRegistryStatus())) { BigDecimal regBalance = registryO.getBalance();
log.debug("Registry[{}].RegistryStatus={} - error", if (regBalance == null || regBalance.compareTo(request.getOutboundAmount()) <= 0) {
registry.getId(), registry.getRegistryStatus());
return Optional.of(new EnumMessage(ClearingError.TCRegistryNotFound, request.getContract()));
}
BigDecimal regBalance = registry.getBalance();
if (regBalance == null || regBalance.compareTo(request.getOutboundAmount()) < 0) {
log.trace("Registry[{}] balance={} < OutboundAmount {}", log.trace("Registry[{}] balance={} < OutboundAmount {}",
registry.getId(), regBalance, request.getOutboundAmount()); registryO.getId(), regBalance, request.getOutboundAmount());
return Optional.of(new EnumMessage(ClearingError.BalanceInsufficient, request.getContract())); return Optional.of(new EnumMessage(ClearingError.BalanceInsufficient, request.getContract()));
} }
if (!registry.getRefundDate().isAfter(request.getRefundDate())) { if (registryO.getRefundDate().isBefore(request.getRefundDate())) { // дате в регистре >= refundDate
log.trace("Registry[{}].RefundDate={} but request RefundDate={}", log.trace("Registry[{}].RefundDate={} but request RefundDate={}",
registry.getId(), registry.getRefundDate(), request.getRefundDate()); registryO.getId(), registryO.getRefundDate(), request.getRefundDate());
return Optional.of(new EnumMessage(ClearingError.WrongFieldValue, "RefundDate")); return Optional.of(new EnumMessage(ClearingError.WrongFieldValue, "RefundDate"));
} }

View file

@ -28,5 +28,5 @@ public enum ValidationStored {
SecurityBySecurityCode, SecurityBySecurityCode,
RegistryByContract RegistrysByContract
} }