SDF55
SDF10 в DS*T#contract кладется sdf10.outDocument а не sdf11.outDocument
блокировки в PaymentInstructionOutboundService
imdg SDf20/SDf21/SDf57 выгружаются за все дни
This commit is contained in:
ialbert 2023-08-18 19:33:46 +03:00
parent 64e6f932bc
commit 334a91fb81
19 changed files with 455 additions and 34 deletions

View file

@ -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);

View file

@ -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();

View file

@ -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) {
}

View file

@ -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())

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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());
}

View file

@ -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");
}

View file

@ -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();

View file

@ -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();
}
}

View file

@ -22,5 +22,7 @@ public enum ValidationStored {
CompanyByTradingCode,
Sdf20Account, Sdf20Company, Sdf20Tcr, Sdf20Dst, Sdf20Ast,
SecurityBySecurityCode
}

View file

@ -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));

View file

@ -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));

View file

@ -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));

View file

@ -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 поле с десятичной частью, и хотим ограничить число знаков после запятой
*/