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:
parent
7a359c1d98
commit
7e2e9dcd51
13 changed files with 109 additions and 46 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue