ialbert 2026-04-29 15:05:20 +03:00
parent ea0a449602
commit 9223d8b391
6 changed files with 375 additions and 2 deletions

View file

@ -1,5 +1,6 @@
package ru.spcex.clearing.config; package ru.spcex.clearing.config;
import java.util.Optional;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -41,11 +42,14 @@ 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.balance.StatementRequest; import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.IdentificationFundsRequest; import ru.spcex.clearing.platform.messaging.domain.cud.registry.IdentificationFundsRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeRefundDateRequest; 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.RegistryChangeStatusExtractRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryReturnDepositRequest; 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.registry.RegistrySplitDepositActionRequest;
import ru.spcex.clearing.service.AssetTrio;
import ru.spcex.clearing.service.registry.AssetTBFProcessing;
import ru.spcex.clearing.service.validation.AnltAccLoad; import ru.spcex.clearing.service.validation.AnltAccLoad;
import ru.spcex.clearing.service.validation.ClrngValidationStored; import ru.spcex.clearing.service.validation.ClrngValidationStored;
import ru.spcex.clearing.service.validation.CompanyByTradingCodeValidationRule; import ru.spcex.clearing.service.validation.CompanyByTradingCodeValidationRule;
@ -68,18 +72,27 @@ import ru.spcex.clearing.service.validation.SecurityBySecurityCodeValidationRule
import ru.spcex.clearing.service.validation.SessionTerminationValidationRule; import ru.spcex.clearing.service.validation.SessionTerminationValidationRule;
import ru.spcex.clearing.service.validation.SplitDepositRequestValidationRule; import ru.spcex.clearing.service.validation.SplitDepositRequestValidationRule;
import ru.spcex.clearing.service.validation.StatusExtractValidationRule; import ru.spcex.clearing.service.validation.StatusExtractValidationRule;
import ru.spcex.clearing.service.validation.WithdrawalFundsValidationRule;
import ru.spcex.clearing.service.validation.WithdrawalFundsValidationStore;
import ru.spcex.clearing.util.security.UserRoleVerification; import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule; import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule; import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule; import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.enumeration.ClearingCategory; import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.enumeration.CompanySymbol;
import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider; 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.IdEqualPredicate;
import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.imdg.validation.LogPrefixId; import ru.spcex.platform.imdg.validation.LogPrefixId;
import ru.spcex.platform.imdg.validation.rule.CurrencyCodeValidationRule; import ru.spcex.platform.imdg.validation.rule.CurrencyCodeValidationRule;
import ru.spcex.platform.imdg.validation.rule.PresentById; import ru.spcex.platform.imdg.validation.rule.PresentById;
import ru.spcex.platform.imdg.validation.rule.PresentByPredicate;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidationRule;
import ru.spcex.platform.utils.validation.IValidator; import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl; import ru.spcex.platform.utils.validation.ValidatorImpl;
@ -113,8 +126,9 @@ public class ValidationConfig {
Imdg<PaymentInstruction> pmtImdg; Imdg<PaymentInstruction> pmtImdg;
Imdg<ClearingMemberCategory> ctgrImdg; Imdg<ClearingMemberCategory> ctgrImdg;
ImdgProvider imdgProvider; ImdgProvider imdgProvider;
AssetTBFProcessing assetsMng;
public ValidationConfig(ImdgProvider imdgProvider) { public ValidationConfig(ImdgProvider imdgProvider, AssetTBFProcessing assetsMng) {
this.imdgRelation = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); this.imdgRelation = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
this.imdgCompany = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); this.imdgCompany = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.imdgCurrency = imdgProvider.getImdg(IMDGDistributedNames.Map_Currency, Currency.class); this.imdgCurrency = imdgProvider.getImdg(IMDGDistributedNames.Map_Currency, Currency.class);
@ -142,6 +156,7 @@ public class ValidationConfig {
this.currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class); this.currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class);
this.digitalCertificateSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_DigitalCertificateSecurity, DigitalCertificateSecurity.class); this.digitalCertificateSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_DigitalCertificateSecurity, DigitalCertificateSecurity.class);
this.imdgProvider = imdgProvider; this.imdgProvider = imdgProvider;
this.assetsMng = assetsMng;
} }
//@Bean("adminRoleVerification") //@Bean("adminRoleVerification")
@ -399,6 +414,81 @@ public class ValidationConfig {
}; };
} }
@Bean("withdrawalFundsValidator")
public Function<DmauRegistryRequest, IValidator> withdrawalFundsValidator() {
return identificationFundsRequest -> {
ImdgValidationContext<DmauRegistryRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(identificationFundsRequest);
context.addImdg(IMDGDistributedNames.Map_Account, imdgAccount);
context.addImdg(IMDGDistributedNames.Map_Company, imdgCompany);
context.addImdg(IMDGDistributedNames.Map_CompanySymbols, imdgCompanySymbols);
context.addImdg(IMDGDistributedNames.Map_TradingClearingRegistry, imdgTradingClearingRegistry);
context.addImdg(IMDGDistributedNames.Map_TradingClearingRegistryList, imdgTradingClearingRegistryList);
context.setLogPrefix(dmauRegistryRequest ->
"[debitCorrAccount:%s]".formatted(dmauRegistryRequest.getDebitCorrAccount()
));
ImdgPredicateBuilder cmpSymbPb = imdgCompanySymbols.predicateBuilder();
var cmpSymbCheck = PresentByPredicate.builder(
(Function<DmauRegistryRequest, ImdgPredicate>) req -> cmpSymbPb.and(
cmpSymbPb.equals("companyId", req.getSenderId()),
cmpSymbPb.equals("companySymbol", CompanySymbol.BIC.getKey())
))
.mapName(IMDGDistributedNames.Map_CompanySymbols)
.errorProvider(req -> new EnumMessage(ClearingError.RecordNotFound, "companySymbol"))
.store(WithdrawalFundsValidationStore.CompanySymbol)
.build()
;
ImdgPredicateBuilder cmpPb = imdgCompany.predicateBuilder();
var cmpCheck = PresentByPredicate.builder(new IdEqualPredicate<>(
cmpPb, DmauRegistryRequest::getSenderId
))
.mapName(IMDGDistributedNames.Map_Company)
.errorProvider(req -> new EnumMessage(ClearingError.RecordNotFound, "company"))
.store(WithdrawalFundsValidationStore.Company)
.build();
ImdgPredicateBuilder accPb = imdgAccount.predicateBuilder();
var accCheck = PresentByPredicate.builder(new IdEqualPredicate<>(
accPb, DmauRegistryRequest::getCreditLegAccountId
))
.mapName(IMDGDistributedNames.Map_Account)
.errorProvider(req -> new EnumMessage(ClearingError.RecordNotFound, "account"))
.store(WithdrawalFundsValidationStore.Account)
.build();
var assetPresent = new IValidationRule<ImdgValidationContext<DmauRegistryRequest>>() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<DmauRegistryRequest> ctx) {
Company cmp = ctx.getStoredObject(WithdrawalFundsValidationStore.Company);
Account acc = ctx.getStoredObject(WithdrawalFundsValidationStore.Account);
Optional<AssetTrio> assetsTrio = assetsMng.searchMoneyByAccAndCompany(cmp.getId(), acc.getId());
if (assetsTrio.isEmpty()) {
return of(ClearingError.RecordNotFound, "AM_F/AM_B/AM_T");
}
ctx.storeObject(WithdrawalFundsValidationStore.AssetTrio, assetsTrio.get());
return empty();
}
@Override
public String ruleName() {
return "assets-present";
}
};
return new ValidatorImpl<>(context,
WithdrawalFundsValidationRule.Fields,
cmpSymbCheck,
cmpCheck,
accCheck,
assetPresent,
WithdrawalFundsValidationRule.TcrPresent
);
};
}
@Bean("splitDepositValidator") @Bean("splitDepositValidator")
public Function<RegistrySplitDepositActionRequest, IValidator> splitDepositValidator() { public Function<RegistrySplitDepositActionRequest, IValidator> splitDepositValidator() {
return refundDateRequest -> { return refundDateRequest -> {

View file

@ -23,6 +23,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.clearing.SessionContinueE
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest; 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.gateway.AssetOperationApprovalRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbondActionNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.IdentificationFundsRequest; import ru.spcex.clearing.platform.messaging.domain.cud.registry.IdentificationFundsRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.RegistryChangeRefundDateRequest; 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.RegistryChangeStatusExtractRequest;
@ -40,6 +41,7 @@ import ru.spcex.clearing.service.execution.ExecutionFondComponent;
import ru.spcex.clearing.service.executors.Sdf06Executor; import ru.spcex.clearing.service.executors.Sdf06Executor;
import ru.spcex.clearing.service.executors.Sdf10Executor; import ru.spcex.clearing.service.executors.Sdf10Executor;
import ru.spcex.clearing.service.payment.PaymentInstructionOutboundService; import ru.spcex.clearing.service.payment.PaymentInstructionOutboundService;
import ru.spcex.clearing.service.payment.WithdrawalFundsService;
import ru.spcex.clearing.session.stage.SessionTerminator; import ru.spcex.clearing.session.stage.SessionTerminator;
import ru.spcex.clearing.session.stage.TaskType; import ru.spcex.clearing.session.stage.TaskType;
import ru.spcex.clearing.session.stage.impl.BalanceRevise; import ru.spcex.clearing.session.stage.impl.BalanceRevise;
@ -65,6 +67,7 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
private final StatementServiceV2 statementService; private final StatementServiceV2 statementService;
private final SessionTerminator sessionTerminator; private final SessionTerminator sessionTerminator;
private final PaymentInstructionOutboundService pmtOutboundService; private final PaymentInstructionOutboundService pmtOutboundService;
private final WithdrawalFundsService withdrawalFundsService;
private final ExecutionCurrencyComponent execCurrUpload; private final ExecutionCurrencyComponent execCurrUpload;
private final ExecutionDepositComponent execDepUpload; private final ExecutionDepositComponent execDepUpload;
private final ExecutionFondComponent execFondUpload; private final ExecutionFondComponent execFondUpload;
@ -81,7 +84,7 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
Sdf05Sender sdf05Sender, Sdf05Sender sdf05Sender,
StatementServiceV2 statementService, StatementServiceV2 statementService,
SessionTerminator sessionTerminator, SessionTerminator sessionTerminator,
PaymentInstructionOutboundService pmtOutboundService, PaymentInstructionOutboundService pmtOutboundService, WithdrawalFundsService withdrawalFundsService,
ExecutionCurrencyComponent execCurrUpload, ExecutionCurrencyComponent execCurrUpload,
ExecutionDepositComponent execDepUpload, ExecutionDepositComponent execDepUpload,
ExecutionFondComponent execFondUpload) { ExecutionFondComponent execFondUpload) {
@ -98,6 +101,7 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
this.statementService = statementService; this.statementService = statementService;
this.sessionTerminator = sessionTerminator; this.sessionTerminator = sessionTerminator;
this.pmtOutboundService = pmtOutboundService; this.pmtOutboundService = pmtOutboundService;
this.withdrawalFundsService = withdrawalFundsService;
this.execCurrUpload = execCurrUpload; this.execCurrUpload = execCurrUpload;
this.execDepUpload = execDepUpload; this.execDepUpload = execDepUpload;
this.execFondUpload = execFondUpload; this.execFondUpload = execFondUpload;
@ -144,6 +148,9 @@ public class EventsReceiver extends QueueConsumerV2 implements InitializingBean
callback(PIClearingOutbondActionNewRequest.class) callback(PIClearingOutbondActionNewRequest.class)
.setFunction(pmtOutboundService::sendOutBoundPayment) .setFunction(pmtOutboundService::sendOutBoundPayment)
.forDestination(Consts.PAYMENT_INSTRUCTION_CLEARING_OUTBOUND_ACTION, callbacks::put); .forDestination(Consts.PAYMENT_INSTRUCTION_CLEARING_OUTBOUND_ACTION, callbacks::put);
callback(DmauRegistryRequest.class)
.setFunction(withdrawalFundsService::withdrawalFunds)
.forDestination(Consts.REGISTRY_DMAU_CREATE_ACTION, callbacks::put);
callback(StatementRequest.class) callback(StatementRequest.class)
.setConsumer(statementService::processReq) .setConsumer(statementService::processReq)
.forDestination(Consts.STATEMENT_PROCESS, callbacks::put); .forDestination(Consts.STATEMENT_PROCESS, callbacks::put);

View file

@ -0,0 +1,192 @@
package ru.spcex.clearing.service.payment;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.Optional;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.sdf.SDf54;
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.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.SdfClearingRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.service.AssetTrio;
import ru.spcex.clearing.service.Sdf54Creator;
import ru.spcex.clearing.service.SpecifUtil;
import ru.spcex.clearing.service.registry.AssetTBFProcessing;
import ru.spcex.clearing.service.registry.DmiService;
import ru.spcex.clearing.service.validation.WithdrawalFundsValidationStore;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.platform.enumeration.CurrencyCode;
import ru.spcex.platform.enumeration.InOutDirection;
import ru.spcex.platform.enumeration.TransactionStatus;
import ru.spcex.platform.enumeration.UserRole;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.log.ExceptionUtils;
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
import ru.spcex.platform.utils.text.TextUtil;
import ru.spcex.platform.utils.time.TimeUtil;
import ru.spcex.platform.utils.validation.IValidator;
@Service
public class WithdrawalFundsService {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Function<DmauRegistryRequest, IValidator> withdrawalFundsVal;
private final Sdf54Creator sdf54Creator;
private final Imdg<SDf54> sdf54Imdg;
private final Imdg<PaymentInstruction> pmtImdg;
private final KafkaSender kafkaSender;
private final ImdgId idGen;
private final RequestHelper reqHelp;
private final UserRoleVerification rights;
private final IMessageResolver msgResolver;
private final AssetTBFProcessing assetsMng;
private final DmiService dmiService;
public WithdrawalFundsService(Function<DmauRegistryRequest, IValidator> withdrawalFundsVal, Sdf54Creator sdf54Creator, ImdgProvider imdgProvider, KafkaSender kafkaSender, RequestHelper reqHelp, UserRoleVerification rights, IMessageResolver msgResolver, AssetTBFProcessing assetsMng, DmiService dmiService) {
this.withdrawalFundsVal = withdrawalFundsVal;
this.sdf54Creator = sdf54Creator;
this.kafkaSender = kafkaSender;
this.sdf54Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf54, SDf54.class);
this.pmtImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class);
this.idGen = imdgProvider.getImdgIdGenerator();
this.reqHelp = reqHelp;
this.rights = rights;
this.msgResolver = msgResolver;
this.assetsMng = assetsMng;
this.dmiService = dmiService;
}
public RequestInfoUpdate withdrawalFunds(BaseRequest<DmauRegistryRequest> req) {
if (!rights.userHasRole(req.getUserId(), UserRole.Admin)) {
return reqHelp.error(req.getId(), ClearingError.UserVerifyDenial);
}
DmauRegistryRequest payload = req.getRequestPayload();
IValidator validator = withdrawalFundsVal.apply(payload);
Optional<EnumMessage> err = validator.tillFirstError();
if (err.isPresent()) {
log.error("DmauRegistryRequest.id={} debitCorrAccount={} validation error: {}",
req.getId(),
payload != null ? payload.getDebitCorrAccount() : null,
msgResolver.resolve(err.get()));
return reqHelp.error(req.getId(), err.get());
}
log.info("DmauRegistryRequest.id={} debitCorrAccount={} validation passed", req.getId(), payload.getDebitCorrAccount());
CompanySymbols cmpSymb = validator.getStored(WithdrawalFundsValidationStore.CompanySymbol);
Company cmp = validator.getStored(WithdrawalFundsValidationStore.Company);
Account acc = validator.getStored(WithdrawalFundsValidationStore.Account);
AssetTrio assets = validator.getStored(WithdrawalFundsValidationStore.AssetTrio);
TradingClearingRegistry tcr = validator.getStored(WithdrawalFundsValidationStore.TCR);
String curr = TextUtil.isEmpty(payload.getSecuritySymbol()) ? CurrencyCode.RUB.getKey() : payload.getSecuritySymbol();
Instant now = Instant.now();
LocalDate nowDate = TimeUtil.toLocalDate(now);
PaymentInstruction pmtIns = new PaymentInstruction();
pmtIns.setSenderId(payload.getSenderId());
pmtIns.setPayeeBic(cmpSymb.getCompanySymbolValue());
pmtIns.setAdresseeBic(payload.getDebitBIC());
pmtIns.setPayeeBankName(cmp.getShortName());
pmtIns.setAddresseeBankName(payload.getDebitBankName());
pmtIns.setPaymentDate(now);
pmtIns.setPaymentPurpose(extractPaymentPurpose(payload));
pmtIns.setSettlementDate(nowDate);
pmtIns.setCreditLeg_amount(payload.getAmount());
pmtIns.setDebitLeg_amount(payload.getAmount());
pmtIns.setCreditLeg_accountId(payload.getCreditLegAccountId());
pmtIns.setCreditLeg_account(acc.getAccount());
pmtIns.setDebit_csAccount(payload.getDebitCorrAccount());
pmtIns.setDebitLeg_account(payload.getDebitLegAccount());
pmtIns.setCreditLeg_direction(InOutDirection.out.getKey());
pmtIns.setDebitLeg_direction(InOutDirection.in.getKey());
pmtIns.setCreditLeg_currencyCode(payload.getSecuritySymbol());
pmtIns.setDebitLeg_currencyCode(payload.getSecuritySymbol());
pmtIns.setCreditLeg_securityId(payload.getSecurityId());
pmtIns.setDebitLeg_securityId(payload.getSecurityId());
pmtIns.setTransactionStatus(TransactionStatus.stld.getKey());
pmtIns.setCreated(now);
pmtIns.setClearingDate(nowDate);
pmtImdg.insert(pmtIns);
log.info("created PaymentInstruction.id={}", pmtIns.getId());
SDf54 sDf54;
try {
sDf54 = sdf54Creator.create(pmtIns);
} catch (IllegalStateException e) {
log.error(ExceptionUtils.getStackTrace(e));
return failedResponse(req, now, pmtIns);
}
sDf54.setId(idGen.nextId());
sDf54.setGenerationId(pmtIns.getId());
sDf54.setRbankcode(pmtIns.getAdresseeBic());
sDf54.setC_acc_cred(pmtIns.getDebit_csAccount());
SpecifUtil.fillSegmentsBy35Symbols(pmtIns.getAddresseeBankName(),
sDf54::setRbanknam1,
sDf54::setRbanknam2,
sDf54::setRbanknam3,
sDf54::setRbanknam4,
sDf54::setRbanknam5);
SpecifUtil.fillSegmentsBy35Symbols(payload.getDebitCompanyName(),
sDf54::setRclientn1,
sDf54::setRclientn2,
sDf54::setRclientn3,
sDf54::setRclientn4
);
sDf54.setInn_cred(payload.getDebitINN());
sDf54.setKpp_cred(payload.getDebitKPP());
sdf54Imdg.insert(sDf54);
log.info("created sdf54.id={}", sDf54.getId());
dmiService.setProcComment(tcr.getId(),
curr,
safeBD(payload.getAmount()).negate(),
sDf54.getDocnm_ref());
log.debug("recalculating assests...");
assetsMng.process(assets.a__b(), assets.a__t(), assets.a__f(), BigDecimal.ZERO);
SdfClearingRequest exp = new SdfClearingRequest();
exp.setGroupId(sDf54.getGenerationId());
kafkaSender.sendRequestToQueue(Consts.SDF54_PROCESS, exp);
return reqHelp.success(req.getId());
}
private RequestInfoUpdate failedResponse(BaseRequest<DmauRegistryRequest> req,
Instant now,
PaymentInstruction pmtIns) {
pmtIns.setTransactionStatus(TransactionStatus.fail.getKey());
pmtIns.setUpdated(now);
pmtImdg.update(pmtIns);
return reqHelp.error(req.getId(), ClearingError.GeneralError);
}
private String extractPaymentPurpose(DmauRegistryRequest payload) {
if (!TextUtil.isEmpty(payload.getPaymentPurpose())) {
return payload.getPaymentPurpose();
}
if (CurrencyCode.RUB.equalsByKey(payload.getSecuritySymbol())) {
return "Вывод средств с регистра невыясненных денежных средств по %s"
.formatted(payload.getSecuritySymbol());
} else {
return "Withdrawal of funds from the register %s of unidentified funds"
.formatted(payload.getSecuritySymbol());
}
}
}

View file

@ -0,0 +1,69 @@
package ru.spcex.clearing.service.validation;
import java.math.BigDecimal;
import java.util.Objects;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistryList;
import ru.spcex.clearing.error.ClearingError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DmauRegistryRequest;
import ru.spcex.clearing.service.AnltSearcher;
import ru.spcex.clearing.service.TcrSearcher;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
public enum WithdrawalFundsValidationRule implements IValidationRule<ImdgValidationContext<DmauRegistryRequest>> {
Fields() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<DmauRegistryRequest> context) {
DmauRegistryRequest validatedObject = context.getValidatedObject();
if (validatedObject.getAmount() == null || validatedObject.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
return of(ClearingError.WrongField, "amount");
}
if (validatedObject.getBalance() == null || validatedObject.getBalance().compareTo(validatedObject.getAmount()) < 0) {
return of(ClearingError.WrongField, "balance");
}
return empty();
}
},
TcrPresent() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<DmauRegistryRequest> context) {
Account accCred = context.getStoredObject(WithdrawalFundsValidationStore.Account);
Company addressee = context.getStoredObject(WithdrawalFundsValidationStore.Company);
Imdg<TradingClearingRegistry> tcrImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
Imdg<TradingClearingRegistryList> tcrListImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistryList, TradingClearingRegistryList.class);
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
Imdg<Account> accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
TcrSearcher tcrSearcher = new TcrSearcher(tcrImdg, tcrListImdg, companyImdg, accountImdg);
AnltSearcher.AnltSearch srchRes = tcrSearcher.searchByAccountId(accCred.getId(), accCred.getCurrency());
if (!srchRes.isFound()) {
return Optional.of(srchRes.getError());
}
if (srchRes.getCompany() != null) {
if (!Objects.equals(srchRes.getCompany().getId(), addressee.getId())) {
return of(ClearingError.AccountIsNotMatchedWithCompany, accCred.getId(), addressee.getId());
}
}
TradingClearingRegistry tcr = srchRes.getTcr();
if (tcr == null) {
return of(ClearingError.RecordNotFound, "TCR");
}
context.storeObject(WithdrawalFundsValidationStore.TCR, tcr);
return Optional.empty();
}
};
private final static Logger log = LoggerFactory.getLogger(WithdrawalFundsValidationRule.class);
@Override
public String ruleName() {
return "WithdrawalFundsValidationRule." + name();
}
}

