1. planBalance проставляется для 5 шага возврата депозитов

2. проверки, создание(обновление) dm_x -> dm_x/dm_t
This commit is contained in:
ialbert 2023-09-25 17:43:43 +03:00
parent 155b899e5d
commit e40a8dc724
9 changed files with 191 additions and 83 deletions

View file

@ -329,9 +329,10 @@ public class ValidationConfig {
context.setLogPrefix(LogPrefixId.INSTANCE);
return new ValidatorImpl<>(context,
new PresentById(IMDGDistributedNames.Map_Registry, ClearingError.RecordNotFound, true),
ReturnDepositValidationRule.RegistryCodeCheck,
ReturnDepositValidationRule.RgsWronCodeCheck,
ReturnDepositValidationRule.CategoryCheck,
ReturnDepositValidationRule.BalanceCheck,
ReturnDepositValidationRule.DmxCheck
ReturnDepositValidationRule.Dm_Check
);
};
}

View file

@ -23,6 +23,7 @@ public enum ClearingError implements IErrorEnumId {
SuchRecordAlreadyExists(5405L),
TradingClearingRegistryNotFound(5418L),
TradingClearingRegistryNotActive(5419L),
CategoryNotFound(5420L),
ClearingUnavailableForCompany(5421L),
InsecurityObligation(5422L),
NewDealsNotFound(5423L),

View file

@ -166,28 +166,34 @@ public class RegistryService {
msgResolver.resolve(err.get()));
return new RequestInfoUpdate(req.getId(), Status.Error, msgResolver.resolve(err.get()));
}
Registry tm_t = validator.getStored(Stored.PresentById);
Registry dm_x = validator.getStored(ValidationStored.ReturnDepositDmx);
if (dm_x != null) {
dm_x.setSessionId(null);
dm_x.setSessionType(null);
dm_x.setBalance(requestPayload.getBalance());
dm_x.setUpdated(Instant.now());
registryImdg.update(dm_x);
log.debug("updated dm*x.id={} by RegistryReturnDepositRequest.id={}",
dm_x.getId(),
Registry _m_t = validator.getStored(Stored.PresentById);
Registry dm__ = validator.getStored(ValidationStored.ReturnDepositDm__);
if (dm__ != null) {
dm__.setSessionId(null);
dm__.setSessionType(null);
dm__.setBalance(requestPayload.getBalance());
dm__.setUpdated(Instant.now());
registryImdg.update(dm__);
log.debug("updated {}.id={} by RegistryReturnDepositRequest.id={}",
dm__.getRegistryCode(),
dm__.getId(),
req.getId());
} else {
dm_x = tm_t.clone();
dm_x.setRegistryDesignation(RegistryDesignation.D.getKey());
dm_x.setRegistryUnit(RegistryUnit.X.getKey());
dm_x.setRegistryCode(RegistryUtil.clearingCode(dm_x));
dm_x.setBalance(requestPayload.getBalance());
dm_x.setSessionId(null);
dm_x.setSessionType(null);
registryImdg.insert(dm_x);
log.debug("created dm*x.id={} by RegistryReturnDepositRequest.id={}",
dm_x.getId(),
dm__ = _m_t.clone();
dm__.setRegistryDesignation(RegistryDesignation.D.getKey());
if (RegistryDesignation.T.equalsByKey(_m_t.getRegistryDesignation())) {
dm__.setRegistryUnit(RegistryUnit.X.getKey());
} else {
dm__.setRegistryUnit(RegistryUnit.T.getKey());
}
dm__.setRegistryCode(RegistryUtil.clearingCode(dm__));
dm__.setBalance(requestPayload.getBalance());
dm__.setSessionId(null);
dm__.setSessionType(null);
registryImdg.insert(dm__);
log.debug("created {}.id={} by RegistryReturnDepositRequest.id={}",
dm__.getRegistryCode(),
dm__.getId(),
req.getId());
}
return new RequestInfoUpdate(req.getId(), Status.Success, null);

View file

@ -1,23 +1,68 @@
package ru.spcex.clearing.service.validation;
import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.error.ClearingError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryReturnDepositRequest;
import ru.spcex.clearing.service.registry.RegistryManager;
import ru.spcex.platform.enumeration.RegistryDesignation;
import ru.spcex.platform.enumeration.RegistryInstrumentType;
import ru.spcex.platform.enumeration.RegistryStatus;
import ru.spcex.platform.enumeration.RegistryUnit;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
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.text.TextUtil;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.math.BigDecimal;
import java.util.Optional;
import static ru.spcex.clearing.service.registry.RegistryManager.equalsByCode;
//1. Проверки
//1.1 Проверить, в запросе у регистра код:
// 1.1.1 Если регистр TM-T:
// Проверить, что у registry.companyId существует категория I, иначе ошибка: 5420 - "Доступ к клирингу на «%s» не найден для компании %s."/> Где %s = категории И
// Проверить, что найденного регистра DM*X: registry.status!=OK, иначе ошибка: 5425 - "Запрещена идентификация средства по рассчитанным обязательствам".
// Создать/добавить в баланс DM-X на базе TM-T
// 1.1.2 Если регистр OM-T:
// Проверить, что у registry.companyId существует категория V, иначе ошибка: 5420 - "Доступ к клирингу на «%s» не найден для компании %s."/> Где %s = категории В
// Проверить, что найденного регистра DM*T: registry.status!=OK, иначе ошибка: 5425 - "Запрещена идентификация средства по рассчитанным обязательствам".
// Создать/добавить в баланс DM-T на базе OM-T
//1.2 Проверить, баланс в запросе
// Баланс должен быть положительный
public enum ReturnDepositValidationRule implements IValidationRule<ImdgValidationContext<RegistryReturnDepositRequest>> {
RgsWronCodeCheck() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<RegistryReturnDepositRequest> context) {
Registry rgs = context.getStoredObject(Stored.PresentById);
if (!equalsByCode(RegistryTradingParams.TM_T, rgs) && !equalsByCode(RegistryTradingParams.OM_T, rgs)) {
return of(ClearingError.RgsWrongCode, "{}.id={}", rgs.getRegistryCode(), rgs.getId());
}
return empty();
}
},
CategoryCheck() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<RegistryReturnDepositRequest> context) {
Registry rgs = context.getStoredObject(Stored.PresentById);
ClearingCategory ctgr = null;
if (equalsByCode(RegistryTradingParams.TM_T, rgs)) {
ctgr = ClearingCategory.I;
} else {
ctgr = ClearingCategory.V;
}
Imdg<ClearingMemberCategory> ctgImdg = context.obtainMap(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
ClearingMemberCategory category =
ctgImdg.getFirstObjectBySQL("companyId = %d and clearingMemberCategory = '%s'"
.formatted(rgs.getCompanyId(), ctgr.getKey()));
if (category == null) {
return of(ClearingError.CategoryNotFound, ctgr.getKey(), rgs.getCompanyId());
}
return empty();
}
},
@Deprecated
RegistryCodeCheck() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<RegistryReturnDepositRequest> context) {
@ -34,23 +79,40 @@ public enum ReturnDepositValidationRule implements IValidationRule<ImdgValidatio
public Optional<EnumMessage> validate(ImdgValidationContext<RegistryReturnDepositRequest> context) {
Registry rgs = context.getStoredObject(Stored.PresentById);
RegistryReturnDepositRequest request = context.getValidatedObject();
if (request.getBalance() == null || request.getBalance().compareTo(rgs.getBalance()) > 0) {
if (request.getBalance() == null || request.getBalance().compareTo(BigDecimal.ZERO) < 0) {
return of(ClearingError.WrongField, "balance");
}
if (request.getBalance().compareTo(rgs.getBalance()) > 0) {
return of(ClearingError.IdentifiedFundsExceedObligations);
}
return Optional.empty();
}
}, DmxCheck() {
}, Dm_Check() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<RegistryReturnDepositRequest> context) {
Registry rgs = context.getStoredObject(Stored.PresentById);
Imdg<Registry> rgsImdg = context.obtainMap(IMDGDistributedNames.Map_Registry, Registry.class);
RegistryManager rgsMng = new RegistryManager(rgsImdg);
Optional<Registry> dmx = rgsMng.searchDmxByCompanyId(rgs);
if (dmx.isPresent() && RegistryStatus.OK.equalsByKey(dmx.get().getRegistryStatus()) ) {
if (TextUtil.isEmpty(rgs.getContract())) {
return empty();
}
RegistryTradingParams rgsCode;
if (equalsByCode(RegistryTradingParams.TM_T, rgs)) {
rgsCode = RegistryTradingParams.DM_X;
} else {
rgsCode = RegistryTradingParams.DM_T;
}
String sqlCondition = String.format("(%s) and companyId = %d and contract = '%s'",
RegistryCodeSqlBuilder.getInstance(rgsCode).build(),
rgs.getCompanyId(),
rgs.getContract());
Registry dm__ = rgsImdg.getFirstObjectBySQL(sqlCondition);
if (dm__ != null && RegistryStatus.OK.equalsByKey(dm__.getRegistryStatus()) ) {
return of(ClearingError.ObligationsAlreadyCalculated);
}
dmx.ifPresent(dmxRgs -> context.storeObject(ValidationStored.ReturnDepositDmx, dmxRgs));
return Optional.empty();
if (dm__ != null) {
context.storeObject(ValidationStored.ReturnDepositDm__, dm__);
}
return empty();
}
};

