clearing-service http://jira.mfd.msk:8088/browse/CLS-307 SPLT todo уточнить ТЗ

This commit is contained in:
AKurakin 2023-08-28 16:16:15 +03:00
parent 94831710e4
commit 99e83b8bf9
4 changed files with 152 additions and 2 deletions

View file

@ -25,8 +25,10 @@ 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.RegistryReturnDepositRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest;
import ru.spcex.clearing.service.validation.*;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.imdg.api.Imdg;
@ -336,6 +338,20 @@ public class ValidationConfig {
};
}
@Bean("splitDepositValidator")
public Function<RegistrySplitDepositActionRequest, IValidator> splitDepositValidator() {
return refundDateRequest -> {
ImdgValidationContext<RegistrySplitDepositActionRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(refundDateRequest);
context.addImdg(IMDGDistributedNames.Map_Registry, imdgRegistry);
context.setLogPrefix(r -> "contract=%d refundDate=%s".formatted(r.getContract(), r.getRefundDate()));
return new ValidatorImpl<>(context,
FieldRequiredRule.instance("contract", RegistrySplitDepositActionRequest::getContract, ClearingError.RequiredFieldEmpty),
FieldRequiredRule.instance("refundDate", RegistrySplitDepositActionRequest::getRefundDate, ClearingError.RequiredFieldEmpty)
);
};
}
@Bean
public Function<PIClearingOutbondActionNewRequest, IValidator> piOutboundValidation() {
return pmtOut -> {

View file

@ -17,6 +17,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.gateway.AssetOperationApp
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.RegistryReturnDepositRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest;
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;
@ -138,6 +139,9 @@ public class EventsReceiver extends QueueConsumer implements InitializingBean {
callback(LauncherCommandRequest.class)
.setConsumer(event -> registryService.resetBalances())
.forDestination(Task.createRegistry_GRYT.topic(), callbacks::put);
callback(RegistrySplitDepositActionRequest.class)
.setFunction(registryService::splitDeposit)
.forDestination(Consts.REGISTRY_SPLIT_DEPOSIT_ACTION, callbacks::put);
callback(LauncherCommandRequest.class)
.setConsumer(task -> {

View file

@ -6,18 +6,22 @@ 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.RegistryReturnDepositRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistrySplitDepositActionRequest;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
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.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
@ -43,18 +47,25 @@ public class RegistryService {
private final Imdg<Registry> registryImdg;
private final Function<RegistryReturnDepositRequest, IValidator> returnDepositVal;
private final Function<RegistryChangeRefundDateRequest, IValidator> refundDateVal;
private final Function<RegistrySplitDepositActionRequest, IValidator> splitDepositActionVal;
private final IMessageResolver msgResolver;
private final UserRoleVerification rights;
public RegistryService(ImdgProvider imdgProvider,
@Qualifier("returnDepositValidator") Function<RegistryReturnDepositRequest, IValidator> returnDepositVal,
@Qualifier("refundDateValidator") Function<RegistryChangeRefundDateRequest, IValidator> refundDateVal,
IMessageResolver msgResolver) {
@Qualifier("splitDepositValidator") Function<RegistrySplitDepositActionRequest, IValidator> splitDepositActionVal,
IMessageResolver msgResolver,
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.msgResolver = msgResolver;
this.rights = rights;
}
public void createRegistry(CreateRegistryRequest createRegistryRequest) {
@ -276,4 +287,122 @@ public class RegistryService {
registryImdg.update(registry);
}
}
public RequestInfoUpdate splitDeposit(BaseRequest<RegistrySplitDepositActionRequest> req) {
RegistrySplitDepositActionRequest requestPayload = req.getRequestPayload();
RequestInfoUpdate roleCheck = rights.validateRoleAndGetResult(req);
if (roleCheck != null) {
return roleCheck;
}
{
IValidator validator = splitDepositActionVal.apply(requestPayload);
Optional<EnumMessage> err = validator.tillFirstError();
if (err.isPresent()) {
log.info("RegistrySplitDepositActionRequest request id={} validation error: {}",
req.getId(),
msgResolver.resolve(err.get()));
return new RequestInfoUpdate(req.getId(), Status.Error, msgResolver.resolve(err.get()));
}
}
Registry baseRegistry;
{
ImdgPredicateBuilder prdBldr = registryImdg.predicateBuilder();
ImdgPredicate query = prdBldr.and(
RegistryCodeSqlBuilder.getInstance(RegistryTradingParams.OM_T).buildPredicate(prdBldr),
prdBldr.equals("contract", requestPayload.getContract()));
baseRegistry = registryImdg.getSingleObjectByPredicate(query);
if (baseRegistry == null) {
String errMsg = msgResolver.resolve(new EnumMessage(ClearingError.TCRegistryNotFound, requestPayload.getContract()));
log.info("RegistrySplitDepositActionRequest request id={}, registry query \"{}\": {}",
req.getId(), query, errMsg);
return new RequestInfoUpdate(req.getId(), Status.Error, errMsg);
} else {
log.debug("Registry.id={} found by query \"{}\"",
baseRegistry.getId(), query);
}
}
{
Optional<EnumMessage> err = validateSplitDepositRegister(baseRegistry, requestPayload);
if (err.isPresent()) {
log.info("RegistrySplitDepositActionRequest request id={} cross validation with registry.id={} error: {}",
req.getId(), baseRegistry.getId(), msgResolver.resolve(err.get()));
return new RequestInfoUpdate(req.getId(), Status.Error, msgResolver.resolve(err.get()));
}
}
ImdgTransaction txCtx = imdgProvider.newTransaction();
boolean txOk = false;
txCtx.beginTransaction();
try {
Imdg<Registry> registryTMap = txCtx.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
Instant now = Instant.now();
InOutDirection direction = InOutDirection.out; // todo откуда брать направление?
// 1. Первая группа
Registry firstRegistry = baseRegistry.clone();
firstRegistry.setId(null);
firstRegistry.setCreated(now);
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. Вторая группа
Registry secondRegistry = null;
if (InOutDirection.out == direction) {
secondRegistry.setId(null);
secondRegistry.setCreated(now);
secondRegistry.setUpdated(null);
secondRegistry.setBalance(requestPayload.getOutboundAmount());
secondRegistry.setContract(baseRegistry.getContract() + "~2");
registryTMap.insert(secondRegistry);
}
// 3. Текущим обязательствам установить статус SPLT
baseRegistry.setRegistryStatus(RegistryStatus.SPLT.getKey());
baseRegistry.setUpdated(Instant.now());
registryTMap.update(baseRegistry);
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 {
if (txOk) {
txCtx.commitTransaction();
} else {
txCtx.rollbackTransaction();
log.debug("Transaction rollback {}", txCtx);
}
}
return new RequestInfoUpdate(req.getId(), Status.Success, null);
}
private Optional<EnumMessage> validateSplitDepositRegister(Registry registry, RegistrySplitDepositActionRequest request) {
if (!RegistryStatus.PROC.equalsByKey(registry.getRegistryStatus())) {
log.trace("Registry[{}].RegistryStatus={} - error", 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 {}", registry.getId(), regBalance, request.getOutboundAmount());
return Optional.of(new EnumMessage(ClearingError.BalanceInsufficient, request.getContract()));
}
if (!registry.getRefundDate().isAfter(request.getRefundDate())) {
log.trace("Registry[{}].RefundDate={} but request RefundDate={}", registry.getId(), registry.getRefundDate(), request.getRefundDate());
return Optional.of(new EnumMessage(ClearingError.WrongFieldValue, "RefundDate"));
}
return Optional.empty();
}
}

View file

@ -11,7 +11,8 @@ public enum RegistryStatus implements IEnumKey {
FAIL("FAIL"),
UNCV("UNCV"),
MNG("MNG"),
POOL("POOL")
POOL("POOL"),
SPLT("SPLT")
;
private final String key;