View file

@ -0,0 +1,10 @@
package ru.spcex.clearing.service.validation;
public enum WithdrawalFundsValidationStore {
CompanySymbol,
Company,
Account,
AssetTrio,
TCR,
;
}

View file

@ -2,6 +2,8 @@ package ru.spcex.platform.imdg.validation.rule;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.classes.base.SpcexObjectBase;
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;
@ -10,6 +12,7 @@ import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule; import ru.spcex.platform.utils.validation.IValidationRule;
public class PresentByPredicate<T> implements IValidationRule<ImdgValidationContext<T>> { public class PresentByPredicate<T> implements IValidationRule<ImdgValidationContext<T>> {
private static final Logger log = LoggerFactory.getLogger(PresentByPredicate.class);
private final String mapName; private final String mapName;
private final Function<T, EnumMessage> errorProvider; private final Function<T, EnumMessage> errorProvider;
@ -42,8 +45,10 @@ public class PresentByPredicate<T> implements IValidationRule<ImdgValidationCont
if (obj == null) { if (obj == null) {
EnumMessage errMsg = errorProvider.apply(validatedObject); EnumMessage errMsg = errorProvider.apply(validatedObject);
log.debug("object not found by predicate: {}", predicate);
return Optional.of(errMsg); return Optional.of(errMsg);
} }
log.debug("object found by predicate [{}]: {}.id={}", predicate, mapName, obj.getId());
if (storeEnabled != null) { if (storeEnabled != null) {
context.storeObject(storeEnabled, obj); context.storeObject(storeEnabled, obj);