SDF20
SDF55 SDF10 в DS*T#contract кладется sdf10.outDocument а не sdf11.outDocument блокировки в PaymentInstructionOutboundService imdg SDf20/SDf21/SDf57 выгружаются за все дни
This commit is contained in:
parent
64e6f932bc
commit
334a91fb81
19 changed files with 455 additions and 34 deletions
|
|
@ -343,6 +343,22 @@ public class ValidationConfig {
|
|||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<SDf20, IValidator> sdf20Validator() {
|
||||
return sdf20 -> {
|
||||
ImdgValidationContext<SDf20> ctx = new ImdgValidationContext<>();
|
||||
ctx.setValidatedObject(sdf20);
|
||||
ctx.addImdg(IMDGDistributedNames.Map_Company, imdgCompany);
|
||||
ctx.addImdg(IMDGDistributedNames.Map_Account, imdgAccount);
|
||||
return new ValidatorImpl<>(ctx,
|
||||
Sdf20ValidationRule.AccountPresent,
|
||||
Sdf20ValidationRule.CompanyPresent,
|
||||
Sdf20ValidationRule.TCRPresent,
|
||||
Sdf20ValidationRule.DS_TFound,
|
||||
Sdf20ValidationRule.AS_TFound);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean("userRoleVerification")
|
||||
public UserRoleVerification userRoleVerification(ImdgProvider imdgProvider, IMessageResolver msgs) {
|
||||
return new UserRoleVerification(imdgProvider, msgs, ClearingError.UserVerifyDenial);
|
||||
|
|
|
|||
|
|
@ -5,25 +5,33 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.platform.enumeration.CurrencyCode;
|
||||
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.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.utils.number.BigDecimalUtil;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
|
||||
|
||||
@Service
|
||||
public class AssetTBFProcessing {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Imdg<Registry> registryImdg;
|
||||
private final Imdg<Registry> rgsImdg;
|
||||
private final RegistryManager rgsMng;
|
||||
|
||||
public AssetTBFProcessing(ImdgProvider imdgProvider, RegistryManager rgsMng) {
|
||||
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||
this.rgsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||
this.rgsMng = rgsMng;
|
||||
}
|
||||
|
||||
|
|
@ -38,8 +46,8 @@ public class AssetTBFProcessing {
|
|||
am_b.setUpdated(now);
|
||||
am_f.setUpdated(now);
|
||||
|
||||
registryImdg.update(am_b);
|
||||
registryImdg.update(am_f);
|
||||
rgsImdg.update(am_b);
|
||||
rgsImdg.update(am_f);
|
||||
}
|
||||
|
||||
public void processByAm_b(Registry am_b, BigDecimal sum) {
|
||||
|
|
@ -58,6 +66,27 @@ public class AssetTBFProcessing {
|
|||
}
|
||||
}
|
||||
|
||||
public Optional<AssetTrio> searchMoneyByAccAndCompany(Long companyId, Long accountId) {
|
||||
ImdgPredicateBuilder pb = rgsImdg.predicateBuilder();
|
||||
Function<RegistryTradingParams, ImdgPredicate> prdct = rgsCode -> pb.and(
|
||||
pb.sql(RegistryCodeSqlBuilder.getInstance(rgsCode).build()),
|
||||
pb.equals("companyId", companyId),
|
||||
pb.equals("accountId", accountId),
|
||||
pb.equals("securitySymbol", CurrencyCode.RUB.getKey())
|
||||
);
|
||||
Registry amf = rgsImdg.getFirstObjectByPredicate(prdct.apply(AM_F));
|
||||
Registry amb = rgsImdg.getFirstObjectByPredicate(prdct.apply(AM_B));
|
||||
Registry amt = rgsImdg.getFirstObjectByPredicate(prdct.apply(AM_T));
|
||||
if (amf != null && amb != null && amt != null) {
|
||||
return Optional.of(new AssetTrio(amf, amb, amt));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public boolean insufficientBalance(Registry registry, BigDecimal amount) {
|
||||
return BigDecimalUtil.safeBD(registry.getBalance()).compareTo(BigDecimalUtil.safeBD(amount)) < 0;
|
||||
}
|
||||
|
||||
//точно будет аналогично и с другими полями
|
||||
private void safeWrapField(Supplier<BigDecimal> getter, Consumer<BigDecimal> setter) {
|
||||
BigDecimal fieldValue = getter.get();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package ru.spcex.clearing.service;
|
||||
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
|
||||
public record AssetTrio(Registry am_f, Registry am_b, Registry am_t) {
|
||||
}
|
||||
|
|
@ -89,6 +89,25 @@ public class RegistryManager {
|
|||
return Optional.ofNullable(dmt);
|
||||
}
|
||||
|
||||
public Optional<Registry> searchByAccSecContract(Long accountId, String securitySymbol, String contract, RegistryTradingParams rgsCde) {
|
||||
if (TextUtil.isEmpty(contract)
|
||||
|| TextUtil.isEmpty(securitySymbol)
|
||||
|| accountId == null
|
||||
|| rgsCde == null)
|
||||
return Optional.empty();
|
||||
ImdgPredicateBuilder pb = rgsImdg.predicateBuilder();
|
||||
return Optional.ofNullable(
|
||||
rgsImdg.getSingleObjectByPredicate(
|
||||
pb.and(
|
||||
pb.sql(RegistryCodeSqlBuilder.getInstance(rgsCde).build()),
|
||||
pb.equals("accountId", accountId),
|
||||
pb.equals("securitySymbol", securitySymbol),
|
||||
pb.equals("contract", contract)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public Optional<Registry> searchDmtClrn(Registry rgs) {
|
||||
ImdgPredicate dmtClrnPrdct = RegistryDm_tClrnPredicate
|
||||
.instance(rgs.getCompanyId(), rgs.getCounterPartyId())
|
||||
|
|
|
|||
|
|
@ -46,7 +46,10 @@ public class Sdf54Creator {
|
|||
this.idGenerator = imdgProvider.getImdgIdGenerator();
|
||||
}
|
||||
|
||||
private final static DateTimeFormatter docnmRefFormatter = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
|
||||
|
||||
public SDf54 create(PaymentInstruction paymentInstruction) {
|
||||
Instant now = Instant.now();
|
||||
AccountType creditAccType = getAccountType(paymentInstruction.getCreditLeg_accountId());
|
||||
AccountType debAccType = getAccountType(paymentInstruction.getDebitLeg_accountId());
|
||||
String c_acc_deb = null;
|
||||
|
|
@ -118,9 +121,7 @@ public class Sdf54Creator {
|
|||
|
||||
|
||||
sDf54.setDoc_type("002");
|
||||
String strId = paymentInstruction.getId().toString();
|
||||
String strIdCut = strId.length() > 16 ? strId.substring(strId.length() - 16) : strId;
|
||||
sDf54.setDocnm_ref(strIdCut);
|
||||
sDf54.setDocnm_ref(docnmRefFormatter.format(TimeUtil.toDateTime(now)));
|
||||
sDf54.setC_acc_deb(c_acc_deb);
|
||||
|
||||
|
||||
|
|
@ -149,7 +150,7 @@ public class Sdf54Creator {
|
|||
String sumDeb = paymentInstruction.getDebitLeg_amount() != null ? paymentInstruction.getDebitLeg_amount().toString() : "";
|
||||
sDf54.setSum_deb(BigDecimalUtil.limitDecimalPlaces(sumDeb, 2));
|
||||
sDf54.setSpecif_1(paymentInstruction.getPaymentPurpose());
|
||||
sDf54.setGenerationTime(Instant.now());
|
||||
sDf54.setGenerationTime(now);
|
||||
log.debug("paymentInstruction.id={}, sdf54.id {}", paymentInstruction.getId(), sDf54.getId());
|
||||
return sDf54;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,11 +71,11 @@ public class StatementService extends QueueConsumer implements InitializingBean
|
|||
.setConsumer(systemRequest -> {
|
||||
StatementRequest payload = systemRequest.getRequestPayload();
|
||||
if (payload.getTable() == null
|
||||
|| !Arrays.asList(SdfTable.SDF_01, SdfTable.SDF_04, SdfTable.SDF_57, SdfTable.SDF_08, SdfTable.SDF_13, SdfTable.SDF_21, SdfTable.SDF_10).contains(payload.getTable())) {
|
||||
|| !Arrays.asList(SdfTable.SDF_01, SdfTable.SDF_04, SdfTable.SDF_57, SdfTable.SDF_08, SdfTable.SDF_13, SdfTable.SDF_21, SdfTable.SDF_10, SdfTable.SDF_55, SdfTable.SDF_20).contains(payload.getTable())) {
|
||||
log.debug("StatementService: skipping table {}", payload.getTable());
|
||||
return;
|
||||
}
|
||||
if (Arrays.asList(SdfTable.SDF_08, SdfTable.SDF_21, SdfTable.SDF_10).contains(payload.getTable())) {
|
||||
if (Arrays.asList(SdfTable.SDF_08, SdfTable.SDF_21, SdfTable.SDF_10, SdfTable.SDF_55, SdfTable.SDF_20).contains(payload.getTable())) {
|
||||
stmtSrvV2.processReq(systemRequest);
|
||||
} else if (payload.isContinueSdf()) {
|
||||
processAccountAnswer(systemRequest);
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ import ru.spcex.clearing.platform.messaging.domain.Consts;
|
|||
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdf01Request;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||
import ru.spcex.clearing.service.executors.Sdf08Executor;
|
||||
import ru.spcex.clearing.service.executors.Sdf10Executor;
|
||||
import ru.spcex.clearing.service.executors.Sdf21Executor;
|
||||
import ru.spcex.clearing.service.executors.*;
|
||||
import ru.spcex.clearing.service.model.Result;
|
||||
import ru.spcex.platform.enumeration.SdfTable;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
|
|
@ -32,13 +30,23 @@ public class StatementServiceV2 {
|
|||
private final Sdf08Executor sdf08Executor;
|
||||
private final Sdf21Executor sdf21Executor;
|
||||
private final Sdf10Executor sdf10Executor;
|
||||
private final Sdf55Executor sdf55Executor;
|
||||
private final Sdf20Executor sdf20Executor;
|
||||
|
||||
public StatementServiceV2(ImdgProvider imdgProvider, KafkaSender kafkaSender, Sdf08Executor sdf08Executor, Sdf21Executor sdf21Executor, Sdf10Executor sdf10Executor) {
|
||||
public StatementServiceV2(ImdgProvider imdgProvider,
|
||||
KafkaSender kafkaSender,
|
||||
Sdf08Executor sdf08Executor,
|
||||
Sdf21Executor sdf21Executor,
|
||||
Sdf10Executor sdf10Executor,
|
||||
Sdf55Executor sdf55Executor,
|
||||
Sdf20Executor sdf20Executor) {
|
||||
this.imdgProvider = imdgProvider;
|
||||
this.kafkaSender = kafkaSender;
|
||||
this.sdf08Executor = sdf08Executor;
|
||||
this.sdf21Executor = sdf21Executor;
|
||||
this.sdf10Executor = sdf10Executor;
|
||||
this.sdf55Executor = sdf55Executor;
|
||||
this.sdf20Executor = sdf20Executor;
|
||||
}
|
||||
|
||||
public void processReq(BaseRequest<StatementRequest> systemRequest) {
|
||||
|
|
@ -50,9 +58,9 @@ public class StatementServiceV2 {
|
|||
log.debug("table {} is not paired with any other SDF", table);
|
||||
//здесь switch case одиночные методы
|
||||
switch (table) {
|
||||
case SDF_10 -> {
|
||||
sdf10Executor.execute(systemRequest);
|
||||
}
|
||||
case SDF_10 -> sdf10Executor.execute(systemRequest);
|
||||
case SDF_55 -> sdf55Executor.execute(systemRequest);
|
||||
case SDF_20 -> sdf20Executor.execute(systemRequest);
|
||||
default -> log.error("unknown table {}", table);
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ public class Sdf10Executor {
|
|||
requests.add(requestFromStatement(stmt, company.getTradingCode(), tcr.getCode(), sDf10.getSecurityCode()));
|
||||
} else {
|
||||
SDf11 sDf11 = processedApproved(stmt, sDf10, now, sdf11GroupId);
|
||||
createDs_t(tcr, company, validator.getStored(ValidationStored.SecurityBySecurityCode), stmt.getAmount(), sDf11.getOutDocument());
|
||||
createDs_t(tcr, company, validator.getStored(ValidationStored.SecurityBySecurityCode), stmt.getAmount(), sDf10.getOutDocument());
|
||||
sdf11WasCreated = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package ru.spcex.clearing.service.executors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.company.Company;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
|
||||
import ru.clearing.classes.statics.data.sdf.SDf20;
|
||||
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.balance.StatementRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.AssetOperationListRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.AssetOperationRequest;
|
||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||
import ru.spcex.clearing.service.RegistryManager;
|
||||
import ru.spcex.clearing.service.validation.ValidationStored;
|
||||
import ru.spcex.platform.enumeration.InOutDirection;
|
||||
import ru.spcex.platform.enumeration.RegistryStatus;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
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.number.BigDecimalUtil;
|
||||
import ru.spcex.platform.utils.validation.IValidator;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
public class Sdf20Executor {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Imdg<SDf20> sDf20Imdg;
|
||||
private final Imdg<Registry> rgsImdg;
|
||||
private final Function<SDf20, IValidator> validation;
|
||||
private final IMessageResolver msgRslv;
|
||||
private final KafkaSender kafka;
|
||||
|
||||
@Autowired
|
||||
public Sdf20Executor(ImdgProvider imdgProvider,
|
||||
Function<SDf20, IValidator> validation,
|
||||
IMessageResolver msgRslv,
|
||||
RegistryManager rgsMng,
|
||||
KafkaSender kafka) {
|
||||
this.sDf20Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf20, SDf20.class);
|
||||
this.rgsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||
this.validation = validation;
|
||||
this.msgRslv = msgRslv;
|
||||
this.kafka = kafka;
|
||||
}
|
||||
|
||||
public void execute(BaseRequest<StatementRequest> systemRequest) {
|
||||
Instant now = Instant.now();
|
||||
StatementRequest payload = systemRequest.getRequestPayload();
|
||||
log.debug("executing {}.generationId={}", payload.getTable(), payload.getGroupId());
|
||||
SDf20 sDf20 = sDf20Imdg.getFirstObjectBySQL("generationId = %d".formatted(payload.getGroupId()));
|
||||
if (sDf20 == null) {
|
||||
log.error("sDf20 not found for generationId={}", payload.getGroupId());
|
||||
return;
|
||||
}
|
||||
IValidator validator = validation.apply(sDf20);
|
||||
Optional<EnumMessage> err = validator.tillFirstError();
|
||||
if (err.isPresent()) {
|
||||
log.error("sdf20.id={} error {}", sDf20.getId(), msgRslv.resolve(err.get()));
|
||||
return;
|
||||
}
|
||||
Registry ds_t = validator.getStored(ValidationStored.Sdf20Dst);
|
||||
Registry as_t = validator.getStored(ValidationStored.Sdf20Ast);
|
||||
Company company = validator.getStored(ValidationStored.Sdf20Company);
|
||||
TradingClearingRegistry tcr = validator.getStored(ValidationStored.Sdf20Tcr);
|
||||
log.debug("sdf20.id={}, found as_t.id={}, ds_t.id={}", sDf20.getId(), as_t.getId(), ds_t.getId());
|
||||
|
||||
ds_t.setComment(sDf20.getTransactionNumber());
|
||||
ds_t.setRegistryStatus(RegistryStatus.OK.getKey());
|
||||
ds_t.setUpdated(now);
|
||||
|
||||
BigDecimal quantity = BigDecimalUtil.parseLeadingZeroes(sDf20.getQuantity());
|
||||
BigDecimal balance = BigDecimalUtil.safeBD(as_t.getBalance());
|
||||
if ("ADDFREE".equalsIgnoreCase(sDf20.getOperationCode())) {
|
||||
as_t.setBalance(balance.add(quantity));
|
||||
} else if ("DELFREE".equals(sDf20.getOperationCode())) {
|
||||
as_t.setBalance(balance.subtract(quantity));
|
||||
}
|
||||
as_t.setCheckBalance(BigDecimalUtil.parseLeadingZeroes(sDf20.getCloseBalance()));
|
||||
as_t.setUpdated(now);
|
||||
|
||||
rgsImdg.update(ds_t);
|
||||
rgsImdg.update(as_t);
|
||||
|
||||
//send gateway
|
||||
{
|
||||
Collection<AssetOperationRequest> requests = new ArrayList<>();
|
||||
AssetOperationRequest req = requestFromStatement(
|
||||
quantity,
|
||||
sDf20.getSecurity(),
|
||||
company.getTradingCode(),
|
||||
tcr.getCode()
|
||||
);
|
||||
requests.add(req);
|
||||
|
||||
AssetOperationListRequest assetOperationListRequest = new AssetOperationListRequest();
|
||||
assetOperationListRequest.setAssetOperationRequests(requests);
|
||||
kafka.sendRequestToQueue(Consts.ASSET_OPERATION, assetOperationListRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private AssetOperationRequest requestFromStatement(BigDecimal quantity, //из sdf
|
||||
String securitySymbol, //из sdf
|
||||
String tradingCode, //из компании
|
||||
String tcrCode//из TCR
|
||||
) {
|
||||
AssetOperationRequest req = new AssetOperationRequest();
|
||||
req.setStatementId(null);
|
||||
req.setQuantity(quantity); //+
|
||||
req.setSecuritySymbol(securitySymbol); //+
|
||||
req.setTradingCode(tradingCode); //???
|
||||
req.setCode(tcrCode); //TCR
|
||||
req.setDirection(InOutDirection.in.getKey());
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package ru.spcex.clearing.service.executors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.payment.PaymentInstruction;
|
||||
import ru.clearing.classes.statics.data.sdf.SDf54;
|
||||
import ru.clearing.classes.statics.data.sdf.SDf55;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
|
||||
import ru.spcex.platform.enumeration.TransactionStatus;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Service
|
||||
public class Sdf55Executor {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Imdg<SDf54> sDf54Imdg;
|
||||
private final Imdg<SDf55> sDf55Imdg;
|
||||
private final Imdg<PaymentInstruction> pmtImdg;
|
||||
|
||||
|
||||
public Sdf55Executor(ImdgProvider imdgProvider) {
|
||||
this.sDf54Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf54, SDf54.class);
|
||||
this.sDf55Imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SDf55, SDf55.class);
|
||||
this.pmtImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_PaymentInstruction, PaymentInstruction.class);
|
||||
}
|
||||
|
||||
public void execute(BaseRequest<StatementRequest> systemRequest) {
|
||||
StatementRequest payload = systemRequest.getRequestPayload();
|
||||
log.debug("executing {}.generationId={}", payload.getTable(), payload.getGroupId());
|
||||
SDf55 sDf55 = sDf55Imdg.getFirstObjectBySQL("generationId = %d".formatted(payload.getGroupId()));
|
||||
if (sDf55 == null) {
|
||||
log.error("sDf55 not found for generationId={}", payload.getGroupId());
|
||||
return;
|
||||
}
|
||||
SDf54 sDf54 = sDf54Imdg.getFirstObjectBySQL("docnm_ref = '%s'".formatted(sDf55.getDocnm_ref()));
|
||||
if (sDf54 == null) {
|
||||
log.error("sDf54 not found for sDf55.id={} docnm_ref={}", sDf55.getId(), sDf55.getDocnm_ref());
|
||||
return;
|
||||
}
|
||||
PaymentInstruction pmt = pmtImdg.getSingleObjectByID(sDf54.getGenerationId());
|
||||
if (pmt == null) {
|
||||
log.error("pmt not found for sDf54.id={} generationId={}", sDf54.getId(), sDf54.getGenerationId());
|
||||
return;
|
||||
}
|
||||
log.debug("sdf55.id={}, found sdf54.id={}, PaymentInstruction.id={}", sDf55.getId(), sDf54.getId(), pmt.getId());
|
||||
pmt.setTransactionStatus(TransactionStatus.ok.getKey());
|
||||
pmt.setUpdated(Instant.now());
|
||||
pmtImdg.update(pmt);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,8 @@ import ru.spcex.clearing.platform.messaging.domain.cud.payment.PIClearingOutbond
|
|||
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
|
||||
import ru.spcex.clearing.platform.messaging.service.Status;
|
||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||
import ru.spcex.clearing.service.AssetTBFProcessing;
|
||||
import ru.spcex.clearing.service.AssetTrio;
|
||||
import ru.spcex.clearing.service.RegistryManager;
|
||||
import ru.spcex.clearing.service.Sdf54Creator;
|
||||
import ru.spcex.clearing.service.builder.PaymentInstructionBuilderV2;
|
||||
|
|
@ -35,9 +37,11 @@ import ru.spcex.platform.imdg.api.ImdgProvider;
|
|||
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||
import ru.spcex.platform.utils.enumeration.IEnumId;
|
||||
import ru.spcex.platform.utils.enumeration.IMessageResolver;
|
||||
import ru.spcex.platform.utils.number.BigDecimalUtil;
|
||||
import ru.spcex.platform.utils.validation.IValidator;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
|
@ -59,12 +63,13 @@ public class PaymentInstructionOutboundService {
|
|||
private final RegistryManager rgsMng;
|
||||
private final Sdf54Creator sdf54Creator;
|
||||
private final KafkaSender kafkaSender;
|
||||
private final AssetTBFProcessing assetsMng;
|
||||
|
||||
@Autowired
|
||||
public PaymentInstructionOutboundService(UserRoleVerification rights,
|
||||
IMessageResolver msgs,
|
||||
ImdgProvider imdgProvider,
|
||||
Function<PIClearingOutbondActionNewRequest, IValidator> validation, RegistryManager rgsMng, KafkaSender kafkaSender) {
|
||||
Function<PIClearingOutbondActionNewRequest, IValidator> validation, RegistryManager rgsMng, KafkaSender kafkaSender, AssetTBFProcessing assetsMng) {
|
||||
this.imdgProvider = imdgProvider;
|
||||
this.rights = rights;
|
||||
this.msgs = msgs;
|
||||
|
|
@ -80,10 +85,12 @@ public class PaymentInstructionOutboundService {
|
|||
this.idGenerator = imdgProvider.getImdgIdGenerator();
|
||||
this.rgsMng = rgsMng;
|
||||
this.kafkaSender = kafkaSender;
|
||||
this.assetsMng = assetsMng;
|
||||
}
|
||||
|
||||
public RequestInfoUpdate sendOutBoundPayment(BaseRequest<PIClearingOutbondActionNewRequest> req) {
|
||||
log.info("new PIClearingOutbondActionNewRequest.id: {}", req.getId());
|
||||
Instant now = Instant.now();
|
||||
PIClearingOutbondActionNewRequest payload = req.getRequestPayload();
|
||||
if (!rights.userHasRole(req.getUserId(), UserRole.Admin)) {
|
||||
return error(req.getId(), ClearingError.UserVerifyDenial);
|
||||
|
|
@ -97,7 +104,7 @@ public class PaymentInstructionOutboundService {
|
|||
Account accDeb = validator.getStored(ValidationStored.PIOutboundAccountDeb);
|
||||
Company addressee = cmpImdg.getSingleObjectByID(payload.getAddresseeId());
|
||||
Company sender = cmpImdg.getSingleObjectByID(payload.getSenderId());
|
||||
BigDecimal amount = payload.getCreditLeg_amount();
|
||||
BigDecimal amount = BigDecimalUtil.safeBD(payload.getCreditLeg_amount());
|
||||
log.debug("all checks passed, accCred.id={}, accDeb.id={}, addressee.id={}, sender.id={}, amount: {}",
|
||||
accCred.getId(), accDeb.getId(), addressee.getId(), sender.getId(), amount);
|
||||
|
||||
|
|
@ -128,14 +135,25 @@ public class PaymentInstructionOutboundService {
|
|||
|
||||
pmtImdg.insert(pmt);
|
||||
log.debug("new PaymentInstruction.id: {}", pmt.getId());
|
||||
Optional<AssetTrio> assets = assetsMng.searchMoneyByAccAndCompany(addressee.getId(), accCred.getId());
|
||||
if (assets.isEmpty() || assetsMng.insufficientBalance(assets.get().am_f(), amount)) {
|
||||
pmt.setTransactionStatus(TransactionStatus.cher.getKey());
|
||||
pmt.setUpdated(now);
|
||||
pmtImdg.update(pmt);
|
||||
log.debug("insufficient balance, pmt.id: {}, am*f.balance={}",
|
||||
pmt.getId(), assets.map(AssetTrio::am_f).map(Registry::getBalance).orElse(null));
|
||||
return error(req.getId(), ClearingError.BalanceInsufficient);
|
||||
}
|
||||
log.debug("assets found and balance is ok. am*b.id={}, am*t.id={}, am*f.id={}",
|
||||
assets.get().am_b().getId(), assets.get().am_t().getId(), assets.get().am_f().getId());
|
||||
assetsMng.process(assets.get().am_b(), assets.get().am_t(), assets.get().am_f(), amount.negate());
|
||||
SDf54 sDf54 = sdf54Creator.create(pmt);
|
||||
Long sdf54Id = idGenerator.nextId();
|
||||
sDf54.setId(sdf54Id);
|
||||
sDf54.setGenerationId(sdf54Id);
|
||||
sDf54.setId(idGenerator.nextId());
|
||||
sDf54.setGenerationId(pmt.getId());
|
||||
sdf54Imdg.insert(sDf54);
|
||||
log.debug("new sdf54.id: {}", sDf54.getId());
|
||||
SdfClearingRequest exp = new SdfClearingRequest();
|
||||
exp.setGroupId(sdf54Id);
|
||||
exp.setGroupId(sDf54.getGenerationId());
|
||||
kafkaSender.sendRequestToQueue(Consts.SDF54_PROCESS, exp);
|
||||
return success(req.getId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import ru.spcex.platform.imdg.validation.ImdgValidationContext;
|
|||
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum PaymentOutboundValidationRule implements IValidationRule<ImdgValidationContext<PIClearingOutbondActionNewRequest>> {
|
||||
|
|
@ -29,6 +30,9 @@ public enum PaymentOutboundValidationRule implements IValidationRule<ImdgValidat
|
|||
if (pmtOut.getCreditLeg_amount() == null) {
|
||||
return of(ClearingError.RequiredFieldEmpty, "creditLeg_amount");
|
||||
}
|
||||
if (pmtOut.getCreditLeg_amount().compareTo(BigDecimal.ZERO) < 0) {
|
||||
return of(ClearingError.WrongFieldValue, "creditLeg_amount");
|
||||
}
|
||||
if (pmtOut.getCreditLeg_accountId() == null) {
|
||||
return of(ClearingError.RequiredFieldEmpty, "creditLeg_accountId");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public enum Sdf10ValidationRule implements IValidationRule<ImdgValidationContext
|
|||
Map.of("depoAccountId", account.getId())
|
||||
);
|
||||
if (tcr == null) {
|
||||
return of(ClearingError.TCRegistryNotFound, "<moneyAccountId = " + account.getId() + ">");
|
||||
return of(ClearingError.TCRegistryNotFound, "<depoAccountId = " + account.getId() + ">");
|
||||
}
|
||||
context.storeObject(ValidationStored.Sdf10Tcr, tcr);
|
||||
return empty();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
package ru.spcex.clearing.service.validation;
|
||||
|
||||
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.Registry;
|
||||
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
|
||||
import ru.clearing.classes.statics.data.sdf.SDf20;
|
||||
import ru.spcex.clearing.error.ClearingError;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.service.RegistryManager;
|
||||
import ru.spcex.platform.enumeration.AccountType;
|
||||
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.text.TextUtil;
|
||||
import ru.spcex.platform.utils.validation.IValidationRule;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static ru.spcex.platform.enumeration.RegistryTradingParams.AS_T;
|
||||
import static ru.spcex.platform.enumeration.RegistryTradingParams.DS_T;
|
||||
|
||||
public enum Sdf20ValidationRule implements IValidationRule<ImdgValidationContext<SDf20>> {
|
||||
AccountPresent() {
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<SDf20> context) {
|
||||
SDf20 sdf20 = context.getValidatedObject();
|
||||
String depoCodeCl = sdf20.getDepoCodeCl();
|
||||
if (TextUtil.isEmpty(depoCodeCl)) {
|
||||
return of(ClearingError.AccountNotFoundB, depoCodeCl);
|
||||
}
|
||||
Imdg<Account> accImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
|
||||
Account acc = accImdg.getFirstObjectBySQL("account = '%s' and accountType = '%s'"
|
||||
.formatted(depoCodeCl, AccountType.Clrn.getKey()));
|
||||
if (acc == null) {
|
||||
return of(ClearingError.AccountNotFoundB, depoCodeCl);
|
||||
}
|
||||
context.storeObject(ValidationStored.Sdf20Account, acc);
|
||||
return empty();
|
||||
}
|
||||
},
|
||||
CompanyPresent() {
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<SDf20> context) {
|
||||
Account acc = context.getStoredObject(ValidationStored.Sdf20Account);
|
||||
if (acc == null) {
|
||||
return of(ClearingError.CompanyNotFoundB, "<no account to search by>");
|
||||
}
|
||||
if (acc.getCompanyId() == null) {
|
||||
return of(ClearingError.CompanyNotFoundB, "<account.id=" + acc.getId() + " companyId is empty>");
|
||||
}
|
||||
Imdg<Company> cmpImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
|
||||
Company company = cmpImdg.getSingleObjectByID(acc.getCompanyId());
|
||||
if (company == null) {
|
||||
return of(ClearingError.CompanyNotFoundB, acc.getCompanyId());
|
||||
}
|
||||
context.storeObject(ValidationStored.Sdf20Company, company);
|
||||
return empty();
|
||||
}
|
||||
},
|
||||
TCRPresent() {
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<SDf20> context) {
|
||||
Account acc = context.getStoredObject(ValidationStored.Sdf20Account);
|
||||
if (acc == null) {
|
||||
return of(ClearingError.TCRegistryNotFound, "<no account to search by>");
|
||||
}
|
||||
Imdg<TradingClearingRegistry> tcrImdg = context.obtainMap(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
|
||||
TradingClearingRegistry tcr = tcrImdg.getFirstObjectByFieldValues(
|
||||
Map.of("depoAccountId", acc.getId())
|
||||
);
|
||||
if (tcr == null) {
|
||||
return of(ClearingError.TCRegistryNotFound, "<depoAccountId = " + acc.getId() + ">");
|
||||
}
|
||||
context.storeObject(ValidationStored.Sdf20Tcr, tcr);
|
||||
return empty();
|
||||
}
|
||||
},
|
||||
DS_TFound() {
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<SDf20> context) {
|
||||
SDf20 sDf20 = context.getValidatedObject();
|
||||
String inDocument = sDf20.getInDocument();
|
||||
String security = sDf20.getSecurity();
|
||||
Account acc = context.getStoredObject(ValidationStored.Sdf20Account);
|
||||
if (TextUtil.isEmpty(inDocument) || TextUtil.isEmpty(security) || acc == null) {
|
||||
return of(ClearingError.RecordNotFound, "DS*T");
|
||||
}
|
||||
Imdg<Registry> rgsImdg = context.obtainMap(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||
RegistryManager rgsMng = new RegistryManager(rgsImdg);
|
||||
Optional<Registry> ds_t = rgsMng.searchByAccSecContract(acc.getId(), security, inDocument, DS_T);
|
||||
if (ds_t.isEmpty()) {
|
||||
return of(ClearingError.RecordNotFound, "DS*T");
|
||||
}
|
||||
context.storeObject(ValidationStored.Sdf20Dst, ds_t.get());
|
||||
return empty();
|
||||
}
|
||||
},
|
||||
AS_TFound() {
|
||||
@Override
|
||||
public Optional<EnumMessage> validate(ImdgValidationContext<SDf20> context) {
|
||||
SDf20 sDf20 = context.getValidatedObject();
|
||||
String inDocument = sDf20.getInDocument();
|
||||
String security = sDf20.getSecurity();
|
||||
Account acc = context.getStoredObject(ValidationStored.Sdf20Account);
|
||||
if (TextUtil.isEmpty(inDocument) || TextUtil.isEmpty(security) || acc == null) {
|
||||
return of(ClearingError.RecordNotFound, "AS*T");
|
||||
}
|
||||
Imdg<Registry> rgsImdg = context.obtainMap(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||
RegistryManager rgsMng = new RegistryManager(rgsImdg);
|
||||
Optional<Registry> as_t = rgsMng.searchByAccSecContract(acc.getId(), security, inDocument, AS_T);
|
||||
if (as_t.isEmpty()) {
|
||||
return of(ClearingError.RecordNotFound, "AS*T");
|
||||
}
|
||||
context.storeObject(ValidationStored.Sdf20Ast, as_t.get());
|
||||
return empty();
|
||||
}
|
||||
}
|
||||
;
|
||||
private final static Logger log = LoggerFactory.getLogger(Sdf20ValidationRule.class);
|
||||
@Override
|
||||
public String ruleName() {
|
||||
return "Sdf20ValidationRule." + name();
|
||||
}
|
||||
}
|
||||
|
|
@ -22,5 +22,7 @@ public enum ValidationStored {
|
|||
|
||||
CompanyByTradingCode,
|
||||
|
||||
Sdf20Account, Sdf20Company, Sdf20Tcr, Sdf20Dst, Sdf20Ast,
|
||||
|
||||
SecurityBySecurityCode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import ru.spcex.platform.utils.time.TimeUtil;
|
|||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
|
|
@ -43,8 +42,7 @@ public class SDf20MapStore extends TemplateMapStore<SDf20> {
|
|||
log.debug("loadAllKeys from " + getTableName());
|
||||
List<Long> keys;
|
||||
try {
|
||||
keys = jdbcTemplate.query("select id from " + getTableName() + " where cast(generation_time as date) = ?",
|
||||
new Object[]{LocalDate.now()},
|
||||
keys = jdbcTemplate.query("select id from " + getTableName(),
|
||||
(resultSet, i) -> resultSet.getLong("id"));
|
||||
} catch (Throwable e) {
|
||||
log.error("{}", ExceptionUtils.getStackTrace(e));
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import ru.spcex.platform.utils.time.TimeUtil;
|
|||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
|
|
@ -42,8 +41,7 @@ public class SDf21MapStore extends TemplateMapStore<SDf21> {
|
|||
log.debug("loadAllKeys from " + getTableName());
|
||||
List<Long> keys;
|
||||
try {
|
||||
keys = jdbcTemplate.query("select id from " + getTableName() + " where cast(generation_time as date) = ?",
|
||||
new Object[]{LocalDate.now()},
|
||||
keys = jdbcTemplate.query("select id from " + getTableName(),
|
||||
(resultSet, i) -> resultSet.getLong("id"));
|
||||
} catch (Throwable e) {
|
||||
log.error("{}", ExceptionUtils.getStackTrace(e));
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import ru.spcex.platform.utils.time.TimeUtil;
|
|||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
|
|
@ -42,8 +41,7 @@ public class SDf57MapStore extends TemplateMapStore<SDf57> {
|
|||
log.debug("loadAllKeys from " + getTableName());
|
||||
List<Long> keys;
|
||||
try {
|
||||
keys = jdbcTemplate.query("select id from " + getTableName() + " where cast(generation_time as date) = ?",
|
||||
new Object[]{LocalDate.now()},
|
||||
keys = jdbcTemplate.query("select id from " + getTableName(),
|
||||
(resultSet, i) -> resultSet.getLong("id"));
|
||||
} catch (Throwable e) {
|
||||
log.error("{}", ExceptionUtils.getStackTrace(e));
|
||||
|
|
|
|||
|
|
@ -20,6 +20,20 @@ public class BigDecimalUtil {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* для парсинга вида '-00001234'/'00000123'
|
||||
* @param number
|
||||
* @return
|
||||
*/
|
||||
public static BigDecimal parseLeadingZeroes(String number) {
|
||||
try {
|
||||
return new BigDecimal(number);
|
||||
} catch (Throwable e) {
|
||||
//оставил чтобы стукнул NLP если где-то окажется неровный формат чтобы уточнить поведение
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Для кейсов когда есть String поле с десятичной частью, и хотим ограничить число знаков после запятой
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue