ialbert 2023-01-31 20:09:27 +03:00
parent 7647a0ff5b
commit 2363c3362c
5 changed files with 223 additions and 1 deletions

View file

@ -0,0 +1,61 @@
package ru.spcex.clearing.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.clearing.classes.statics.data.execution.ExecutionDeposit;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.service.validation.ClrngValidationStored;
import ru.spcex.clearing.service.validation.ExecutionDepositValidationRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@Configuration
public class ValidationConfig {
private final Map<String, Imdg<? extends SpcexObjectBase>> imdgs;
public ValidationConfig(ImdgProvider imdgProvider) {
this.imdgs = new HashMap<>();
BiConsumer<String, Class<? extends SpcexObjectBase>> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass));
addImdg.accept(IMDGDistributedNames.Map_Relation, Relation.class);
addImdg.accept(IMDGDistributedNames.Map_Company, Company.class);
}
/**
* чтобы во всех валидаторах был один экземпляр Imdg
*/
private Imdg<?> getImdg(String key) {
return imdgs.get(key);
}
private final BiConsumer<ImdgValidationContext<?>, String> addImdg = (context, s)
-> context.addImdg(s, getImdg(s));
@Bean("executionDepositValidator")
public BiFunction<ClearingCategory, ExecutionDeposit, IValidator> executionDepositValidator() {
return (category, execDeposit) -> {
ImdgValidationContext<ExecutionDeposit> context = new ImdgValidationContext<>();
context.setValidatedObject(execDeposit);
context.storeObject(ClrngValidationStored.categoryPredefined, category);
addImdg.accept(context, IMDGDistributedNames.Map_Relation);
addImdg.accept(context, IMDGDistributedNames.Map_Company);
return new ValidatorImpl<>(context,
ExecutionDepositValidationRule.ClearingIsAllowed,
ExecutionDepositValidationRule.AccountIsNotBlocked,
ExecutionDepositValidationRule.CompanyIsNotBlocked,
ExecutionDepositValidationRule.FinancialObligationSecurity);
};
}
}

View file

@ -0,0 +1,21 @@
package ru.spcex.clearing.error;
import ru.spcex.platform.utils.enumeration.IEnumId;
public enum ClearingErrorInternal implements IEnumId {
ClearingNotAllowed(1L),
AccountNotActive(2L),
CompanyNotActive(3L),
FinancialObligationNotSatisfied(4L),
;
private final Long id;
ClearingErrorInternal(Long id) {
this.id = id;
}
@Override
public Long getId() {
return id;
}
}

View file