View file

@ -18,7 +18,7 @@ public enum ValidationStored {
Sdf06Company, Sdf06Account, Sdf06Tcr,
ReturnDepositDmx,
ReturnDepositDm__,
IdentificationFundsTcrSearch, IdentificationFundsAssetTrio,

View file

@ -160,6 +160,7 @@ public class ReturnDepositSession extends AbstractSession implements Initializin
{
InspectionPoolPayload companyIdPayload = new InspectionPoolPayload();
companyIdPayload.setProcessedCompanyId(currSession.getCompanyId());
companyIdPayload.setSessionId(currSession.getId());
runStage(TaskType.InspectionObligations, companyIdPayload, inspectionObligationsDepositReturn);
}

View file

@ -1,7 +1,5 @@
package ru.spcex.clearing.session.stage.impl;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -55,16 +53,18 @@ public class InspectionObligations implements ISessionStage {
private final AssetTBFProcessing assets;
private final GatewayRequester gateway;
private final TradingTimeService tradingTimeService;
private final PlanBalanceCalc planBalanceCalc;
@Autowired
public InspectionObligations(ImdgProvider imdgProvider,
RegistryManager registryManager,
AssetTBFProcessing assets,
GatewayRequester gateway) {
GatewayRequester gateway, PlanBalanceCalc planBalanceCalc) {
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
this.registryManager = registryManager;
this.assets = assets;
this.gateway = gateway;
this.planBalanceCalc = planBalanceCalc;
this.gateway.setName("InspectionObligations|OM*T");
this.tradingTimeService = new TradingTimeService(imdgProvider);
}
@ -204,52 +204,11 @@ public class InspectionObligations implements ISessionStage {
}
}
stageRevision2(sessionId);
planBalanceCalc.stageRevision2(sessionId);
return new StageResult(null, true);
}
protected void stageRevision2(Long sessionId) {
/* todo logic
Collection rgsAT = findRegistryATBySession // registry_disignation=A and registry_unit=T
Collection rgsAB = findRegistryATBySession // registry_disignation=A and registry_unit=B and sessionId = current
foreach( at: rgsAT)
foreach (ab: rgsAB)
if (at.companyId=ab.companyId and at.accountId=ab.accountId and at.securityId=ab.securityId)
at.plannecBallance -= ab.balance
*/
String sqlAT = RegistryCodeSqlBuilder.getInstance(A__T).build();
String sqlAB = String.format("(%s) and sessionId = %d",
RegistryCodeSqlBuilder.getInstance(A__B).build(),
sessionId
);
Collection<Registry> registriesAT = registryImdg.getCollectionObjectsBySQL(sqlAT);
Collection<Registry> registriesAB = registryImdg.getCollectionObjectsBySQL(sqlAB);
log.debug("Select {} registers by \"{}\", {} registers by \"{}\" for revision step 2",
registriesAT.size(), sqlAT, registriesAB.size(), sqlAB);
Map<Triple<Long, Long, Long>, List<Registry>> regABIndex = registriesAB.stream().collect(Collectors.groupingBy(
(Registry reg) -> new MutableTriple(reg.getCompanyId(), reg.getAccountId(), reg.getSecurityId())
));
int updateCount = 0;
Instant now = Instant.now();
for (Registry regT : registriesAT) {
Triple<Long, Long, Long> key = new MutableTriple(regT.getCompanyId(), regT.getAccountId(), regT.getSecurityId());
List<Registry> regsB = regABIndex.get(key);
if (regsB == null) {
log.debug("Registry A__B for registry[{}] (A__T key {}) not found", regT, key);
} else {
for (Registry regB : regsB) {
regT.setPlanBalance(safeBD(regT.getPlanBalance()).subtract(safeBD(regB.getBalance())));
}
regT.setUpdated(now);
registryImdg.update(regT);
updateCount++;
}
}
log.debug("Updated {} registers A__T with planBalance at {}", updateCount, now);
}
private String searchAssetsByObligationSql(Registry obligation) {
RegistryTradingParams counterRegistryTradingParams = null;
if (IEnumKey.getEnumByKey(RegistryInstrumentType.class, obligation.getRegistryInstrumentType()) == RegistryInstrumentType.S) {

View file

@ -16,6 +16,7 @@ import ru.spcex.clearing.service.schedule.TradingTimeService;
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.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
@ -44,23 +45,26 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
private final AssetTBFProcessing assets;
private final TradingTimeService tradingTimeService;
private final GatewayRequester gateway;
private final PlanBalanceCalc planBalanceCalc;
@Autowired
public InspectionObligationsDepositReturn(ImdgProvider imdgProvider, RegistryManager rgsMng, AssetTBFProcessing assets, TradingTimeService tradingTimeService, GatewayRequester gateway) {
public InspectionObligationsDepositReturn(ImdgProvider imdgProvider, RegistryManager rgsMng, AssetTBFProcessing assets, TradingTimeService tradingTimeService, GatewayRequester gateway, PlanBalanceCalc planBalanceCalc) {
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
this.categoryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
this.rgsMng = rgsMng;
this.assets = assets;
this.tradingTimeService = tradingTimeService;
this.gateway = gateway;
this.planBalanceCalc = planBalanceCalc;
this.gateway.setName("InspectionObligationsDepositReturn|OM*T");
}
@Override
public StageResult<?> submit(Task<?> task) {
InspectionPoolPayload payload = (InspectionPoolPayload) task.getData();
switch (task.getTaskType()) {
case InspectionObligations -> {
return inspectionObligations();
return inspectionObligations(payload.getSessionId());
}
default -> throw new IllegalStateException("Unknown task type: " + task.getTaskType());
}
@ -81,7 +85,7 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
}
}
private StageResult<?> inspectionObligations() {
private StageResult<?> inspectionObligations(Long sessionId) {
String sqlCondition = String.format("(%s) and registryStatus = '%s'",
RegistryCodeSqlBuilder.getInstance(OS_T, OM_T, TS_T, TM_T).build(),
RegistryStatus.POOL.getKey());
@ -196,6 +200,7 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
group.forEach(rgs -> updateStatus(rgs, registryStatusFailed(rgs)));
}
}
planBalanceCalc.stageRevision2(sessionId);
return new StageResult<>(null, true);
}

View file

@ -0,0 +1,73 @@
package ru.spcex.clearing.session.stage.impl;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static ru.spcex.platform.enumeration.RegistryTradingParams.A__B;
import static ru.spcex.platform.enumeration.RegistryTradingParams.A__T;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
@Component
public class PlanBalanceCalc {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<Registry> rgsImdg;
public PlanBalanceCalc(ImdgProvider imdgProvider) {
this.rgsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
}
public void stageRevision2(Long sessionId) {
/* todo logic
Collection rgsAT = findRegistryATBySession // registry_disignation=A and registry_unit=T
Collection rgsAB = findRegistryATBySession // registry_disignation=A and registry_unit=B and sessionId = current
foreach( at: rgsAT)
foreach (ab: rgsAB)
if (at.companyId=ab.companyId and at.accountId=ab.accountId and at.securityId=ab.securityId)
at.plannecBallance -= ab.balance
*/
String sqlAT = RegistryCodeSqlBuilder.getInstance(A__T).build();
String sqlAB = String.format("(%s) and sessionId = %d",
RegistryCodeSqlBuilder.getInstance(A__B).build(),
sessionId
);
Collection<Registry> registriesAT = rgsImdg.getCollectionObjectsBySQL(sqlAT);
Collection<Registry> registriesAB = rgsImdg.getCollectionObjectsBySQL(sqlAB);
log.debug("Select {} registers by \"{}\", {} registers by \"{}\" for revision step 2",
registriesAT.size(), sqlAT, registriesAB.size(), sqlAB);
Map<Triple<Long, Long, Long>, List<Registry>> regABIndex = registriesAB.stream().collect(Collectors.groupingBy(
(Registry reg) -> new MutableTriple(reg.getCompanyId(), reg.getAccountId(), reg.getSecurityId())
));
int updateCount = 0;
Instant now = Instant.now();
for (Registry regT : registriesAT) {
Triple<Long, Long, Long> key = new MutableTriple(regT.getCompanyId(), regT.getAccountId(), regT.getSecurityId());
List<Registry> regsB = regABIndex.get(key);
if (regsB == null) {
log.debug("Registry A__B for registry[{}] (A__T key {}) not found", regT, key);
} else {
for (Registry regB : regsB) {
regT.setPlanBalance(safeBD(regT.getPlanBalance()).subtract(safeBD(regB.getBalance())));
}
regT.setUpdated(now);
rgsImdg.update(regT);
updateCount++;
}
}
log.debug("Updated {} registers A__T with planBalance at {}", updateCount, now);
}
}