http://jira.mfd.msk:8088/browse/CLS-445
backend-api/clearing-service return deposit request
This commit is contained in:
ialbert 2023-07-26 17:35:27 +03:00
parent dac9c80c6f
commit f7cb4855aa
12 changed files with 264 additions and 7 deletions

View file

@ -7,13 +7,11 @@ import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.backendapi.controller.queue.AbstractQueueController;
import ru.spcex.clearing.backendapi.controller.request.cud.registry.RSplitDepositActionNew;
import ru.spcex.clearing.backendapi.controller.request.cud.registry.ReturnDepositActionNew;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.CommonGetAllResponse;
@ -57,4 +55,17 @@ public class RegistryController extends AbstractQueueController {
@RequestBody RSplitDepositActionNew rSplitDepositActionNew) throws ExecutionException, InterruptedException {
return processRequest(Consts.REGISTRY_SPLIT_DEPOSIT_ACTION, rSplitDepositActionNew);
}
@ApiOperation(value = "Отметить средства на возврат депозита")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(value = "/returnDeposit/{id}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CudResponse returnDepositAction(
@ApiParam(value = "Идентификатор изменяемого объекта.", required = true, example = "1234")
@PathVariable("id") Long id,
@ApiParam(value = "Параметры команды в JSON формате.", required = true)
@RequestBody ReturnDepositActionNew returnDepositAction) throws ExecutionException, InterruptedException {
returnDepositAction.setId(id);
return processRequest(Consts.REGISTRY_RETURN_DEPOSIT_ACTION, returnDepositAction);
}
}

View file

@ -0,0 +1,68 @@
package ru.spcex.clearing.backendapi.controller.request.cud.registry;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryReturnDepositRequest;
import ru.spcex.platform.classes.base.interfaces.WithId;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ReturnDepositActionNew implements IAction<RegistryReturnDepositRequest>, WithId {
@JsonIgnore
public Long id;
@ApiModelProperty(value = "Сумма", example = "1600.20")
@JsonProperty
public BigDecimal balance;
@Override
public RegistryReturnDepositRequest toRequest() {
var req = new RegistryReturnDepositRequest();
req.setId(id);
req.setBalance(balance);
return req;
}
@Override
public Collection<EnumMessage> validate() {
List<EnumMessage> errors = new ArrayList<>();
if (id == null) {
errors.add(new EnumMessage(BackEndError.ValidationError, "url parameter 'id'"));
}
if (balance == null) {
errors.add(new EnumMessage(BackEndError.ValidationError, "balance"));
}
return errors;
}
@ApiModelProperty(hidden = true)
@Override
public ActionType getActionType() {
return ActionType.NEW;
}
@Override
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getBalance() {
return balance;
}
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
}

View file

@ -38,6 +38,7 @@ public class ActionValidationProvider implements InitializingBean {
@Override
public void afterPropertiesSet() {
validators.put(Consts.LAUNCHER_NEW, taskRunnerNew());
validators.put(Consts.REGISTRY_RETURN_DEPOSIT_ACTION, idPresent(IMDGDistributedNames.Map_Registry));
}
@SuppressWarnings("unchecked")

View file

@ -21,13 +21,16 @@ import ru.clearing.classes.statics.data.sdf.SDf57;
import ru.clearing.classes.statics.data.security.MoneyMarketSecurity;
import ru.clearing.classes.statics.data.security.Security;
import ru.clearing.platform.dictionary.SectionDictionary;
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.validation.*;
import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.imdg.validation.LogPrefixId;
import ru.spcex.platform.imdg.validation.rule.PresentById;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
@ -239,4 +242,20 @@ public class ValidationConfig {
);
};
}
@Bean("returnDepositValidator")
public Function<RegistryReturnDepositRequest, IValidator> returnDepositValidator() {
return returnDepositRequest -> {
ImdgValidationContext<RegistryReturnDepositRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(returnDepositRequest);
context.addImdg(IMDGDistributedNames.Map_Registry, imdgRegistry);
context.setLogPrefix(LogPrefixId.INSTANCE);
return new ValidatorImpl<>(context,
new PresentById(IMDGDistributedNames.Map_Registry, ClearingError.RecordNotFound, true),
ReturnDepositValidationRule.RegistryCodeCheck,
ReturnDepositValidationRule.BalanceCheck,
ReturnDepositValidationRule.DmxCheck
);
};
}
}

View file