@ -1,30 +1,44 @@
package ru.spcex.clearing.service;
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.execution.ExecutionDeposit;
import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
import ru.spcex.clearing.error.ClearingErrorInternal;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.service.order.ExecutionDepositSorter;
import ru.spcex.platform.enumeration.Allowed;
import ru.spcex.platform.enumeration.ClearingCategory;
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.validation.IValidator;
import java.time.Instant;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
@Service
public class Clearing {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<ExecutionDeposit> executionDepositImdg;
private final Imdg<ClearingMemberCategory> clearingCategoryImdg;
private final ExecutionDepositSorter sorter;
private final BiFunction<ClearingCategory, ExecutionDeposit, IValidator> validation;
@Autowired
public Clearing(ImdgProvider imdgProvider, ExecutionDepositSorter sorter) {
public Clearing(ImdgProvider imdgProvider,
ExecutionDepositSorter sorter,
BiFunction<ClearingCategory, ExecutionDeposit, IValidator> validation) {
this.executionDepositImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionDeposit, ExecutionDeposit.class);
this.clearingCategoryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
this.sorter = sorter;
this.validation = validation;
}
public void startClearing() {
@ -41,6 +55,37 @@ public class Clearing {
}
private void processSingleCompany(ClearingCategory category, List<ExecDepositWCategory> executionDeposits) {
log.info("Start clearing for category: {}, company: {}", category, executionDeposits.get(0).getCompanyId());
boolean financialError = false;
for (ExecDepositWCategory execDepositWrapper : executionDeposits) {
ExecutionDeposit execDeposit = execDepositWrapper.getExecutionDeposit();
if (financialError) {
updateDenied(execDeposit);
continue;
}
IValidator validator = validation.apply(category, execDeposit);
Optional<EnumMessage> errorMsg = validator.tillFirstError();
if (errorMsg.isPresent() && !ClearingErrorInternal.FinancialObligationNotSatisfied.equals(errorMsg.get().getSubject())) {
updateDenied(execDeposit);
continue;
} else if (errorMsg.isPresent()) {
financialError = true;
updateDenied(execDeposit);
continue;
}
updateAllowed(execDeposit);
}
}
private void updateDenied(ExecutionDeposit execDeposit) {
execDeposit.setCoverageStatus(Allowed.DENIED.getKey());
execDeposit.setUpdated(Instant.now());
executionDepositImdg.update(execDeposit);
}
private void updateAllowed(ExecutionDeposit execDeposit) {
execDeposit.setCoverageStatus(Allowed.ALLOWED.getKey());
execDeposit.setUpdated(Instant.now());
executionDepositImdg.update(execDeposit);
}
}

View file

@ -0,0 +1,6 @@
package ru.spcex.clearing.service.validation;
public enum ClrngValidationStored {
relation, categoryPredefined
;
}

View file

@ -0,0 +1,89 @@
package ru.spcex.clearing.service.validation;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.clearing.classes.statics.data.execution.ExecutionDeposit;
import ru.spcex.clearing.error.ClearingErrorInternal;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Map;
import java.util.Optional;
public enum ExecutionDepositValidationRule implements IValidationRule<ImdgValidationContext<ExecutionDeposit>> {
ClearingIsAllowed() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<ExecutionDeposit> context) {
ExecutionDeposit validatedObject = context.getValidatedObject();
Imdg<Relation> relationImdg = context.obtainMap(IMDGDistributedNames.Map_Relation, Relation.class);
Relation relation = relationImdg.getSingleObjectByFieldValues(Map.of("consumerId", validatedObject.getCompanyId()));
if (relation == null || !ServiceStatus.Active.equalsByKey(relation.getServiceStatus())) {
return of(ClearingErrorInternal.ClearingNotAllowed);
}
context.storeObject(ClrngValidationStored.relation, relation);
return empty();
}
},
AccountIsNotBlocked() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<ExecutionDeposit> context) {
ExecutionDeposit validatedObject = context.getValidatedObject();
Imdg<Account> accountImdg = context.obtainMap(IMDGDistributedNames.Map_Account, Account.class);
Relation relation = context.getStoredObject(ClrngValidationStored.relation);
Account account = accountImdg.getSingleObjectByFieldValues(
Map.of("id", validatedObject.getAccountId(), "relationId", relation.getId()));
if (account == null || !AccountStatus.ACTIVE.equalsByKey(account.getAccountStatus())) {
return of(ClearingErrorInternal.AccountNotActive);
}
return empty();
}
},
CompanyIsNotBlocked() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<ExecutionDeposit> context) {
ExecutionDeposit validatedObject = context.getValidatedObject();
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
Company company = companyImdg.getSingleObjectByFieldValues(Map.of("id", validatedObject.getCompanyId()));
if (company == null || !WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) {
return of(ClearingErrorInternal.CompanyNotActive);
}
return empty();
}
},
FinancialObligationSecurity() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<ExecutionDeposit> context) {
ClearingCategory category = context.getStoredObject(ClrngValidationStored.categoryPredefined);
if (!category.equals(ClearingCategory.V)) {
return Optional.empty();
}
ExecutionDeposit validatedObject = context.getValidatedObject();
Imdg<AccountBalance> accountBalanceImdg = context.obtainMap(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);
AccountBalance accountBalance = accountBalanceImdg.getSingleObjectByFieldValues(
Map.of("accountId", validatedObject.getAccountId(),
"companyId", validatedObject.getCompanyId()));
if (accountBalance == null) {
return of(ClearingErrorInternal.FinancialObligationNotSatisfied);
}
//todo ABS
if (validatedObject.getFirstLegAmount().compareTo(accountBalance.getFreeBalanceAmount()) > 0) {
return of(ClearingErrorInternal.FinancialObligationNotSatisfied);
}
return empty();
}
};
@Override
public String ruleName() {
return "Sdf09ValidationRule." + name();
}
}