NotificationSender objectType

Sdf57/Sdf01 revise notification comment & objectType
PaymentStateMarkService valueDate/settlementDate conditions
AnltSearcher comment TCR 12 symbols
planBalance revise notification comment
session step 7 fix
session step 5 gateway request only for OK groups
session step 5 deposit return A**B change on receiver side
clearingDate today on POOL
PaymentInstruction paymentPurpose fix
This commit is contained in:
ialbert 2023-10-05 17:40:26 +03:00
parent 7a359c1d98
commit 7e2e9dcd51
13 changed files with 109 additions and 46 deletions

View file

@ -22,7 +22,7 @@ public class NotificationSender {
public void sendNotification(ObjectType objType, String comment, Priority priority) {
NotificationNewRequest reviseNotification = new NotificationNewRequest();
reviseNotification.setObjectType(ObjectType.rgst.getKey());
reviseNotification.setObjectType(objType.getKey());
reviseNotification.setComment(comment);
reviseNotification.setPriority(priority.getKey());
kafkaSender.sendRequestToQueue(Consts.NOTIFICATION_NEW, reviseNotification);

View file

@ -17,6 +17,10 @@ import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IEnumId;
import ru.spcex.platform.utils.text.TextUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
public class AnltSearcher {
@ -83,25 +87,19 @@ public class AnltSearcher {
return new AnltSearch(infoAcc, company, tcr);
}
private static final Pattern tcrPattern = Pattern.compile("ТКР.*?([0-9A-Z-]{12})");
private static String getTkrCodeFromComment(String comment) {
if (comment == null) {
if (TextUtil.isEmpty(comment)) {
return null;
}
comment = comment.toUpperCase();
int tcrIndex = comment.indexOf("ТКР");
if (tcrIndex == -1) {
return null;
}
if (comment.length() < (tcrIndex + 4)) {
return null;
}
int spaceAfterTCR = comment.indexOf(" ", tcrIndex + 4);
if (spaceAfterTCR == -1) {
comment = comment.substring(tcrIndex + 4);
Matcher matcher = tcrPattern.matcher(comment);
if (matcher.find()) {
return matcher.group(1);
} else {
comment = comment.substring(tcrIndex + 4, spaceAfterTCR);
return null;
}
return comment.replaceAll("\\s+", "");
}
public static class AnltSearch {

View file

@ -25,8 +25,8 @@ import java.util.Optional;
@Component
public class Reviser {
private final Logger log = LoggerFactory.getLogger(Reviser.class);
private static final String reviseFailedMessage = "Сверка остатков денежных средств по результатам клиринговой сессии завершена с ошибками.";
private static final String reviseSuccessMessage = "Сверка остатков денежных средств по результатам клиринговой сессии завершена успешно.";
private static final String reviseFailedMessage = "После сверки обнаружена разница между сверочным и фактическим балансом.";
private static final String reviseSuccessMessage = "Ошибок после получения остатков не обнаружено.";
private final Imdg<Registry> registryImdg;
private final Imdg<Statement> statementImdg;
private final Imdg<SDf01> sdf01Imdg;
@ -66,7 +66,7 @@ public class Reviser {
log.trace("revise ok for sdf01.id={}, stmt.id={}, registry.id={}", sdf.getId(), statement.get().getId(), registry.get().getId());
}
NotificationNewRequest reviseNotification = new NotificationNewRequest();
reviseNotification.setObjectType(ObjectType.rgst.getKey());
reviseNotification.setObjectType(ObjectType.diff.getKey());
reviseNotification.setComment(reviseFailed ? reviseFailedMessage : reviseSuccessMessage);
reviseNotification.setPriority(reviseFailed ? Priority.HIGH.getKey() : Priority.LOW.getKey());
kafkaSender.sendRequestToQueue(Consts.NOTIFICATION_NEW, reviseNotification);

View file

@ -115,7 +115,7 @@ public class AssetTBFProcessing {
}
}
public void processByAm_f(Registry am_f, BigDecimal sum) {
public Optional<AssetTrio> processByAm_f(Registry am_f, BigDecimal sum) {
Optional<Registry> am_b = rgsMng.findRegByUnit(am_f.getCompanyId(),
am_f.getAccountId(),
am_f.getContract(),
@ -128,6 +128,9 @@ public class AssetTBFProcessing {
RegistryUnit.T);
if (am_b.isPresent() && am_t.isPresent()) {
process(am_b.get(), am_t.get(), am_f, sum);
return Optional.of(new AssetTrio(am_f, am_b.get(), am_t.get()));
} else {
return Optional.empty();
}
}

View file

@ -54,6 +54,9 @@ public class PaymentStateMarkService {
Collection<Registry> claimsAndLiabilities = rgsImdg.getCollectionObjectsByPredicate(prdct);
Map<Long, List<Registry>> groups = claimsAndLiabilities
.stream()
.filter(rgs -> rgs.getValueDate() != null)
.filter(rgs -> rgs.getSettlementDate() != null)
.filter(rgs -> rgs.getSettlementDate().isAfter(rgs.getValueDate()))
.collect(Collectors.groupingBy(Registry::getGroupId));
log.debug("found {} ({} groups) CM*T/LM*T by {}", claimsAndLiabilities.size(), groups.size(), prdct.toString());
for (Map.Entry<Long, List<Registry>> group : groups.entrySet()) {

View file

@ -166,7 +166,7 @@ public class BalanceRevise implements ISessionStage {
NotificationNewRequest nRequest = new NotificationNewRequest();
nRequest.setObjectType(ObjectType.rgst.getKey());
nRequest.setPriority(Priority.HIGH.getKey());
nRequest.setComment("После сверки обнаружена разница между плановым и фактическим балансом");
nRequest.setComment("Сверка по результатам клиринговой сессии завершена с ошибками.");
kafkaSender.sendRequestToQueue(Consts.NOTIFICATION_NEW, nRequest);
return new StageResult<>(new EnumMessage(ClearingError.PlanBalanceReviseError), false);
} else {

View file

@ -156,12 +156,6 @@ public class FormingPaymentInstructionAssets implements ISessionStage {
for (Registry registry : AMBregistries) {
//по каждому AMB регистру создаем PaymentInstruction
//проверяем balance посчитанный на шаге 5
if (registry.getBalance().compareTo(BigDecimal.ZERO) == 0) {
log.debug("Skip creating paymentInstruction by registry with 0 balance");
continue;
}
boolean isPositiveBalance = registry.getBalance().compareTo(BigDecimal.ZERO) > 0;
Account counterAcc = null;
if (AccountType.Clrn.equalsByKey(registry.getAccountType())) {
counterAcc = accountImdg.getSingleObjectByID(registry.getAccountId());
@ -176,12 +170,16 @@ public class FormingPaymentInstructionAssets implements ISessionStage {
Account debitLegAccount;
Account creditLegAccount;
BigDecimal amount;
amount = safeBD(registry.getBalance()).add(adjustAmountByReturns(registry, sessionId));
boolean isPositiveBalance = amount.compareTo(BigDecimal.ZERO) > 0;
if (amount.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
if (isPositiveBalance) {
senderId = registry.getCompanyId();
addresseeId = Sender.One.getId();
debitLegAccount = tranAcc;
creditLegAccount = counterAcc;
amount = registry.getBalance() == null ? null : registry.getBalance().abs();
Optional<Registry> payerAmtO = rgsMng.findRelatedAsset(
registry.getTradingClearingRegistryId(),
registry.getCompanyId(),
@ -196,7 +194,6 @@ public class FormingPaymentInstructionAssets implements ISessionStage {
addresseeId = registry.getCompanyId();
debitLegAccount = counterAcc;
creditLegAccount = tranAcc;
amount = registry.getBalance() == null ? null : registry.getBalance().abs();
Optional<Registry> payerAmtO = rgsMng.findRelatedAsset(
registry.getTradingClearingRegistryId(),
registry.getCompanyId(),
@ -208,6 +205,7 @@ public class FormingPaymentInstructionAssets implements ISessionStage {
setUpdatedStoreInImdg(amt, now);
});
}
amount = amount.abs();
PaymentInstructionBuilderV2 paymentInstructionBuilder = PaymentInstructionBuilderV2.builder(imdgProvider)
.registry(registry)
@ -311,6 +309,41 @@ public class FormingPaymentInstructionAssets implements ISessionStage {
return stageResult;
}
private BigDecimal adjustAmountByReturns(Registry amb, Long sessionId) {//companyid, tcr/account, sessionId, RUB
Long companyId = amb.getCompanyId();
Long tradingClearingRegistryId = amb.getTradingClearingRegistryId();
ImdgPredicateBuilder pb = registryImdg.predicateBuilder();
ImdgPredicate cL = pb.and(
pb.equals("companyId", companyId),
pb.equals("tradingClearingRegistryId", tradingClearingRegistryId),
pb.equals("registryStatus", RegistryStatus.OK.getKey()),
pb.equals("sessionId", sessionId),
pb.or(
pb.sql(RegistryCodeSqlBuilder.getInstance(LM_T).build()),
pb.sql(RegistryCodeSqlBuilder.getInstance(CM_T).build())
)
);
BigDecimal reduce = registryImdg.getCollectionObjectsByPredicate(cL)
.stream()
.filter(rgs -> rgs.getValueDate() != null)
.filter(rgs -> rgs.getSettlementDate() != null)
.filter(rgs -> rgs.getSettlementDate().isAfter(rgs.getValueDate()))
.map(rgs -> {
if (RegistryDesignation.C.equalsByKey(rgs.getRegistryDesignation())) {
return rgs.getBalance();
} else {
return rgs.getBalance().abs().negate();
}
})
.reduce(BigDecimal.ZERO, BigDecimal::add);
log.debug("{}.id={} {} adjust value {}",
amb.getRegistryCode(),
amb.getId(),
cL,
reduce);
return reduce;
}
private void setUpdatedStoreInImdg(Registry rgs, Instant now) {
rgs.setUpdated(now);

View file

@ -223,6 +223,7 @@ public class FormingPaymentInstructionDepositReturn implements ISessionStage {
.tranAcc(tranAcc)
.sessionId(sessionId)
.paymentPurpose("Возврат депозита " + cm_t.getContract() + " по ТКР " + cm_t.getTradingClearingRegistry())
.paymentPurposeLmt("Возврат депозита " + lm_t.getContract() + " по ТКР " + lm_t.getTradingClearingRegistry())
.build();
paymentInstructionImdg.insert(pmts.getFirst());
paymentInstructionImdg.insert(pmts.getSecond());

View file

@ -187,6 +187,7 @@ public class FormingPaymentInstructionReturnMkr implements ISessionStage {
.tranAcc(tranAcc)
.sessionId(sessionId)
.paymentPurpose("Возврат депозита " + cm_t.getContract() + " по ТКР " + cm_t.getTradingClearingRegistry())
.paymentPurposeLmt("Возврат депозита " + lm_t.getContract() + " по ТКР " + lm_t.getTradingClearingRegistry())
.build();
paymentInstructionImdg.insert(pmts.getFirst());
paymentInstructionImdg.insert(pmts.getSecond());

View file

@ -109,7 +109,8 @@ public class InclusionObligations implements ISessionStage {
for (Map.Entry<Long, List<Registry>> entrySet : registryByGroupId.entrySet()) {
log.debug("Processing set of registry with groupId: {}", entrySet.getKey());
for (Registry registry : entrySet.getValue()) {
registry.setRegistryStatus("POOL");
registry.setRegistryStatus(RegistryStatus.POOL.getKey());
registry.setClearingDate(LocalDate.now());
registry.setSessionId(sessionId);
obtainSessionType(sessionId).ifPresent(st -> registry.setSessionType(st.getKey()));
registryImdg.update(registry);

View file

@ -134,18 +134,6 @@ public class InspectionObligations implements ISessionStage {
}
Optional<Registry> omt = group.stream().filter(rgs -> RegistryManager.equalsByCode(OM_T, rgs)).findFirst();
if (SessionType.FINL.equals(sessionType) && tradingTimeService.isTradingTime() && omt.isPresent()) {
Optional<Boolean> gatewayReceived = gateway.gatewayRequestAndWait(() -> GatewayRequestCreator.from(omt.get()));
if (gatewayReceived.isEmpty()) {
log.error("Gateway not received response for groupId: {}. ", entry.getKey());
}
if (!gatewayReceived.orElse(false)) {
checkResults.stream()
.filter(chk -> chk.registry().getId().equals(omt.get().getId()))
.findFirst()
.ifPresent(chk -> chk.isUncovered = true);
}
}
for (Registry rgs : group) {
Runnable failGroup = () -> Stream.concat(group.stream(), getRefundDateRgsIfPresent(group).stream())
.forEach(registry -> {
@ -170,6 +158,21 @@ public class InspectionObligations implements ISessionStage {
continue GROUP;
}
}
if (SessionType.FINL.equals(sessionType)
&& omt.isPresent()
&& checkResults.stream().noneMatch(checkResult -> checkResult.isUncovered)
&& tradingTimeService.isTradingTime()) {
Optional<Boolean> gatewayReceived = gateway.gatewayRequestAndWait(() -> GatewayRequestCreator.from(omt.get()));
if (gatewayReceived.isEmpty()) {
log.error("Gateway not received response for groupId: {}. ", entry.getKey());
}
if (!gatewayReceived.orElse(false)) {
checkResults.stream()
.filter(chk -> chk.registry().getId().equals(omt.get().getId()))
.findFirst()
.ifPresent(chk -> chk.isUncovered = true);
}
}
defineStatusAndUpdateRegistry(checkResults, group);
if (checkResults.stream().noneMatch(checkResult -> checkResult.isUncovered)) {
Instant now = Instant.now();

View file

@ -9,6 +9,7 @@ import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.service.AssetTrio;
import ru.spcex.clearing.service.integration.GatewayRequestCreator;
import ru.spcex.clearing.service.registry.AssetTBFProcessing;
import ru.spcex.clearing.service.registry.RegistryManager;
@ -28,6 +29,7 @@ import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import static ru.spcex.platform.enumeration.RegistryTradingParams.*;
@ -102,12 +104,14 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
for (Map.Entry<Long, List<Registry>> entry : registriesByGroupSorted) {
List<Registry> group = entry.getValue();
Optional<Registry> omtInGroupO = group.stream().filter(registry -> equalByRgs(OM_T, registry)).findFirst();
if (omtInGroupO.isEmpty()) {
log.error("groupId {} failed to find OM*T registry", entry.getKey());
Optional<Registry> tmtInGroupO = group.stream().filter(registry -> equalByRgs(TM_T, registry)).findFirst();
if (omtInGroupO.isEmpty() || tmtInGroupO.isEmpty()) {
log.error("groupId {} failed to find OM*T/TM*T registry", entry.getKey());
group.forEach(rgs -> updateStatus(rgs, registryStatusFailed())); // FAIL or MNG
continue;
}
Registry omtRgs = omtInGroupO.get();
Registry tmtRgs = tmtInGroupO.get();
log.debug("groupId={}, OM*T.id={}", entry.getKey(), omtRgs.getId());
BigDecimal omtBalance = safeBD(omtRgs.getBalance());
@ -139,15 +143,28 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
}
Optional<Registry> amfAssetO = searchAssetByOMT(omtRgs);
Optional<Registry> amfAssetReceiverO = searchAssetByOMT(tmtRgs);
if (amfAssetO.isEmpty()) {
log.error("OM*T register.id={} groupId={} failed to find AM*F asset", omtRgs.getId(), entry.getKey());
group.forEach(rgs -> updateStatus(rgs, registryStatusFailed())); // FAIL or MNG
continue;
}
if (amfAssetReceiverO.isEmpty()) {
log.error("TM*T register.id={} groupId={} failed to find AM*F asset", tmtRgs.getId(), entry.getKey());
group.forEach(rgs -> updateStatus(rgs, registryStatusFailed())); // FAIL or MNG
continue;
}
Registry amfAsset = amfAssetO.get();
log.debug("groupId={}, AM*F.id={}", entry.getKey(), amfAsset.getId());
BigDecimal amfBalance = safeBD(amfAsset.getBalance());
BiConsumer<Registry, BigDecimal> processAssetsAndSetSessionId = (amf, amount) -> {
Optional<AssetTrio> asts = assets.processByAm_f(amf, amount);
if (asts.isPresent()) {
asts.get().a__b().setSessionId(sessionId);
registryImdg.update(asts.get().a__b());
}
};
Optional<Registry> dmtInfo = rgsMng.searchDmtInfo(omtRgs);
if (dmtInfo.isPresent()) {
BigDecimal dmtBalance = safeBD(dmtInfo.get().getBalance());
@ -158,7 +175,8 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
);
if (dmtBalance.compareTo(omtBalance) >= 0 && amfBalance.compareTo(omtBalance) >=0) {
group.forEach(rgs -> updateStatus(rgs, RegistryStatus.OK));
assets.processByAm_f(amfAsset, omtBalance.negate());
processAssetsAndSetSessionId.accept(amfAsset, omtBalance.negate());
processAssetsAndSetSessionId.accept(amfAssetReceiverO.get(), omtBalance);
// updateStatus(dmtInfo.get(), RegistryStatus.POOL);
continue;
} else if (SessionType.XDEP.equals(sessionType)) {
@ -177,7 +195,8 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
);
if (dmtBalance.compareTo(omtBalance) >= 0 && amfBalance.compareTo(omtBalance) >= 0) {
group.forEach(rgs -> updateStatus(rgs, RegistryStatus.OK));
assets.processByAm_f(amfAsset, omtBalance.negate());
processAssetsAndSetSessionId.accept(amfAsset, omtBalance.negate());
processAssetsAndSetSessionId.accept(amfAssetReceiverO.get(), omtBalance);
continue;
} else if (SessionType.XDEP.equals(sessionType)) {
group.forEach(rgs -> updateStatus(rgs, registryStatusFailed(rgs)));
@ -193,7 +212,8 @@ public class InspectionObligationsDepositReturn implements ISessionStage {
"FINL, initiator.category='V' and am*f > om*t: setting OK status to group",
omtRgs.getId());
group.forEach(rgs -> updateStatus(rgs, RegistryStatus.OK));
assets.processByAm_f(amfAsset, omtBalance.negate());
processAssetsAndSetSessionId.accept(amfAsset, omtBalance.negate());
processAssetsAndSetSessionId.accept(amfAssetReceiverO.get(), omtBalance);
} else {
log.info("OM*T.id={} -> no DM*X/DM*T(INFO/CLRN) registry found. setting {} status to group",
omtRgs.getId(), registryStatusFailed());

View file

@ -4,7 +4,7 @@ import ru.spcex.platform.utils.enumeration.IEnumKey;
public enum ObjectType implements IEnumKey {
statement("STMT"), vfrs("VFRS"), rgst("RGST"), gateway("GTWY"), session("SESN"),
account_block("ACCB"), account_active("ACCA");
account_block("ACCB"), account_active("ACCA"), diff("DIFF");
private final String key;