@ -4,6 +4,7 @@ import ru.spcex.platform.utils.enumeration.IErrorEnumId;
public enum ClearingError implements IErrorEnumId {
GeneralError(5400L),
RecordNotFoundInDictionary(5423L),
IncorrectValue(5404L),
RecordNotFound(5406L),
CompanyNotFound(5410L),
@ -19,7 +20,9 @@ public enum ClearingError implements IErrorEnumId {
ClearingUnavailableForCompany(5421L),
InsecurityObligation(5422L),
NewDealsNotFound(5423L),
//ошибки "перенесенные" из balance-service
IdentifiedFundsExceedObligations(5424L),
ObligationsAlreadyCalculated(5425L),
//ошибки "перенесенные" из balance-service,
CompanyNotFoundB(5211L),
CurrencyNotFound(5213L),
OperationCanBeRunForTodayOnly(5214L),

View file

@ -13,6 +13,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.clearing.CreateRegistryRe
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.Sdf04Request;
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.registry.RegistryReturnDepositRequest;
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;
@ -113,6 +114,9 @@ public class EventsReceiver extends QueueConsumer implements InitializingBean {
callback(CreateRegistryRequest.class)
.setConsumer(event -> registryService.updateRegistryIfNeeded(event.getRequestPayload()))
.forDestination(Consts.REGISTRY_NEW, callbacks::put);
callback(RegistryReturnDepositRequest.class)
.setFunction(registryService::returnDeposit)
.forDestination(Consts.REGISTRY_RETURN_DEPOSIT_ACTION, callbacks::put);
callback(LauncherCommandRequest.class)
.setConsumer(event -> registryService.resetBalances())
.forDestination(Task.createRegistry_GRYT.topic(), callbacks::put);

View file

@ -29,6 +29,10 @@ public class RegistryManager {
this.rgsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
}
public RegistryManager(Imdg<Registry> rgsImdg) {
this.rgsImdg = rgsImdg;
}
public Optional<Registry> searchDmx(Registry rgs) {
if (TextUtil.isEmpty(rgs.getContract())) return Optional.empty();
String sqlCondition = String.format("(%s) and companyId = %d and contract = '%s'",

View file

@ -2,18 +2,29 @@ package ru.spcex.clearing.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.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.RegistryReturnDepositRequest;
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.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
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;
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.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
import java.math.BigDecimal;
import java.time.Instant;
@ -29,11 +40,17 @@ public class RegistryService {
private final ImdgProvider imdgProvider;
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private final Imdg<Registry> registryImdg;
private final Function<RegistryReturnDepositRequest, IValidator> returnDepositVal;
private final IMessageResolver msgResolver;
public RegistryService(ImdgProvider imdgProvider) {
public RegistryService(ImdgProvider imdgProvider,
@Qualifier("returnDepositValidator") Function<RegistryReturnDepositRequest, IValidator> returnDepositVal,
IMessageResolver msgResolver) {
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.msgResolver = msgResolver;
}
public void createRegistry(CreateRegistryRequest createRegistryRequest) {
@ -87,6 +104,43 @@ public class RegistryService {
});
}
public RequestInfoUpdate returnDeposit(BaseRequest<RegistryReturnDepositRequest> req) {
RegistryReturnDepositRequest requestPayload = req.getRequestPayload();
IValidator validator = returnDepositVal.apply(requestPayload);
Optional<EnumMessage> err = validator.tillFirstError();
if (err.isPresent()) {
log.info("RegistryReturnDepositRequest.id={} validation error: {}",
requestPayload.getId(),
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(),
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(),
req.getId());
}
return new RequestInfoUpdate(req.getId(), Status.Success, null);
}
/**
* находим все регистры AM__/AS__ по пришедшему ТКР
*/

View file

@ -0,0 +1,61 @@
package ru.spcex.clearing.service.validation;
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.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.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.util.Optional;
public enum ReturnDepositValidationRule implements IValidationRule<ImdgValidationContext<RegistryReturnDepositRequest>> {
RegistryCodeCheck() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<RegistryReturnDepositRequest> context) {
Registry rgs = context.getStoredObject(Stored.PresentById);
if (!RegistryDesignation.T.equalsByKey(rgs.getRegistryDesignation())
|| !RegistryInstrumentType.M.equalsByKey(rgs.getRegistryInstrumentType())
|| !RegistryUnit.T.equalsByKey(rgs.getRegistryUnit())) {
return of(ClearingError.RecordNotFoundInDictionary, "TM*T", "Registry");
}
return empty();
}
}, BalanceCheck() {
@Override
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) {
return of(ClearingError.IdentifiedFundsExceedObligations);
}
return Optional.empty();
}
}, DmxCheck() {
@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.searchDmx(rgs);
if (dmx.isPresent() && RegistryStatus.OK.equalsByKey(dmx.get().getRegistryStatus()) ) {
return of(ClearingError.ObligationsAlreadyCalculated);
}
dmx.ifPresent(dmxRgs -> context.storeObject(ValidationStored.ReturnDepositDmx, dmxRgs));
return Optional.empty();
}
};
@Override
public String ruleName() {
return "ReturnDepositValidationRule." + name();
}
}

View file

@ -10,5 +10,7 @@ public enum ValidationStored {
Sdf08Company, Sdf08Account,
Sdf06Company, Sdf06Account
Sdf06Company, Sdf06Account,
ReturnDepositDmx
}

View file

@ -159,6 +159,7 @@ public interface Consts {
String PAYMENT_INSTRUCTION_CLEARING_OUTBOUND_ACTION = "clearing-outbound-action";
String REGISTRY_SPLIT_DEPOSIT_ACTION = "registry-split-deposit-action";
String REGISTRY_RETURN_DEPOSIT_ACTION = "registry-return-deposit-action";
String REGISTRY_COVERED_DEAL_REGISTER_NEW = "registry-covered-deal-register-new";
String REGISTRY_ADMITTED_DEAL_REGISTER_NEW = "registry-admitted-deal-register-new";
String REGISTRY_DEAL_REGISTER_NEW = "registry-deal-register-new";

View file

@ -0,0 +1,29 @@
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 RegistryReturnDepositRequest implements WithId {
@JsonProperty
private Long id;
@JsonProperty
private BigDecimal balance;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getBalance() {
return balance;
}
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
}