Merge branch 'dev' into CLS-277-execution-deposit

# Conflicts:
#	platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java
This commit is contained in:
ialbert 2023-05-11 12:23:28 +03:00
commit 837485e96e
66 changed files with 3322 additions and 291 deletions

View file

@ -6,10 +6,11 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.util.services.IMDGMessageResolver;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.platform.enumeration.UserRole;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.clearing.util.services.IMDGMessageResolver;
@Configuration
public class BeanConfiguration {
@ -18,6 +19,12 @@ public class BeanConfiguration {
return new IMDGMessageResolver(imdgProvider);
}
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RequestHelper requestHelper(IMessageResolver messageResolver) {
return new RequestHelper(messageResolver, AccountError.GeneralError);
}
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public UserRoleVerification userRoleVerification(ImdgProvider imdgProvider, IMessageResolver messageResolver) {

View file

@ -5,18 +5,19 @@ import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.platform.dictionary.AccountTypeDictionary;
import ru.clearing.platform.dictionary.ServiceStatusDictionary;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.CorrespondentAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.CorrespondentAccountUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.EnumPresentRule;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
@ -45,6 +46,7 @@ public class AccountValidationConfig {
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Company);
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary);
addImdg.accept(IMDGDistributedNames.Map_AccountTypeDictionary);
return new ValidatorImpl<>(context,
IdPresentRule.instance("companyId",
@ -69,12 +71,15 @@ public class AccountValidationConfig {
if (accounts.isEmpty()) return null;
return AccountError.AccountAlreadyExist;
}),
FieldRequiredRule.instance("status",
DictionaryPresentRule.instance("status",
CorrespondentAccountNewRequest::getStatus,
IMDGDistributedNames.Map_ServiceStatusDictionary,
ServiceStatusDictionary.class,
AccountError.RequiredFieldEmpty,
AccountError.WrongFieldValue,
false,
statusValue -> {
if (statusValue == null || AccountStatus.ACTIVE.equalsByKey(statusValue)) return null;
if (ServiceStatus.Active.equalsByKey(statusValue.getCode())) return null;
return AccountError.WrongFieldValue;
}),
DictionaryPresentRule.instance("accountType",
@ -127,16 +132,16 @@ public class AccountValidationConfig {
error = Objects.equals(company.getId(), correspondentAccountUpdateRequest.getCompanyId()) ? error : AccountError.WrongFieldValue;
return error;
}),
EnumPresentRule.instance("status",
DictionaryPresentRule.instance("status",
CorrespondentAccountUpdateRequest::getStatus,
AccountStatus.values(),
false,
AccountError.WrongFieldValue,
AccountError.RequiredFieldEmpty),
IMDGDistributedNames.Map_ServiceStatusDictionary,
ServiceStatusDictionary.class,
AccountError.RequiredFieldEmpty,
AccountError.WrongFieldValue),
DictionaryPresentRule.instance("accountType",
CorrespondentAccountUpdateRequest::getAccountType,
IMDGDistributedNames.Map_AccountTypeDictionary,
AccountTypeDictionary.class,
ServiceStatusDictionary.class,
AccountError.RequiredFieldEmpty,
AccountError.WrongFieldValue,
accountType -> {
@ -148,23 +153,23 @@ public class AccountValidationConfig {
}
@Bean("correspondentAccountBlockRequestValidator")
public Function<CommonDeleteRequest, IValidator> correspondentAccountBlockRequestValidator(
public Function<CommonIdRequest, IValidator> correspondentAccountBlockRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return correspondentAccountBlockRequest -> {
ImdgValidationContext<CommonDeleteRequest> context = new ImdgValidationContext<>();
ImdgValidationContext<CommonIdRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(correspondentAccountBlockRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Account);
return new ValidatorImpl<>(context,
IdPresentRule.instance("id",
CommonDeleteRequest::getId,
CommonIdRequest::getId,
IMDGDistributedNames.Map_Account,
Account.class,
AccountError.RequiredFieldEmpty,
AccountError.AccountNotFound,
account -> {
if (AccountStatus.ACTIVE.equalsByKey(account.getStatus())) return null;
if (WorkflowStatus.Active.equalsByKey(account.getStatus())) return null;
return AccountError.AccountNotActive;
})
);

View file

@ -10,13 +10,14 @@ import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
@ -62,7 +63,7 @@ public class BankAccountValidationConfig {
);
ImdgPredicateBuilder pb = accountImdg.predicateBuilder();
ImdgPredicate accountValuePredicate = pb.equals("account", accountValue);
ImdgPredicate accountStatusPredicate = pb.equals("status", AccountStatus.ACTIVE.getKey());
ImdgPredicate accountStatusPredicate = pb.equals("status", ServiceStatus.Active.getKey());
ImdgPredicate accountTypePredicate = pb.equals("accountType", AccountType.Bank.getKey());
ImdgPredicate finalPredicate = pb.and(accountValuePredicate,
accountStatusPredicate,
@ -131,18 +132,18 @@ public class BankAccountValidationConfig {
}
@Bean("bankAccountBlockRequestValidator")
public Function<CommonDeleteRequest, IValidator> bankAccountBlockRequestValidator(
public Function<CommonIdRequest, IValidator> bankAccountBlockRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return bankAccountBlockRequest -> {
ImdgValidationContext<CommonDeleteRequest> context = new ImdgValidationContext<>();
ImdgValidationContext<CommonIdRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(bankAccountBlockRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_BankAccount);
addImdg.accept(IMDGDistributedNames.Map_Account);
return new ValidatorImpl<>(context,
IdPresentRule.instance("id",
CommonDeleteRequest::getId,
CommonIdRequest::getId,
IMDGDistributedNames.Map_BankAccount,
BankAccount.class,
AccountError.RequiredFieldEmpty,

View file

@ -13,8 +13,8 @@ import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
@ -60,7 +60,7 @@ public class ClearingAccountValidationConfig {
);
ImdgPredicateBuilder pb = accountImdg.predicateBuilder();
ImdgPredicate accountValuePredicate = pb.equals("account", accountValue);
ImdgPredicate accountStatusPredicate = pb.equals("status", AccountStatus.ACTIVE.getKey());
ImdgPredicate accountStatusPredicate = pb.equals("status", ServiceStatus.Active.getKey());
ImdgPredicate accountTypePredicate = pb.equals("accountType", AccountType.Clrn.getKey());
ImdgPredicate finalPredicate = pb.and(accountValuePredicate,
accountStatusPredicate,
@ -102,7 +102,7 @@ public class ClearingAccountValidationConfig {
);
ImdgPredicateBuilder pb = accountImdg.predicateBuilder();
ImdgPredicate accountValuePredicate = pb.equals("account", accountValue);
ImdgPredicate accountStatusPredicate = pb.equals("status", AccountStatus.ACTIVE.getKey());
ImdgPredicate accountStatusPredicate = pb.equals("status", ServiceStatus.Active.getKey());
ImdgPredicate accountTypePredicate = pb.equals("accountType", AccountType.Clrn.getKey());
ImdgPredicate finalPredicate = pb.and(accountValuePredicate,
accountStatusPredicate,

View file

@ -10,8 +10,8 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.DepoAccountNewReq
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
@ -56,7 +56,7 @@ public class DepoAccountValidationConfig {
);
ImdgPredicateBuilder pb = accountImdg.predicateBuilder();
ImdgPredicate accountValuePredicate = pb.equals("account", accountValue);
ImdgPredicate accountStatusPredicate = pb.equals("status", AccountStatus.ACTIVE.getKey());
ImdgPredicate accountStatusPredicate = pb.equals("status", ServiceStatus.Active.getKey());
ImdgPredicate accountTypePredicate = pb.equals("accountType", AccountType.Clrn.getKey());
ImdgPredicate finalPredicate = pb.and(accountValuePredicate,
accountStatusPredicate,

View file

@ -0,0 +1,144 @@
package ru.spcex.clearing.account.config.validation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.ClearingAccount;
import ru.clearing.classes.statics.data.account.DepoAccount;
import ru.clearing.classes.statics.data.account.InformationAccount;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.platform.dictionary.ServiceStatusDictionary;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryUpdateRequest;
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@Configuration
public class TradingClearingRegistryValidationConfig {
@Bean("tradingClearingRegistryNewRequest")
public Function<TradingClearingRegistryNewRequest, IValidator> tradingClearingRegistryNewRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return tradingClearingRegistryNewRequest -> {
ImdgValidationContext<TradingClearingRegistryNewRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(tradingClearingRegistryNewRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Company);
addImdg.accept(IMDGDistributedNames.Map_ClearingAccount);
addImdg.accept(IMDGDistributedNames.Map_DepoAccount);
addImdg.accept(IMDGDistributedNames.Map_InformationAccount);
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary);
return new ValidatorImpl<>(context,
IdPresentRule.instance("companyId",
TradingClearingRegistryNewRequest::getCompanyId,
IMDGDistributedNames.Map_Company,
Company.class,
AccountError.RequiredFieldEmpty,
AccountError.CompanyNotFound),
FieldRequiredRule.instance("moneyAccountId",
TradingClearingRegistryNewRequest::getMoneyAccountId,
AccountError.RequiredFieldEmpty,
moneyAccountId -> {
Imdg<ClearingAccount> clearingAccountImdg = context.obtainMap(
IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class
);
ClearingAccount clearingAccount = clearingAccountImdg.getSingleObjectByID(moneyAccountId);
if (clearingAccount == null) {
Imdg<InformationAccount> informationAccountImdg = context.obtainMap(
IMDGDistributedNames.Map_InformationAccount, InformationAccount.class
);
InformationAccount infoAccount = informationAccountImdg.getSingleObjectByID(moneyAccountId);
if (infoAccount == null) return AccountError.AccountNotFound;
}
return null;
}),
FieldRequiredRule.instance("depoAccountId",
TradingClearingRegistryNewRequest::getDepoAccountId,
AccountError.RequiredFieldEmpty,
false,
depoAccountId -> {
if (depoAccountId == null) return null;
Imdg<DepoAccount> depoAccountImdg = context.obtainMap(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class);
DepoAccount depoAccount = depoAccountImdg.getSingleObjectByID(depoAccountId);
if (depoAccount == null) return AccountError.AccountNotFound;
return null;
}),
DictionaryPresentRule.instance("status",
TradingClearingRegistryNewRequest::getStatus,
IMDGDistributedNames.Map_ServiceStatusDictionary,
ServiceStatusDictionary.class,
AccountError.RequiredFieldEmpty,
AccountError.WrongFieldValue,
false,
statusValue -> {
String statusCode = statusValue.getCode();
if (ServiceStatus.Active.equalsByKey(statusCode)) return null;
return AccountError.WrongFieldValue;
})
);
};
}
@Bean("tradingClearingRegistryUpdateRequest")
public Function<TradingClearingRegistryUpdateRequest, IValidator> tradingClearingRegistryUpdateRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return tradingClearingRegistryUpdateRequest -> {
ImdgValidationContext<TradingClearingRegistryUpdateRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(tradingClearingRegistryUpdateRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary);
addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry);
return new ValidatorImpl<>(context,
IdPresentRule.instance("id",
TradingClearingRegistryUpdateRequest::getId,
IMDGDistributedNames.Map_TradingClearingRegistry,
TradingClearingRegistry.class,
AccountError.RequiredFieldEmpty,
AccountError.TradingClearingRegistryNotFound),
DictionaryPresentRule.instance("status",
TradingClearingRegistryUpdateRequest::getStatus,
IMDGDistributedNames.Map_ServiceStatusDictionary,
ServiceStatusDictionary.class,
AccountError.RequiredFieldEmpty,
AccountError.WrongFieldValue,
false)
);
};
}
@Bean("tradingClearingRegistryBlockRequest")
public Function<CommonIdRequest, IValidator> tradingClearingRegistryBlockRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return tradingClearingRegistryBlockRequest -> {
ImdgValidationContext<CommonIdRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(tradingClearingRegistryBlockRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry);
return new ValidatorImpl<>(context,
IdPresentRule.instance("id",
CommonIdRequest::getId,
IMDGDistributedNames.Map_TradingClearingRegistry,
TradingClearingRegistry.class,
AccountError.RequiredFieldEmpty,
AccountError.TradingClearingRegistryNotFound)
);
};
}
}

View file

@ -3,15 +3,14 @@ package ru.spcex.clearing.account.config.validation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.BankAccount;
import ru.clearing.classes.statics.data.account.ClearingAccount;
import ru.clearing.classes.statics.data.account.InformationAccount;
import ru.clearing.classes.statics.data.account.*;
import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.platform.dictionary.AccountTypeDictionary;
import ru.clearing.platform.dictionary.ClearingAccountTypeDictionary;
import ru.clearing.platform.dictionary.CurrencyCodeDictionary;
import ru.clearing.platform.dictionary.ServiceStatusDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.classes.base.SpcexObjectBase;
@ -40,6 +39,9 @@ public class ValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_BankAccount, BankAccount.class);
addImdg.accept(IMDGDistributedNames.Map_CurrencyCodeDictionary, CurrencyCodeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class);
addImdg.accept(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class);
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary, ServiceStatusDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
return imdg;
}

View file

@ -3,6 +3,7 @@ package ru.spcex.clearing.account.errors;
import ru.spcex.platform.utils.enumeration.IErrorEnumId;
public enum AccountError implements IErrorEnumId {
GeneralError(5000L),
UserVerifyDenial(5001L),
RequiredFieldEmpty(5002L),
WrongFieldValue(5004L),
@ -12,7 +13,11 @@ public enum AccountError implements IErrorEnumId {
CompanyNotFound(5013L),
CompanyNotActive(5014L),
InfoAccountAlreadyExist(5015L),
ClearingCategoryNotFound(5019L)
TradingClearingRegistryAlreadyExist(5016L),
DepoAccountNotFound(5017L),
MoneyAccountNotFound(5018L),
ClearingCategoryNotFound(5019L),
TradingClearingRegistryNotFound(5022L),
;
private final Long id;

View file

@ -21,15 +21,15 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdf0
import ru.spcex.clearing.platform.messaging.domain.cud.account.sdf01.AccountSdfRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.AccountSdfToStatementRequestPart;
import ru.spcex.clearing.platform.messaging.domain.cud.balance.StatementRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
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.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
@ -57,7 +57,7 @@ public class AccountService extends QueueConsumer implements InitializingBean {
private final ValidationHelper validationHelper;
private final Function<CorrespondentAccountNewRequest, IValidator> accountNewRequestValidator;
private final Function<CorrespondentAccountUpdateRequest, IValidator> accountUpdateRequestValidator;
private final Function<CommonDeleteRequest, IValidator> accountBlockRequestValidator;
private final Function<CommonIdRequest, IValidator> accountBlockRequestValidator;
@Autowired
public AccountService(Consumer<String, Object> kafkaQueue,
@ -72,7 +72,7 @@ public class AccountService extends QueueConsumer implements InitializingBean {
@Qualifier("correspondentAccountUpdateRequestValidator")
Function<CorrespondentAccountUpdateRequest, IValidator> accountUpdateRequestValidator,
@Qualifier("correspondentAccountBlockRequestValidator")
Function<CommonDeleteRequest, IValidator> accountBlockRequestValidator) {
Function<CommonIdRequest, IValidator> accountBlockRequestValidator) {
super(kafkaQueue, kafkaProducer);
this.accountMap = imdgProvider.getImdg(
IMDGDistributedNames.Map_Account, Account.class
@ -103,7 +103,7 @@ public class AccountService extends QueueConsumer implements InitializingBean {
callback(CorrespondentAccountUpdateRequest.class)
.setConsumer(this::correspondentAccountUpdate)
.forDestination(Consts.DESTINATION_CORRESPONDENT_ACCOUNT_UPDATE, callbacks::put);
callback(CommonDeleteRequest.class)
callback(CommonIdRequest.class)
.setConsumer(this::correspondentAccountBlock)
.forDestination(Consts.DESTINATION_CORRESPONDENT_ACCOUNT_BLOCK, callbacks::put);
init();
@ -161,7 +161,7 @@ public class AccountService extends QueueConsumer implements InitializingBean {
return null;
}
public RequestInfoUpdate correspondentAccountBlock(BaseRequest<CommonDeleteRequest> userRequest) {
public RequestInfoUpdate correspondentAccountBlock(BaseRequest<CommonIdRequest> userRequest) {
log.debug("AccountBlockRequest received");
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
@ -170,10 +170,10 @@ public class AccountService extends QueueConsumer implements InitializingBean {
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, accountBlockRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
CommonDeleteRequest request = userRequest.getRequestPayload();
CommonIdRequest request = userRequest.getRequestPayload();
Account account = accountMap.getSingleObjectByID(request.getId());
account.setStatus(AccountStatus.BLOCKED.getKey());
account.setStatus(ServiceStatus.Blocked.getKey());
account.setUpdated(Instant.now());
accountMap.update(account);

View file

@ -15,13 +15,13 @@ import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
@ -44,7 +44,7 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
private final Function<BankAccountNewRequest, IValidator> bankAccountNewRequestValidator;
private final Function<BankAccountUpdateRequest, IValidator> bankAccountUpdateRequestValidator;
private final Function<CommonDeleteRequest, IValidator> bankAccountBlockRequestValidator;
private final Function<CommonIdRequest, IValidator> bankAccountBlockRequestValidator;
@Autowired
public BankAccountService(Consumer<String, Object> kafkaQueue,
@ -58,7 +58,7 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
@Qualifier("bankAccountUpdateRequestValidator")
Function<BankAccountUpdateRequest, IValidator> bankAccountUpdateRequestValidator,
@Qualifier("bankAccountBlockRequestValidator")
Function<CommonDeleteRequest, IValidator> bankAccountBlockRequestValidator) {
Function<CommonIdRequest, IValidator> bankAccountBlockRequestValidator) {
super(kafkaQueue, kafkaProducer);
this.bankAccountMap = imdgProvider.getImdg(IMDGDistributedNames.Map_BankAccount, BankAccount.class);
this.accountMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
@ -79,7 +79,7 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
callback(BankAccountUpdateRequest.class)
.setFunction(this::bankAccountUpdate)
.forDestination(Consts.DESTINATION_BANK_ACCOUNT_UPDATE, callbacks::put);
callback(CommonDeleteRequest.class)
callback(CommonIdRequest.class)
.setFunction(this::bankAccountBlock)
.forDestination(Consts.DESTINATION_BANK_ACCOUNT_BLOCK, callbacks::put);
init();
@ -101,7 +101,7 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
Account account = new Account();
account.setAccount(req.getAccount());
account.setAccountType(AccountType.Bank.getKey());
account.setStatus(AccountStatus.ACTIVE.getKey());
account.setStatus(ServiceStatus.Active.getKey());
account.setCompanyId(req.getCompanyId());
account.setCreated(now);
account.setUpdated(now);
@ -194,8 +194,8 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
return null;
}
private RequestInfoUpdate bankAccountBlock(BaseRequest<CommonDeleteRequest> userRequest) {
CommonDeleteRequest req = userRequest.getRequestPayload();
private RequestInfoUpdate bankAccountBlock(BaseRequest<CommonIdRequest> userRequest) {
CommonIdRequest req = userRequest.getRequestPayload();
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
@ -203,11 +203,11 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, bankAccountBlockRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
log.debug("CommonDeleteRequest received id = {}", req.getId());
log.debug("CommonIdRequest received id = {}", req.getId());
BankAccount bankAccount = bankAccountMap.getSingleObjectByID(req.getId());
Account account = accountMap.getSingleObjectByID(bankAccount.getAccountId());
account.setStatus(AccountStatus.BLOCKED.getKey());
account.setStatus(ServiceStatus.Blocked.getKey());
account.setUpdated(Instant.now());
ImdgTransaction imdgTransaction = imdgProvider.newTransaction();
@ -224,7 +224,6 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
bankAccount.getId(),
account.getId());
} else {
// todo выяснить, что возвращать из метода в этой ситуации
log.debug("failed block, bank account id {}, new account id {}",
bankAccount.getId(),
account.getId());

View file

@ -16,18 +16,19 @@ import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClearingAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClearingAccountUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
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.util.services.RequestHelper;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
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.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
@ -38,33 +39,39 @@ import java.util.function.Function;
@Service
public class ClearingAccountService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final KafkaSender kafkaSender;
private final AccountService accountService;
private final ValidationHelper validationHelper;
private final ImdgProvider imdgProvider;
private final Imdg<Account> accountImdg;
private final Imdg<ClearingAccount> clearingAccountImdg;
private final IMessageResolver messageResolver;
private final RequestHelper requestHelper;
private final Function<ClearingAccountNewRequest, IValidator> clearingAccountNewRequestValidator;
private final Function<ClearingAccountUpdateRequest, IValidator> clearingAccountUpdateRequestValidator;
@Autowired
public ClearingAccountService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaResponseQueue,
KafkaSender kafkaSender,
AccountService accountService,
ValidationHelper validationHelper,
ImdgProvider imdgProvider,
IMessageResolver messageResolver,
RequestHelper requestHelper,
@Qualifier("clearingAccountNewRequestValidator")
Function<ClearingAccountNewRequest, IValidator> clearingAccountNewRequestValidator,
@Qualifier("clearingAccountUpdateRequestValidator")
Function<ClearingAccountUpdateRequest, IValidator> clearingAccountUpdateRequestValidator) {
super(kafkaQueue, kafkaResponseQueue);
this.kafkaSender = kafkaSender;
this.accountService = accountService;
this.validationHelper = validationHelper;
this.imdgProvider = imdgProvider;
this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
this.clearingAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class);
this.messageResolver = messageResolver;
this.requestHelper = requestHelper;
this.clearingAccountNewRequestValidator = clearingAccountNewRequestValidator;
this.clearingAccountUpdateRequestValidator = clearingAccountUpdateRequestValidator;
}
@ -92,7 +99,7 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
Account account = new Account();
account.setAccount(req.getAccount());
account.setAccountType(AccountType.Clrn.getKey());
account.setStatus(AccountStatus.ACTIVE.getKey());
account.setStatus(ServiceStatus.Active.getKey());
account.setCompanyId(req.getCompanyId());
account.setCreated(now);
account.setUpdated(now);
@ -104,10 +111,11 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
ImdgTransaction imdgTransaction = imdgProvider.newTransaction();
boolean txOk = false;
imdgTransaction.beginTransaction();
ClearingAccount clearingAccount = null;
try {
accountId = accountImdg.insert(account);
ClearingAccount clearingAccount = new ClearingAccount();
clearingAccount = new ClearingAccount();
clearingAccount.setCompanyId(req.getCompanyId());
clearingAccount.setAccountId(accountId);
clearingAccount.setClearingAccountType(req.getClearingAccountType());
@ -116,9 +124,12 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
} finally {
if (txOk) {
imdgTransaction.commitTransaction();
TradingClearingRegistryNewRequest request = new TradingClearingRegistryNewRequest();
request.setMoneyAccountId(accountId);
request.setCompanyId(clearingAccount.getCompanyId());
kafkaSender.sendRequestToQueue(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_AUTO_NEW, request);
log.debug("successfully processed, new clearing account id {}, account id {}", clearingAccountId, accountId);
} else {
// todo выяснить, что возвращать из метода в этой ситуации
log.debug("failed insert, new clearing account id {}, new account id {} (if id = -1 then insert is failed)",
clearingAccountId,
accountId);
@ -137,7 +148,7 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
ClearingAccountUpdateRequest req = userRequest.getRequestPayload();
ImdgPredicateBuilder pb = accountImdg.predicateBuilder();
ImdgPredicate accountValuePredicate = pb.equals("account", req.getAccount());
ImdgPredicate accountStatusPredicate = pb.equals("status", AccountStatus.ACTIVE.getKey());
ImdgPredicate accountStatusPredicate = pb.equals("status", ServiceStatus.Active.getKey());
ImdgPredicate accountTypePredicate = pb.equals("accountType", AccountType.Clrn.getKey());
ImdgPredicate finalPredicate = pb.and(accountValuePredicate,
accountStatusPredicate,
@ -147,18 +158,13 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
Long accountId = account.getId();
ClearingAccount clearingAccount = clearingAccountImdg.getSingleObjectByFieldValues(Map.of("accountId", accountId));
if (clearingAccount == null) {
String errMsg = messageResolver.resolve(new EnumMessage(AccountError.AccountNotFound, account.getAccount()));
return new RequestInfoUpdate()
.setId(userRequest.getId())
.setStatus(Status.Error)
.setMessage(errMsg);
}
if (clearingAccount == null)
return requestHelper.makeErrorResponse(userRequest, AccountError.AccountNotFound, account.getAccount());
Integer statusValue = req.getStatus();
if (statusValue == 0) account.setStatus(AccountStatus.BLOCKED.getKey());
else if (statusValue == 1) account.setStatus(AccountStatus.ACTIVE.getKey());
else if (statusValue == 2) account.setStatus(AccountStatus.CLOSE.getKey());
if (statusValue == 0) account.setStatus(ServiceStatus.Blocked.getKey());
else if (statusValue == 1) account.setStatus(ServiceStatus.Active.getKey());
else if (statusValue == 2) account.setStatus(ServiceStatus.Closed.getKey());
account.setUpdated(Instant.now());
accountImdg.update(account);

View file

@ -13,11 +13,13 @@ 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.account.DepoAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
@ -30,6 +32,7 @@ import java.util.function.Function;
public class DepoAccountService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final KafkaSender kafkaSender;
private final ValidationHelper validationHelper;
private final ImdgProvider imdgProvider;
private final AccountService accountService;
@ -39,12 +42,14 @@ public class DepoAccountService extends QueueConsumer implements InitializingBea
public DepoAccountService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
KafkaSender kafkaSender,
ValidationHelper validationHelper,
ImdgProvider imdgProvider,
AccountService accountService,
@Qualifier("depoAccountNewRequestValidator")
Function<DepoAccountNewRequest, IValidator> depoAccountNewRequestValidator) {
super(kafkaQueue, kafkaProducer);
this.kafkaSender = kafkaSender;
this.validationHelper = validationHelper;
this.imdgProvider = imdgProvider;
this.accountService = accountService;
@ -74,7 +79,7 @@ public class DepoAccountService extends QueueConsumer implements InitializingBea
Account account = new Account();
account.setAccount(req.getAccount());
account.setAccountType(AccountType.Depo.getKey());
account.setStatus(AccountStatus.ACTIVE.getKey());
account.setStatus(ServiceStatus.Active.getKey());
account.setCompanyId(req.getCompanyId());
account.setCreated(now);
account.setUpdated(now);
@ -86,10 +91,11 @@ public class DepoAccountService extends QueueConsumer implements InitializingBea
ImdgTransaction imdgTransaction = imdgProvider.newTransaction();
boolean txOk = false;
imdgTransaction.beginTransaction();
DepoAccount depoAccount = null;
try {
accountId = accountImdg.insert(account);
DepoAccount depoAccount = new DepoAccount();
depoAccount = new DepoAccount();
depoAccount.setCompanyId(req.getCompanyId());
depoAccount.setAccountId(accountId);
depoAccount.setDepoAccountType(req.getDepoAccountType());
@ -98,9 +104,12 @@ public class DepoAccountService extends QueueConsumer implements InitializingBea
} finally {
if (txOk) {
imdgTransaction.commitTransaction();
TradingClearingRegistryNewRequest request = new TradingClearingRegistryNewRequest();
request.setDepoAccountId(accountId);
request.setCompanyId(depoAccount.getCompanyId());
kafkaSender.sendRequestToQueue(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_AUTO_NEW, request);
log.debug("successfully processed, new depo account id {}, account id {}", depoAccountId, accountId);
} else {
// todo выяснить, что возвращать из метода в этой ситуации
log.debug("failed insert, new depo account id {}, new account id {} (if id = -1 then insert is failed)",
depoAccountId,
accountId);

View file

@ -15,18 +15,19 @@ 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.account.InformationAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
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.util.services.RequestHelper;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
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.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
@ -37,10 +38,12 @@ import java.util.function.Function;
@Service
public class InformationAccountService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final KafkaSender kafkaSender;
private final IMessageResolver messageResolver;
private final ImdgProvider imdgProvider;
private final ValidationHelper validationHelper;
private final AccountService accountService;
private final RequestHelper requestHelper;
private final Function<InformationAccountNewRequest, IValidator> infoAccountNewRequestValidator;
private final Imdg<InformationAccount> informationAccountImdg;
private final Imdg<Account> accountImdg;
@ -48,17 +51,21 @@ public class InformationAccountService extends QueueConsumer implements Initiali
@Autowired
public InformationAccountService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaResponseQueue,
KafkaSender kafkaSender,
IMessageResolver messageResolver,
ImdgProvider imdgProvider,
ValidationHelper validationHelper,
AccountService accountService,
RequestHelper requestHelper,
@Qualifier("informationAccountNewRequestValidator")
Function<InformationAccountNewRequest, IValidator> infoAccountNewRequestValidator) {
super(kafkaQueue, kafkaResponseQueue);
this.kafkaSender = kafkaSender;
this.messageResolver = messageResolver;
this.imdgProvider = imdgProvider;
this.validationHelper = validationHelper;
this.accountService = accountService;
this.requestHelper = requestHelper;
this.infoAccountNewRequestValidator = infoAccountNewRequestValidator;
this.informationAccountImdg = imdgProvider.getImdg(
IMDGDistributedNames.Map_InformationAccount, InformationAccount.class
@ -91,11 +98,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali
ImdgPredicate andPredicate = accountPredicateBuilder.and(companyIdPredicate, accountTypePredicate);
Collection<Account> accountsAnlt = accountImdg.getCollectionObjectsByPredicate(andPredicate);
if (accountsAnlt.isEmpty()) {
String errMsg = messageResolver.resolve(new EnumMessage(AccountError.WrongFieldValue, "clearingAccountId"));
return new RequestInfoUpdate()
.setId(userRequest.getId())
.setStatus(Status.Error)
.setMessage(errMsg);
return requestHelper.makeErrorResponse(userRequest, AccountError.WrongFieldValue, "clearingAccountId");
} else if (accountsAnlt.size() > 1) {
log.warn("Account for companyId 1 and accountType=ANLT contains multiply elements, use first");
}
@ -105,7 +108,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali
Account account = new Account();
account.setAccount(accountValue);
account.setAccountType(AccountType.Info.getKey());
account.setStatus(AccountStatus.ACTIVE.getKey());
account.setStatus(ServiceStatus.Active.getKey());
account.setCompanyId(userRequest.getRequestPayload().getCompanyId());
account.setCreated(now);
account.setUpdated(now);
@ -117,10 +120,11 @@ public class InformationAccountService extends QueueConsumer implements Initiali
boolean txOk = false;
Long informationAccountId = -1L;
Long accountId = -1L;
InformationAccount informationAccount = null;
try {
accountId = accountImdg.insert(account);
InformationAccount informationAccount = new InformationAccount();
informationAccount = new InformationAccount();
informationAccount.setId(newId);
informationAccount.setAccountId(accountId);
informationAccount.setClearingAccountId(anltAccount.getId());
@ -130,11 +134,14 @@ public class InformationAccountService extends QueueConsumer implements Initiali
} finally {
if (txOk) {
imdgTransaction.commitTransaction();
TradingClearingRegistryNewRequest request = new TradingClearingRegistryNewRequest();
request.setMoneyAccountId(informationAccountId);
request.setCompanyId(informationAccount.getCompanyId());
kafkaSender.sendRequestToQueue(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_AUTO_NEW, request);
log.debug("successfully processed, new information account id {}, new account id {}",
informationAccountId,
accountId);
} else {
// todo выяснить, что возвращать из метода в этой ситуации
log.debug("failed insert, new information account id {}, new account id {} (if id = -1 then insert is failed)",
informationAccountId,
accountId);

View file

@ -0,0 +1,359 @@
package ru.spcex.clearing.account.service;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.ClearingAccount;
import ru.clearing.classes.statics.data.account.DepoAccount;
import ru.clearing.classes.statics.data.account.InformationAccount;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.account.errors.AccountError;
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.common.CommonIdRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.TradingClearingRegistryPurpose;
import ru.spcex.platform.enumeration.TradingClearingRegistryType;
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.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@Service
public class TradingClearingRegistryService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ValidationHelper validationHelper;
private final UserRoleVerification userRoleVerification;
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private final Imdg<DepoAccount> depoAccountImdg;
private final Imdg<ClearingAccount> clearingAccountImdg;
private final Imdg<InformationAccount> informationAccountImdg;
private final Imdg<Account> accountImdg;
private final Imdg<Company> companyImdg;
private final Imdg<Relation> relationImdg;
private final Function<TradingClearingRegistryUpdateRequest, IValidator> tradingClearingRegistryUpdateRequestValidator;
private final RequestHelper requestHelper;
private final Function<TradingClearingRegistryNewRequest, IValidator> tradingClearingRegistryNewRequestValidator;
private final Function<CommonIdRequest, IValidator> tradingClearingRegistryBlockRequestValidator;
private final IMessageResolver messageResolver;
public TradingClearingRegistryService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider,
ValidationHelper validationHelper,
UserRoleVerification userRoleVerification,
IMessageResolver messageResolver,
RequestHelper requestHelper,
@Qualifier("tradingClearingRegistryNewRequest")
Function<TradingClearingRegistryNewRequest, IValidator> tradingClearingRegistryNewRequestValidator,
@Qualifier("tradingClearingRegistryUpdateRequest")
Function<TradingClearingRegistryUpdateRequest, IValidator> tradingClearingRegistryUpdateRequestValidator,
@Qualifier("tradingClearingRegistryBlockRequest")
Function<CommonIdRequest, IValidator> tradingClearingRegistryBlockRequestValidator) {
super(kafkaQueue, kafkaProducer);
this.validationHelper = validationHelper;
this.userRoleVerification = userRoleVerification;
this.requestHelper = requestHelper;
this.tradingClearingRegistryNewRequestValidator = tradingClearingRegistryNewRequestValidator;
this.tradingClearingRegistryImdg = imdgProvider.getImdg(
IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class
);
this.depoAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class);
this.clearingAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class);
this.informationAccountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_InformationAccount, InformationAccount.class);
this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.accountImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
this.relationImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
this.tradingClearingRegistryUpdateRequestValidator = tradingClearingRegistryUpdateRequestValidator;
this.tradingClearingRegistryBlockRequestValidator = tradingClearingRegistryBlockRequestValidator;
this.messageResolver = messageResolver;
}
@Override
public void afterPropertiesSet() throws Exception {
init();
callback(TradingClearingRegistryNewRequest.class)
.setConsumer(this::tradingClearingRegistryAutoNew)
.forDestination(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_AUTO_NEW, callbacks::put);
callback(TradingClearingRegistryNewRequest.class)
.setConsumer(this::tradingClearingRegistryNew)
.forDestination(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW, callbacks::put);
callback(TradingClearingRegistryUpdateRequest.class)
.setConsumer(this::tradingClearingRegistryUpdate)
.forDestination(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE, callbacks::put);
callback(CommonIdRequest.class)
.setConsumer(this::tradingClearingRegistryBlock)
.forDestination(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_BLOCK, callbacks::put);
}
public RequestInfoUpdate tradingClearingRegistryAutoNew(BaseRequest<TradingClearingRegistryNewRequest> userRequest) {
log.debug("TradingClearingRegistryNewRequest received");
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, tradingClearingRegistryNewRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
TradingClearingRegistryNewRequest req = userRequest.getRequestPayload();
Long id = tradingClearingRegistryImdg.nextIDSequenceFor();
TradingClearingRegistry tradingClearingRegistry = new TradingClearingRegistry();
tradingClearingRegistry.setId(id);
tradingClearingRegistry.setCompanyId(req.getCompanyId());
tradingClearingRegistry.setMoneyAccountId(req.getMoneyAccountId());
tradingClearingRegistry.setDepoAaccountId(req.getDepoAccountId());
DepoAccount depoAccount = req.getDepoAccountId() != null ? depoAccountImdg.getSingleObjectByID(req.getDepoAccountId()) : null;
Account depoAccountMain = depoAccount != null ? accountImdg.getSingleObjectByID(depoAccount.getAccountId()) : null;
InformationAccount infoAccount = null;
ClearingAccount clearingAccount = clearingAccountImdg.getSingleObjectByID(req.getMoneyAccountId());
if (clearingAccount == null) infoAccount = informationAccountImdg.getSingleObjectByID(req.getMoneyAccountId());
Long accountId = clearingAccount != null ? clearingAccount.getAccountId() : infoAccount.getAccountId();
Account accountMain = accountImdg.getSingleObjectByID(accountId);
// TODO
// Проверка выглядит очень сложно и запутанно, потому что репортеры сами не до конца понимают, какая она должна быть.
// Пока что она соответствует ТЗ, но возможно будет правиться, поэтому расписана без выноса кода в методы и
// прочих методов сокращения кода. В дальнейшем, после тестирования и окончательного выяснения вида проверки,
// её стоит вынести на этап валидации запроса.
Relation relation = relationImdg.getSingleObjectByFieldValues(Map.of("consumerId", req.getCompanyId()));
if (ru.spcex.platform.enumeration.Service.MKR.equalsByKey(relation.getService())) {
TradingClearingRegistry registry = tradingClearingRegistryImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (registry != null) {
return requestHelper.makeErrorResponse(userRequest,
AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.getId());
}
DepoAccount depoAccountForCheck = depoAccountImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (depoAccountForCheck == null)
return requestHelper.makeErrorResponse(userRequest, AccountError.DepoAccountNotFound, req.getCompanyId());
} else if (ru.spcex.platform.enumeration.Service.FOND.equalsByKey(relation.getService())) {
if (AccountType.Info.equalsByKey(accountMain.getStatus())) {
TradingClearingRegistry registry = tradingClearingRegistryImdg.getSingleObjectByFieldValues(Map.of(
"companyId", req.getCompanyId(),
"tradingClearingRegistryType", TradingClearingRegistryPurpose.M.getKey()
));
if (registry != null) {
return requestHelper.makeErrorResponse(userRequest,
AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.getId());
}
DepoAccount depoAccountForCheck = depoAccountImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (depoAccountForCheck == null)
return requestHelper.makeErrorResponse(userRequest, AccountError.DepoAccountNotFound, req.getCompanyId());
} else if (AccountType.Clrn.equalsByKey(accountMain.getStatus())) {
ImdgPredicateBuilder imdgPredicateBuilder = tradingClearingRegistryImdg.predicateBuilder();
ImdgPredicate predicate = imdgPredicateBuilder.and(
imdgPredicateBuilder.equals("companyId", req.getCompanyId()),
imdgPredicateBuilder.or(
imdgPredicateBuilder.equals("tradingClearingRegistryPurpose", TradingClearingRegistryPurpose.M.getKey()),
imdgPredicateBuilder.equals("tradingClearingRegistryPurpose", TradingClearingRegistryPurpose.C.getKey())
)
);
Collection<TradingClearingRegistry> registry = tradingClearingRegistryImdg.getCollectionObjectsByPredicate(predicate);
if (!registry.isEmpty()) {
return requestHelper.makeErrorResponse(userRequest,
AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.iterator().next().getId());
}
DepoAccount depoAccountForCheck = depoAccountImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (depoAccountForCheck == null) {
return requestHelper.makeErrorResponse(userRequest, AccountError.DepoAccountNotFound, req.getCompanyId());
}
} else if (AccountType.Depo.equalsByKey(accountMain.getStatus())) {
InformationAccount infoAccountForCheck = informationAccountImdg.getSingleObjectByFieldValues(
Map.of("companyId", req.getCompanyId())
);
ClearingAccount clearingAccountForCheck = clearingAccountImdg.getSingleObjectByFieldValues(
Map.of("companyId", req.getCompanyId())
);
if (infoAccountForCheck == null && clearingAccountForCheck == null)
return requestHelper.makeErrorResponse(userRequest, AccountError.MoneyAccountNotFound, req.getCompanyId());
}
}
List<String> activeStatuses = Arrays.asList(ServiceStatus.Active.getKey(), ServiceStatus.Reopened.getKey());
String status = null;
if (depoAccountMain != null && depoAccountMain.getStatus() != null) {
if (activeStatuses.contains(depoAccountMain.getStatus()) && activeStatuses.contains(accountMain.getStatus()))
status = ServiceStatus.Active.getKey();
if (depoAccountMain.getStatus().equals(ServiceStatus.Blocked.getKey()) || accountMain.getStatus().equals(ServiceStatus.Blocked.getKey()))
status = ServiceStatus.Blocked.getKey();
if (depoAccountMain.getStatus().equals(ServiceStatus.Suspended.getKey()) || accountMain.getStatus().equals(ServiceStatus.Suspended.getKey()))
status = ServiceStatus.Suspended.getKey();
if (depoAccountMain.getStatus().equals(ServiceStatus.Closed.getKey()) || accountMain.getStatus().equals(ServiceStatus.Closed.getKey()))
status = ServiceStatus.Closed.getKey();
} else if (accountMain.getStatus() != null) {
if (activeStatuses.contains(accountMain.getStatus()))
status = ServiceStatus.Active.getKey();
if (accountMain.getStatus().equals(ServiceStatus.Blocked.getKey()))
status = ServiceStatus.Blocked.getKey();
if (accountMain.getStatus().equals(ServiceStatus.Suspended.getKey()))
status = ServiceStatus.Suspended.getKey();
if (accountMain.getStatus().equals(ServiceStatus.Closed.getKey()))
status = ServiceStatus.Closed.getKey();
}
if (status == null)
return requestHelper.makeErrorResponse(userRequest, AccountError.WrongFieldValue, req.getMoneyAccountId());
tradingClearingRegistry.setStatus(status);
String tradingRegistryType;
if (depoAccount != null) {
tradingRegistryType = depoAccount.getDepoAccountType();
} else {
if (clearingAccount != null) tradingRegistryType = clearingAccount.getClearingAccountType();
else tradingRegistryType = TradingClearingRegistryType.Owner_A.getKey();
}
tradingClearingRegistry.setTradingClearingRegistryType(tradingRegistryType);
TradingClearingRegistryPurpose registryPurpose;
if (req.getDepoAccountId() != null) registryPurpose = TradingClearingRegistryPurpose.C;
else registryPurpose = TradingClearingRegistryPurpose.M;
tradingClearingRegistry.setTradingClearingRegistryPurpose(registryPurpose.getKey());
Company company = companyImdg.getSingleObjectByID(req.getCompanyId());
String code = "%4s".formatted(company.getClearingCode()).replace(' ', '0');
code += registryPurpose.getKey();
if (registryPurpose == TradingClearingRegistryPurpose.C) code += tradingRegistryType + id;
else code += "AT" + id;
tradingClearingRegistry.setCode(code);
Instant now = Instant.now();
tradingClearingRegistry.setCreated(now);
tradingClearingRegistry.setUpdated(now);
tradingClearingRegistryImdg.insert(tradingClearingRegistry);
log.debug("successfully processed, id {}", id);
return null;
}
public RequestInfoUpdate tradingClearingRegistryNew(BaseRequest<TradingClearingRegistryNewRequest> userRequest) {
log.debug("TradingClearingRegistryNewRequest received");
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, tradingClearingRegistryNewRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
TradingClearingRegistryNewRequest req = userRequest.getRequestPayload();
Long id = tradingClearingRegistryImdg.nextIDSequenceFor();
TradingClearingRegistry tradingClearingRegistry = new TradingClearingRegistry();
tradingClearingRegistry.setId(id);
tradingClearingRegistry.setCompanyId(req.getCompanyId());
tradingClearingRegistry.setMoneyAccountId(req.getMoneyAccountId());
tradingClearingRegistry.setDepoAaccountId(req.getDepoAccountId());
DepoAccount depoAccount = req.getDepoAccountId() != null ? depoAccountImdg.getSingleObjectByID(req.getDepoAccountId()) : null;
ClearingAccount clearingAccount = clearingAccountImdg.getSingleObjectByID(req.getMoneyAccountId());
tradingClearingRegistry.setStatus(ServiceStatus.Active.getKey());
String tradingRegistryType;
if (depoAccount != null) {
tradingRegistryType = depoAccount.getDepoAccountType();
} else {
if (clearingAccount != null) tradingRegistryType = clearingAccount.getClearingAccountType();
else tradingRegistryType = TradingClearingRegistryType.Owner_A.getKey();
}
tradingClearingRegistry.setTradingClearingRegistryType(tradingRegistryType);
TradingClearingRegistryPurpose registryPurpose;
if (req.getDepoAccountId() != null) registryPurpose = TradingClearingRegistryPurpose.C;
else registryPurpose = TradingClearingRegistryPurpose.M;
tradingClearingRegistry.setTradingClearingRegistryPurpose(registryPurpose.getKey());
Company company = companyImdg.getSingleObjectByID(req.getCompanyId());
String code = "%4s".formatted(company.getClearingCode()).replace(' ', '0');
code += registryPurpose.getKey();
if (registryPurpose == TradingClearingRegistryPurpose.C) code += tradingRegistryType + id;
else code += "AT" + id;
tradingClearingRegistry.setCode(code);
Instant now = Instant.now();
tradingClearingRegistry.setCreated(now);
tradingClearingRegistry.setUpdated(now);
tradingClearingRegistryImdg.insert(tradingClearingRegistry);
log.debug("successfully processed, id {}", id);
return null;
}
public RequestInfoUpdate tradingClearingRegistryUpdate(BaseRequest<TradingClearingRegistryUpdateRequest> userRequest) {
log.debug("TradingClearingRegistryUpdateRequest received");
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, tradingClearingRegistryUpdateRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
TradingClearingRegistryUpdateRequest req = userRequest.getRequestPayload();
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getSingleObjectByID(req.getId());
if (req.getStatus() != null) tradingClearingRegistry.setStatus(req.getStatus());
Instant now = Instant.now();
tradingClearingRegistry.setUpdated(now);
tradingClearingRegistryImdg.update(tradingClearingRegistry);
log.debug("successfully processed, id {}", tradingClearingRegistry.getId());
return null;
}
public RequestInfoUpdate tradingClearingRegistryBlock(BaseRequest<CommonIdRequest> userRequest) {
log.debug("TradingClearingRegistryBlockRequest received");
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, tradingClearingRegistryBlockRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
CommonIdRequest req = userRequest.getRequestPayload();
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getSingleObjectByID(req.getId());
tradingClearingRegistry.setStatus(ServiceStatus.Blocked.getKey());
tradingClearingRegistry.setUpdated(Instant.now());
tradingClearingRegistryImdg.update(tradingClearingRegistry);
log.debug("successfully processed, id {}", tradingClearingRegistry.getId());
return null;
}
}

View file

@ -19,6 +19,7 @@ import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.clearing.platform.dictionary.AccountTypeDictionary;
import ru.clearing.platform.dictionary.ServiceStatusDictionary;
import ru.spcex.clearing.account.config.BeanConfiguration;
import ru.spcex.clearing.account.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.account.config.KafkaConfigTest;
@ -87,6 +88,7 @@ class AccountServiceTest {
private Imdg<AccountTypeDictionary> accountTypeDictionaryImdg;
private Imdg<ClearingMemberCategory> clearingMemberCategoryImdg;
private Imdg<Relation> relationImdg;
private Imdg<ServiceStatusDictionary> serviceStatusDictionaryImdg;
@PostConstruct
private void init() {
@ -106,6 +108,13 @@ class AccountServiceTest {
relationImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_Relation, Relation.class
);
serviceStatusDictionaryImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_ServiceStatusDictionary, ServiceStatusDictionary.class
);
ServiceStatusDictionary serviceStatusDictionary = new ServiceStatusDictionary();
serviceStatusDictionary.setCode(ServiceStatus.Active.getKey());
serviceStatusDictionary.setName(ServiceStatus.Active.getKey());
serviceStatusDictionaryImdg.insert(serviceStatusDictionary);
Company company = new Company();
company.setId(companyId);
@ -137,13 +146,13 @@ class AccountServiceTest {
correspondentAccountNewRequest.setAccount(uniqueAccount);
correspondentAccountNewRequest.setAccountType(AccountType.Corr.getKey());
correspondentAccountNewRequest.setCompanyId(companyId);
correspondentAccountNewRequest.setStatus(AccountStatus.ACTIVE.getKey());
correspondentAccountNewRequest.setStatus(ServiceStatus.Active.getKey());
Account predictableAccount = new Account();
predictableAccount.setAccount(uniqueAccount);
predictableAccount.setAccountType(AccountType.Corr.getKey());
predictableAccount.setCompanyId(companyId);
predictableAccount.setStatus(AccountStatus.ACTIVE.getKey());
predictableAccount.setStatus(ServiceStatus.Active.getKey());
predictableAccount.setRelationId(relationId);
String jsonString = getJsonStringForNew(correspondentAccountNewRequest, 0L);
@ -169,14 +178,14 @@ class AccountServiceTest {
Account existAccount = new Account();
existAccount.setAccount(account);
existAccount.setAccountType(AccountType.Corr.getKey());
existAccount.setStatus(AccountStatus.CLOSE.getKey());
existAccount.setStatus(ServiceStatus.Closed.getKey());
existAccount.setCompanyId(companyId);
Long accountId = accountImdg.insert(existAccount);
CorrespondentAccountUpdateRequest correspondentAccountUpdateRequest = new CorrespondentAccountUpdateRequest();
correspondentAccountUpdateRequest.setAccount(account);
correspondentAccountUpdateRequest.setAccountType(AccountType.Corr.getKey());
correspondentAccountUpdateRequest.setStatus(AccountStatus.ACTIVE.getKey());
correspondentAccountUpdateRequest.setStatus(ServiceStatus.Active.getKey());
correspondentAccountUpdateRequest.setCompanyId(companyId);
correspondentAccountUpdateRequest.setId(accountId);
@ -204,7 +213,7 @@ class AccountServiceTest {
Account existAccount = new Account();
existAccount.setAccount(account);
existAccount.setAccountType(AccountType.Corr.getKey());
existAccount.setStatus(AccountStatus.ACTIVE.getKey());
existAccount.setStatus(ServiceStatus.Active.getKey());
existAccount.setCompanyId(companyId);
Long accountId = accountImdg.insert(existAccount);
@ -224,7 +233,7 @@ class AccountServiceTest {
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
Account resultBlock = accountImdg.getSingleObjectByID(accountId);
existAccount.setStatus(AccountStatus.BLOCKED.getKey());
existAccount.setStatus(ServiceStatus.Blocked.getKey());
existAccount.setUpdated(resultBlock.getUpdated());
ACCOUNT_MATCHER.assertMatch(existAccount, resultBlock);

View file

@ -37,6 +37,8 @@ import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import javax.annotation.PostConstruct;
import java.util.Map;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFieldsComparator;
import static ru.spcex.clearing.account.utils.TestUtils.*;
@ -151,12 +153,13 @@ class ClearingAccountServiceTest {
0,
jsonString);
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
verify(producer, timeout(30_000L).times(2))
.send(producerRecord.capture());
Account predictableAccount = new Account();
predictableAccount.setAccount(ACCOUNT_VALUE);
predictableAccount.setAccountType(AccountType.Clrn.getKey());
predictableAccount.setStatus(AccountStatus.ACTIVE.getKey());
predictableAccount.setStatus(ServiceStatus.Active.getKey());
predictableAccount.setRelationId(relationId);
predictableAccount.setCompanyId(companyId);
@ -182,7 +185,7 @@ class ClearingAccountServiceTest {
void clearingAccountUpdate() {
Account existAccount = new Account();
existAccount.setAccount(ACCOUNT_VALUE);
existAccount.setStatus(AccountStatus.ACTIVE.getKey());
existAccount.setStatus(ServiceStatus.Active.getKey());
existAccount.setAccountType(AccountType.Clrn.getKey());
Long accountId = accountImdg.insert(existAccount);
@ -193,7 +196,7 @@ class ClearingAccountServiceTest {
Account predictableAccount = new Account();
predictableAccount.setAccount(ACCOUNT_VALUE);
predictableAccount.setStatus(AccountStatus.BLOCKED.getKey());
predictableAccount.setStatus(ServiceStatus.Blocked.getKey());
predictableAccount.setAccountType(AccountType.Clrn.getKey());
clearingAccountImdg.insert(existClearingAccount);

View file

@ -36,8 +36,11 @@ import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import javax.annotation.PostConstruct;
import java.util.Map;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFieldsComparator;
import static ru.spcex.clearing.account.utils.TestUtils.*;
import static ru.spcex.clearing.account.utils.TestUtils.addRecordToKafka;
import static ru.spcex.clearing.account.utils.TestUtils.getJsonStringForNew;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
@ -150,12 +153,13 @@ class DepoAccountServiceTest {
0,
jsonString);
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
verify(producer, timeout(30_000L).times(2))
.send(producerRecord.capture());
Account predictableAccount = new Account();
predictableAccount.setAccount(ACCOUNT_VALUE);
predictableAccount.setAccountType(AccountType.Depo.getKey());
predictableAccount.setStatus(AccountStatus.ACTIVE.getKey());
predictableAccount.setStatus(ServiceStatus.Active.getKey());
predictableAccount.setRelationId(relationId);
predictableAccount.setCompanyId(companyId);

View file

@ -35,8 +35,11 @@ import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import javax.annotation.PostConstruct;
import java.util.Map;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFieldsComparator;
import static ru.spcex.clearing.account.utils.TestUtils.*;
import static ru.spcex.clearing.account.utils.TestUtils.addRecordToKafka;
import static ru.spcex.clearing.account.utils.TestUtils.getJsonStringForNew;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
@ -140,11 +143,13 @@ class InformationAccountServiceTest {
0,
jsonString);
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
//waiting for kafka producer send message (finale event)
verify(producer, timeout(30_000L).times(2))
.send(producerRecord.capture());
Account predictableAccount = new Account();
predictableAccount.setAccountType(AccountType.Info.getKey());
predictableAccount.setStatus(AccountStatus.ACTIVE.getKey());
predictableAccount.setStatus(ServiceStatus.Active.getKey());
predictableAccount.setRelationId(relationId);
predictableAccount.setCompanyId(companyId);

View file

@ -0,0 +1,314 @@
package ru.spcex.clearing.account.service;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.producer.MockProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.ClearingAccount;
import ru.clearing.classes.statics.data.account.DepoAccount;
import ru.clearing.classes.statics.data.account.InformationAccount;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.platform.dictionary.ServiceStatusDictionary;
import ru.spcex.clearing.account.config.BeanConfiguration;
import ru.spcex.clearing.account.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.account.config.KafkaConfigTest;
import ru.spcex.clearing.account.config.validation.TradingClearingRegistryValidationConfig;
import ru.spcex.clearing.account.config.validation.ValidationConfig;
import ru.spcex.clearing.account.utils.MatcherFactory;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryUpdateRequest;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.TradingClearingRegistryPurpose;
import ru.spcex.platform.enumeration.TradingClearingRegistryType;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import javax.annotation.PostConstruct;
import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFieldsComparator;
import static ru.spcex.clearing.account.utils.TestUtils.*;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
BeanConfiguration.class,
ValidationConfig.class,
TradingClearingRegistryValidationConfig.class,
TradingClearingRegistryService.class,
HazelcastServiceTestConfiguration.class,
KafkaConfigTest.class})
class TradingClearingRegistryServiceTest {
public static final MatcherFactory.Matcher<TradingClearingRegistry> TRADING_CLEARING_REGISTRY_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_ACCOUNT_NEW = Consts.ACCOUNT_NEW_SDF01;
private static final String account = "123456789123";
private static final Long companyId = 0L;
private static final Long relationId = 0L;
@Autowired
TradingClearingRegistryService tradingClearingRegistryService;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
@Captor
private ArgumentCaptor<ProducerRecord> producerRecord;
@SpyBean
private MockProducer<String, Object> producer;
private Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private Imdg<Company> companyImdg;
private Imdg<ServiceStatusDictionary> serviceStatusDictionaryImdg;
private Imdg<ClearingAccount> clearingAccountImdg;
private Long clearingAccountId;
private Imdg<DepoAccount> depoAccountImdg;
private Long depoAccountId;
private Imdg<InformationAccount> informationAccountImdg;
private Long infoAccountId;
private Imdg<Account> accountImdg;
private Long accountId;
private Long account2Id;
static int newRequestCnt = 0;
@PostConstruct
private void init() {
hazelcastServiceTest.waitAvailable();
tradingClearingRegistryImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class
);
companyImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_Company, Company.class
);
serviceStatusDictionaryImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_ServiceStatusDictionary, ServiceStatusDictionary.class
);
accountImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_Account, Account.class
);
clearingAccountImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class
);
depoAccountImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_DepoAccount, DepoAccount.class
);
informationAccountImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_InformationAccount, InformationAccount.class
);
ServiceStatusDictionary serviceStatusDictionary = new ServiceStatusDictionary();
serviceStatusDictionary.setCode(ServiceStatus.Active.getKey());
serviceStatusDictionary.setName(ServiceStatus.Active.getKey());
serviceStatusDictionaryImdg.insert(serviceStatusDictionary);
Company company = new Company();
company.setId(companyId);
company.setWorkflowStatus(WorkflowStatus.Active.getKey());
company.setClearingCode("77");
companyImdg.insert(company);
Account account = new Account();
account.setStatus(ServiceStatus.Active.getKey());
accountId = accountImdg.insert(account);
account2Id = accountImdg.insert(account);
DepoAccount depoAccount = new DepoAccount();
depoAccount.setAccountId(accountId);
depoAccount.setDepoAccountType("DAT");
depoAccountId = depoAccountImdg.insert(depoAccount);
ClearingAccount clearingAccount = new ClearingAccount();
clearingAccount.setAccountId(accountId);
clearingAccount.setClearingAccountType("CAT");
clearingAccountId = clearingAccountImdg.insert(clearingAccount);
InformationAccount informationAccount = new InformationAccount();
informationAccount.setAccountId(account2Id);
infoAccountId = informationAccountImdg.insert(informationAccount);
}
@Test
void tradingClearingRegistryNew_moneyAccount_clearingAccount() {
TradingClearingRegistryNewRequest tradingClearingRegistryNewRequest = new TradingClearingRegistryNewRequest();
tradingClearingRegistryNewRequest.setCompanyId(companyId);
tradingClearingRegistryNewRequest.setMoneyAccountId(clearingAccountId);
TradingClearingRegistry predictableTradingClearingRegistry = new TradingClearingRegistry();
predictableTradingClearingRegistry.setCompanyId(companyId);
predictableTradingClearingRegistry.setCode("0077MAT");
predictableTradingClearingRegistry.setMoneyAccountId(clearingAccountId);
predictableTradingClearingRegistry.setTradingClearingRegistryType("CAT");
predictableTradingClearingRegistry.setTradingClearingRegistryPurpose(TradingClearingRegistryPurpose.M.getKey());
predictableTradingClearingRegistry.setStatus(ServiceStatus.Active.getKey());
String jsonString = getJsonStringForNew(tradingClearingRegistryNewRequest, 0L);
addRecordToKafka((MockConsumer) tradingClearingRegistryService.getConsumer(),
Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW,
newRequestCnt,
0,
jsonString);
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
TradingClearingRegistry resultNew = tradingClearingRegistryImdg.getAllValues().iterator().next();
predictableTradingClearingRegistry.setId(resultNew.getId());
predictableTradingClearingRegistry.setCode(predictableTradingClearingRegistry.getCode() + resultNew.getId());
predictableTradingClearingRegistry.setUpdated(resultNew.getUpdated());
predictableTradingClearingRegistry.setCreated(resultNew.getCreated());
TRADING_CLEARING_REGISTRY_MATCHER.assertMatch(resultNew, predictableTradingClearingRegistry);
tradingClearingRegistryImdg.delete(resultNew);
newRequestCnt++;
}
@Test
void tradingClearingRegistryNew_moneyAccount_informationAccount() {
TradingClearingRegistryNewRequest tradingClearingRegistryNewRequest = new TradingClearingRegistryNewRequest();
tradingClearingRegistryNewRequest.setCompanyId(companyId);
tradingClearingRegistryNewRequest.setMoneyAccountId(infoAccountId);
TradingClearingRegistry predictableTradingClearingRegistry = new TradingClearingRegistry();
predictableTradingClearingRegistry.setCompanyId(companyId);
predictableTradingClearingRegistry.setCode("0077MAT");
predictableTradingClearingRegistry.setMoneyAccountId(infoAccountId);
predictableTradingClearingRegistry.setTradingClearingRegistryType(TradingClearingRegistryType.Owner_A.getKey());
predictableTradingClearingRegistry.setTradingClearingRegistryPurpose(TradingClearingRegistryPurpose.M.getKey());
predictableTradingClearingRegistry.setStatus(ServiceStatus.Active.getKey());
String jsonString = getJsonStringForNew(tradingClearingRegistryNewRequest, 0L);
addRecordToKafka((MockConsumer) tradingClearingRegistryService.getConsumer(),
Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW,
newRequestCnt,
0,
jsonString);
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
TradingClearingRegistry resultNew = tradingClearingRegistryImdg.getAllValues().iterator().next();
predictableTradingClearingRegistry.setId(resultNew.getId());
predictableTradingClearingRegistry.setCode(predictableTradingClearingRegistry.getCode() + resultNew.getId());
predictableTradingClearingRegistry.setUpdated(resultNew.getUpdated());
predictableTradingClearingRegistry.setCreated(resultNew.getCreated());
TRADING_CLEARING_REGISTRY_MATCHER.assertMatch(resultNew, predictableTradingClearingRegistry);
tradingClearingRegistryImdg.delete(resultNew);
newRequestCnt++;
}
@Test
void tradingClearingRegistryNew_depoAccount() {
TradingClearingRegistryNewRequest tradingClearingRegistryNewRequest = new TradingClearingRegistryNewRequest();
tradingClearingRegistryNewRequest.setCompanyId(companyId);
tradingClearingRegistryNewRequest.setMoneyAccountId(clearingAccountId);
tradingClearingRegistryNewRequest.setDepoAccountId(depoAccountId);
TradingClearingRegistry predictableTradingClearingRegistry = new TradingClearingRegistry();
predictableTradingClearingRegistry.setCompanyId(companyId);
predictableTradingClearingRegistry.setCode("0077CDAT");
predictableTradingClearingRegistry.setMoneyAccountId(clearingAccountId);
predictableTradingClearingRegistry.setDepoAaccountId(depoAccountId);
predictableTradingClearingRegistry.setTradingClearingRegistryType("DAT");
predictableTradingClearingRegistry.setTradingClearingRegistryPurpose(TradingClearingRegistryPurpose.C.getKey());
predictableTradingClearingRegistry.setStatus(ServiceStatus.Active.getKey());
String jsonString = getJsonStringForNew(tradingClearingRegistryNewRequest, 0L);
addRecordToKafka((MockConsumer) tradingClearingRegistryService.getConsumer(),
Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW,
newRequestCnt,
0,
jsonString);
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
TradingClearingRegistry resultNew = tradingClearingRegistryImdg.getAllValues().iterator().next();
predictableTradingClearingRegistry.setId(resultNew.getId());
predictableTradingClearingRegistry.setCode(predictableTradingClearingRegistry.getCode() + resultNew.getId());
predictableTradingClearingRegistry.setUpdated(resultNew.getUpdated());
predictableTradingClearingRegistry.setCreated(resultNew.getCreated());
TRADING_CLEARING_REGISTRY_MATCHER.assertMatch(resultNew, predictableTradingClearingRegistry);
tradingClearingRegistryImdg.delete(resultNew);
newRequestCnt++;
}
@Test
void tradingClearingRegistryUpdate() {
TradingClearingRegistry existTradingClearingRegistry = new TradingClearingRegistry();
existTradingClearingRegistry.setStatus(ServiceStatus.Closed.getKey());
Long registryId = tradingClearingRegistryImdg.insert(existTradingClearingRegistry);
TradingClearingRegistryUpdateRequest tradingClearingRegistryUpdateRequest = new TradingClearingRegistryUpdateRequest();
tradingClearingRegistryUpdateRequest.setStatus(ServiceStatus.Active.getKey());
tradingClearingRegistryUpdateRequest.setId(registryId);
String jsonString = getJsonStringForUPDATE(tradingClearingRegistryUpdateRequest, 0);
//ACT
addRecordToKafka((MockConsumer) tradingClearingRegistryService.getConsumer(),
Consts.DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE,
PARTITION,
0,
jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
TradingClearingRegistry resultUpdating = tradingClearingRegistryImdg.getSingleObjectByID(registryId);
existTradingClearingRegistry.setUpdated(resultUpdating.getUpdated());
existTradingClearingRegistry.setStatus(ServiceStatus.Active.getKey());
TRADING_CLEARING_REGISTRY_MATCHER.assertMatch(resultUpdating, existTradingClearingRegistry);
tradingClearingRegistryImdg.delete(resultUpdating);
}
@Test
void tradingClearingRegistryBlock() {
TradingClearingRegistry existTradingClearingRegistry = new TradingClearingRegistry();
existTradingClearingRegistry.setStatus(ServiceStatus.Closed.getKey());
Long registryId = tradingClearingRegistryImdg.insert(existTradingClearingRegistry);
CommonDeleteRequest tradingClearingRegistryDeleteRequest = new CommonDeleteRequest();
tradingClearingRegistryDeleteRequest.setId(registryId);
String jsonString = getJsonStringForDELETE(tradingClearingRegistryDeleteRequest, 0);
//ACT
addRecordToKafka((MockConsumer) tradingClearingRegistryService.getConsumer(),
Consts.DESTINATION_TRADING_CLEARING_REGISTRY_BLOCK,
PARTITION,
0,
jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(0L, producer, producerRecord);
TradingClearingRegistry resultUpdating = tradingClearingRegistryImdg.getSingleObjectByID(registryId);
existTradingClearingRegistry.setUpdated(resultUpdating.getUpdated());
existTradingClearingRegistry.setStatus(ServiceStatus.Blocked.getKey());
TRADING_CLEARING_REGISTRY_MATCHER.assertMatch(resultUpdating, existTradingClearingRegistry);
tradingClearingRegistryImdg.delete(resultUpdating);
}
}

View file

@ -14,6 +14,7 @@ import ru.spcex.clearing.backendapi.controller.request.cud.company.CompanyInfoUp
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.CommonGetAllResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.company.CompanyInfoBackendGetAll;
import ru.spcex.clearing.backendapi.meta.GetResponseFactory;
import ru.spcex.clearing.backendapi.service.IOperator;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
@ -53,19 +54,14 @@ public class CompanyInfoController extends AbstractQueueController {
}
@ApiOperation(value = "get all CompanyInfo's.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CommonGetAllResponse.class)})
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CompanyInfoBackendGetAll.class)})
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public CommonGetAllResponse getAll() {
public CompanyInfoBackendGetAll getAll() {
Collection<Map<String, Object>> all = new ArrayList<>();
Collection<Company> companies = companyImdg.getAllValues();
for (Company company : companies) {
if (company.getProfile() != null && company.getProfile().getId() != null) { // пока возвращает "пустой" CompanyInfo если его нет для Company
all.add(responseFactory.responseFromObject(company.getProfile()));
}
}
CommonGetAllResponse response = new CommonGetAllResponse();
response.fromEntity(all);
CompanyInfoBackendGetAll response = new CompanyInfoBackendGetAll();
response.fromEntity(companies);
return response;
}
}

View file

@ -10,9 +10,9 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.backendapi.controller.queue.AbstractQueueController;
import ru.spcex.clearing.backendapi.controller.request.cud.common.CommonDeleteAction;
import ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryNewAction;
import ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryUpdateAction;
import ru.spcex.clearing.backendapi.controller.request.cud.common.CommonDeleteAction;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.CommonGetAllResponse;
@ -69,7 +69,7 @@ public class TradingClearingRegistryController extends AbstractQueueController {
@PathVariable("id") Long id) throws ExecutionException, InterruptedException {
CommonDeleteAction deleteAction = new CommonDeleteAction();
deleteAction.setId(id);
return processRequest(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_DELETE, deleteAction);
return processRequest(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_BLOCK, deleteAction);
}
@ApiOperation(value = "get TradingClearingRegistry by id.")

View file

@ -0,0 +1,48 @@
package ru.spcex.clearing.backendapi.controller.response.entity.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import ru.clearing.classes.statics.data.company.Company;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ApiModel(description = "Ответ при получении объектов CompanyInfos.")
public class CompanyInfoBackendGetAll extends BasicSpcexResponse {
@JsonProperty
@ApiModelProperty(value = "Полезная нагрузка")
private CompanyInfoBackendPayload payload = new CompanyInfoBackendPayload();
private static class CompanyInfoBackendPayload {
private List<CompanyInfoBackendGetFields> items = new ArrayList<>();
public List<CompanyInfoBackendGetFields> getItems() {
return items;
}
public void setItems(List<CompanyInfoBackendGetFields> items) {
this.items = items;
}
}
public CompanyInfoBackendPayload getPayload() {
return payload;
}
public void setPayload(CompanyInfoBackendPayload payload) {
this.payload = payload;
}
public void fromEntity(Collection<Company> companys) {
var payload = this.getPayload();
for (var company : companys) {
var singleItem = CompanyInfoBackendGetFields.fromEntity(company);
payload.getItems().add(singleItem);
}
}
}

View file

@ -0,0 +1,224 @@
package ru.spcex.clearing.backendapi.controller.response.entity.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.profile.CompanyInfo;
public class CompanyInfoBackendGetFields {
@JsonProperty
@ApiModelProperty(value = "Идентификатор записи")
private Long id;
@JsonProperty
@ApiModelProperty(value = "Идентификатор компании")
private Long companyId;
@JsonProperty
@ApiModelProperty(value = "Код единоличного исполнительного органа")
private String corporationSoleType;
@JsonProperty
@ApiModelProperty(value = "Код юрисдикции")
private String countryCode;
@JsonProperty
@ApiModelProperty(value = "Описание компании")
private String description;
@JsonProperty
@ApiModelProperty(value = "Код признака профессионального участника")
private String professionalSign;
@JsonProperty
@ApiModelProperty(value = "Код вида субъекта")
private String legalKind;
@JsonProperty
@ApiModelProperty(value = "Код типа организации")
private String organizationType;
@JsonProperty
@ApiModelProperty(value = "Код резиденции")
private String residence;
@JsonProperty
@ApiModelProperty(value = "Краткое наименование компании")
private String shortName;
@JsonProperty
@ApiModelProperty(value = "Полное наименование компании")
private String fullName;
@JsonProperty
@ApiModelProperty(value = "Краткое наименование компании на английском")
private String shortNameEng;
@JsonProperty
@ApiModelProperty(value = "Краткое наименование компании на английском")
private String fullNameEng;
@JsonProperty
@ApiModelProperty(value = "Код участника торгов")
private String tradingCode;
@JsonProperty
@ApiModelProperty(value = "Код участника клиринга")
private String clearingCode;
@JsonProperty
@ApiModelProperty(value = "Регистрационный код участника")
private String registrationCode;
@JsonProperty
@ApiModelProperty(value = "Наименование статуса")
private String workflowStatus;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getCorporationSoleType() {
return corporationSoleType;
}
public void setCorporationSoleType(String corporationSoleType) {
this.corporationSoleType = corporationSoleType;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getProfessionalSign() {
return professionalSign;
}
public void setProfessionalSign(String professionalSign) {
this.professionalSign = professionalSign;
}
public String getLegalKind() {
return legalKind;
}
public void setLegalKind(String legalKind) {
this.legalKind = legalKind;
}
public String getOrganizationType() {
return organizationType;
}
public void setOrganizationType(String organizationType) {
this.organizationType = organizationType;
}
public String getResidence() {
return residence;
}
public void setResidence(String residence) {
this.residence = residence;
}
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getShortNameEng() {
return shortNameEng;
}
public void setShortNameEng(String shortNameEng) {
this.shortNameEng = shortNameEng;
}
public String getFullNameEng() {
return fullNameEng;
}
public void setFullNameEng(String fullNameEng) {
this.fullNameEng = fullNameEng;
}
public String getTradingCode() {
return tradingCode;
}
public void setTradingCode(String tradingCode) {
this.tradingCode = tradingCode;
}
public String getClearingCode() {
return clearingCode;
}
public void setClearingCode(String clearingCode) {
this.clearingCode = clearingCode;
}
public String getRegistrationCode() {
return registrationCode;
}
public void setRegistrationCode(String registrationCode) {
this.registrationCode = registrationCode;
}
public String getWorkflowStatus() {
return workflowStatus;
}
public void setWorkflowStatus(String workflowStatus) {
this.workflowStatus = workflowStatus;
}
public static CompanyInfoBackendGetFields fromEntity(Company company) {
if (company == null || company.getProfile() == null) {
return null;
}
CompanyInfo info = company.getProfile();
CompanyInfoBackendGetFields fields = new CompanyInfoBackendGetFields();
fields.setId(info.getId());
fields.setCompanyId(info.getCompanyId());
fields.setCorporationSoleType(info.getCorporationSoleType());
fields.setCountryCode(info.getCountryCode());
fields.setDescription(info.getDescription());
fields.setProfessionalSign(info.getProfessionalSign());
fields.setLegalKind(info.getLegalKind());
fields.setOrganizationType(info.getOrganizationType());
fields.setResidence(info.getResidence());
fields.setShortNameEng(info.getShortNameEng());
fields.setFullNameEng(info.getFullNameEng());
fields.setShortName(company.getShortName());
fields.setFullName(company.getFullName());
fields.setTradingCode(company.getTradingCode());
fields.setClearingCode(company.getClearingCode());
fields.setRegistrationCode(company.getRegistrationCode());
fields.setWorkflowStatus(company.getWorkflowStatus());
return fields;
}
}

View file

@ -36,10 +36,12 @@ public class TradingClearingRegistryBackendGetFields {
@ApiModelProperty(value = "Наименование статуса", example = "ACTV")
private String status;
@JsonProperty("Дата-время создания записи")
@JsonProperty
@ApiModelProperty(value = "Дата-время создания записи")
@JsonSerialize(using = InstantSerializer.class)
private Instant createdAt;
@JsonProperty("Дата-время изменения записи")
@JsonProperty
@ApiModelProperty(value = "Дата-время изменения записи")
@JsonSerialize(using = InstantSerializer.class)
private Instant updatedAt;

View file

@ -80,7 +80,7 @@
<companySymbol id="16" code="CLRC" name="Код участника клиринга" shortname="Клиринговый код"/>
<companySymbol id="17" code="RGRC" name="Регистрационный код участника" shortname="Регистрационный код"/>
<companySymbol id="18" code="UUID" name="Идентификатор во внешней системе" shortname="Внешний идентификатор"/>
<companySymbol id="19" code="RDPZ" name="Требуется получение документа о подтверждении открытия депозитного счета" shortname="Подтверждение депозитного счета"/>
<companySymbol id="19" code="LICM" name="Лицензия на управление инвестиционными фондами, паевыми инвестиционными фондами, негосударственными пенсионными фондами" shortname="Лицензия на управление фондами"/>
<companyRole id="1" code="RPRT" name="Отчетная организация"/>
<companyRole id="2" code="CLRH" name="Клиринговая организация"/>
<companyRole id="3" code="EXCH" name="Торговая система"/>
@ -198,7 +198,7 @@
<task id="9" code="GVER" name="Запуск сверки"/>
<task id="12" code="CMBA" name="Формирование распоряжения на перевод с ТБС"/>
<task id="14" code="GCMR" name="Формирование реестра участников клиринга"/>
<task id="15" code="GBRR" name="Формирование реестра остатков денежных средств "/>
<task id="15" code="GBRR" name="Формирование реестра остатков денежных средств"/>
<task id="16" code="GORR" name="Формирование реестра распоряжений, направленных расчетной организации"/>
<task id="17" code="GREP" name="Формирование отчетности"/>
<task id="21" code="GSRR" name="Формирование реестра отправленных отчетов"/>

View file

@ -6,9 +6,9 @@ import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.backendapi.controller.queue.AbstractControllerTest;
import ru.spcex.clearing.backendapi.controller.request.cud.common.CommonDeleteAction;
import ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryNewAction;
import ru.spcex.clearing.backendapi.controller.request.cud.registry.TradingClearingRegistryUpdateAction;
import ru.spcex.clearing.backendapi.controller.request.cud.common.CommonDeleteAction;
import ru.spcex.clearing.backendapi.controller.response.entity.registry.TradingClearingRegistryBackendGetById;
import ru.spcex.clearing.backendapi.controller.response.entity.registry.TradingClearingRegistryBackendGetFields;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
@ -97,7 +97,7 @@ class TradingClearingRegistryControllerTest extends AbstractControllerTest {
deleteAction.setId(id);
//ACT and ASSERT
checkDeletingByRestApi(REST_URL, id);
checkSendedMessegeFromKafka(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_DELETE, deleteAction);
checkSendedMessegeFromKafka(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_BLOCK, deleteAction);
}
/**

View file

@ -15,6 +15,7 @@ public class TradingClearingRegistry extends BusinessObject {
private Long companyId;
private String code;
private Long moneyAccountId;
// todo fix typo
private Long depoAaccountId;
private String tradingClearingRegistryType;
private String tradingClearingRegistryLevel;

View file

@ -1,5 +1,6 @@
package ru.spcex.clearing.util.services;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.clearing.platform.dictionary.ErrorCodeDictionary;
@ -25,13 +26,17 @@ public class IMDGMessageResolver implements IMessageResolver {
@Override
public String resolve(EnumMessage errorMessage) {
if (errorMessage == null) return "null";
ErrorCodeDictionary errorDictionary = errorCodeDictionaryIMDG.getSingleObjectByID(errorMessage.getSubject().getId());
if (errorDictionary == null) {
log.warn("ERROR_CODE_DICTIONARY not found fo id={}", errorMessage.getSubject().getId());
try {
ErrorCodeDictionary errorDictionary = errorCodeDictionaryIMDG.getSingleObjectByID(errorMessage.getSubject().getId());
if (errorDictionary == null) {
log.warn("ERROR_CODE_DICTIONARY not found fo id={}", errorMessage.getSubject().getId());
return String.format("(%d) args %s", errorMessage.getSubject().getId(), Arrays.toString(errorMessage.getArgs()));
}
String textTemplate = errorDictionary.getName();
return String.format(textTemplate, errorMessage.getArgs());
} catch (Exception errFormatting) { // MissingFormatArgumentException
log.warn("Error in message resolver for error {}: {}", errorMessage.getSubject(), ExceptionUtils.getStackTrace(errFormatting));
return String.format("(%d) args %s", errorMessage.getSubject().getId(), Arrays.toString(errorMessage.getArgs()));
}
String textTemplate = errorDictionary.getName();
return String.format(textTemplate, errorMessage.getArgs());
}
}

View file

@ -1,8 +1,7 @@
package ru.spcex.clearing.company.util;
package ru.spcex.clearing.util.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.platform.messaging.service.Status;
@ -22,21 +21,28 @@ import java.util.Objects;
* callback(CompanyNewRequest.class)
* .setFunction( request -> requestHelper.requestFunction(this::createCompany, request))
* .forDestination(Consts.DESTINATION_COMPANY_NEW, callbacks::put);
*
* return requestHelper.makeErrorResponse(CompanyError.GeneralError, ...)
*/
public class RequestHelper {
protected Logger log = LoggerFactory.getLogger(getClass());
protected final IMessageResolver messageResolver;
protected final IErrorEnumId generalError;
public RequestHelper(IMessageResolver messageResolver) {
public RequestHelper(IMessageResolver messageResolver, IErrorEnumId generalError) {
Objects.requireNonNull(messageResolver);
this.messageResolver = messageResolver;
this.generalError = generalError;
Objects.requireNonNull(generalError, "Required generalError enum");
}
public RequestHelper(Logger log, IMessageResolver messageResolver) {
public RequestHelper(Logger log, IMessageResolver messageResolver, IErrorEnumId generalError) {
Objects.requireNonNull(log);
Objects.requireNonNull(messageResolver);
this.log = log;
this.messageResolver = messageResolver;
this.generalError = generalError;
Objects.requireNonNull(generalError, "Required generalError enum");
}
/**
@ -58,13 +64,14 @@ public class RequestHelper {
String message = expectedE.getEnumMsg() == null
? expectedE.getMessage()
: messageResolver.resolve(expectedE.getEnumMsg());
log.info("Response: {}", message);
return new RequestInfoUpdate()
.setId(userRequest.getId())
.setStatus(Status.Error)
.setMessage(message);
} catch (Exception unexpectedE) {
log.error("Error at {}: {} ", command, ExceptionUtils.getStackTrace(unexpectedE));
String message = messageResolver.resolve(new EnumMessage(CompanyErrors.GeneralError));
String message = messageResolver.resolve(new EnumMessage(generalError));
return new RequestInfoUpdate()
.setId(userRequest.getId())
.setStatus(Status.Error)
@ -74,6 +81,7 @@ public class RequestHelper {
public RequestInfoUpdate makeErrorResponse(BaseRequest<?> request, EnumMessage msg) {
String errorMsg = msg == null? "" : messageResolver.resolve(msg);
log.info("Response: {}", errorMsg);
return new RequestInfoUpdate()
.setId(request.getId())
.setStatus(Status.Error)

View file

@ -1,66 +1,216 @@
package ru.spcex.clearing.util.services.exchangers;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
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.AccountBalanceClearingRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.clearing.Sdf04Request;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
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.platform.enumeration.Task;
import ru.spcex.platform.utils.log.ExceptionUtils;
import java.io.Closeable;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Синхронный обмен сообщениями с ассинхронным сервисом.
* Метод exchange() отправляет сообщение в очередь и дожидается ответа из другой очереди
* Метод exchange() отправляет сообщение в очередь и дожидается ответа из другой очереди.
* Использовать с осторожностью, т.к. нет возобновления ожидания в случае нештатного выключения модуля при ожидании ответа из kafka.
* <p>
* <p>
* Ожидает из очереди (CommonIdRequest)
*
* @param <TOut> отправляется в очередь
*/
public class BiDirectionQueueExchanger<TIn, TOut extends BaseRequest<?>> extends QueueConsumer implements InitializingBean, DisposableBean {
public class BiDirectionQueueExchanger<TOut extends BaseRequest<?>> extends QueueConsumer implements Closeable {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final Object sync = new Object();
protected String outQueue;
protected String inQueue;
protected Class<TIn> listenClass;
protected long timeout;
private Producer<String, Object> producer;
protected volatile boolean isTerminated;
protected Object syncObject;
protected Long lastSentRequestId;
protected volatile Long lastResponseId;
protected boolean ignoreOtherResponse = true; // Пропускать другие ID, пока не получит lastResponseId==lastSentRequestId
/**
* Синхронно-ассинхронный обмен сообщениями
*
* @param kafkaQueue
* @param kafkaQueue уникальный kafka Consumer (Spring prototype). Нельзя переиспользовать существующие.
* @param kafkaProducer
* @param outQueue отправляет в очередь
* @param inQueue слушает очередь, ожидает ответов
* @param listenClass типы объектов из inQueue
* @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено
* @param inQueue слушает очередь/топик, ожидает ответов. Пример: Consts.CONTINUE_CLEARING
* @param ignoreOtherResponse true для inQueue=Consts.REQUEST_INFO_UPDATE
* @param timeout - максимальное ожидание ответа, в миллисекундах, 0 - неограничено
*/
public BiDirectionQueueExchanger(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer,
String outQueue,
String inQueue, Class<TIn> listenClass,
String inQueue,
boolean ignoreOtherResponse,
long timeout) {
super(kafkaQueue, kafkaProducer);
super(kafkaQueue);
this.producer = kafkaProducer;
if (kafkaQueue == null) {
throw new IllegalArgumentException("kafkaQueue is empty");
}
if (kafkaProducer == null) {
throw new IllegalArgumentException("kafkaProducer is empty");
}
if (StringUtils.isEmpty(outQueue)) {
throw new IllegalArgumentException("outQueue is empty");
}
this.outQueue = outQueue;
if (StringUtils.isEmpty(inQueue)) {
throw new IllegalArgumentException("inQueue is empty");
}
this.inQueue = inQueue;
this.listenClass = listenClass;
if (timeout < 0) {
timeout = 0;
}
this.timeout = timeout;
this.ignoreOtherResponse = ignoreOtherResponse;
initReplyListener();
}
/**
* Отправить сообщение message в outQueue и дождаться ответа из очереди inQueue
*
* @param message
* @return
* @throws InterruptedException
* @return request/reply id
* @throws InterruptedException или когда поток прерывают, или когда BiDirectionQueueExchanger.close()
*/
public TOut exchange(TIn message) throws InterruptedException {
//todo impl BiDirectionQueueExchanger
return null;
public Long exchange(TOut message) throws InterruptedException {
if (syncObject == null)
throw new IllegalStateException("Listener queue not initialized");
if (message.getId() == null) {
throw new IllegalArgumentException("Required message " + message.getClass().getSimpleName() + ".id is null");
}
//send request to kafka, wait for a reply
try {
synchronized (syncObject) {
Long sentRequestId = sendMessage(message);
log.trace("sent request to kafka, requestId: {}", sentRequestId);
this.lastSentRequestId = sentRequestId;
long waitStart = System.currentTimeMillis();
long waitTime = timeout;
do {
try {
if (timeout > 0) {
syncObject.wait(waitTime);
} else {
syncObject.wait();
}
//если на этом месте произошла ошибка - непонятно как обрабатывать
//т.к. request на самом деле могла быть проблема с сетью/недоступностью кафки etc.
} catch (InterruptedException e) {
log.error(ExceptionUtils.getStackTrace(e));
throw e;
// Thread.currentThread().interrupt();
// throw new RuntimeException(e);
}
waitTime = timeout - (System.currentTimeMillis() - waitStart);
if (isTerminated && lastResponseId == null) {
log.warn("Terminated waiter {} kafka at thread {}", this, Thread.currentThread().getName());
throw new InterruptedException(getClass().getSimpleName() + " closed");
}
if (ignoreOtherResponse && !sentRequestId.equals(lastResponseId)) {
log.debug("Ignore response id={}, we waiting {}.", lastResponseId, sentRequestId);
}
} while (ignoreOtherResponse && !sentRequestId.equals(lastResponseId) && (timeout > 0 && waitTime > 0));
if (!sentRequestId.equals(lastResponseId)) {
log.error("FATAL: last response from {} update from Kafka ID was {}, but sent ID was {}",
inQueue, lastResponseId, sentRequestId);
throw new IllegalStateException("Expected wait till requestId=" + sentRequestId + " but catch lastResponseId=" + lastResponseId);
}
return sentRequestId;
}
} finally {
this.lastSentRequestId = null;
}
}
@Override
public void destroy() throws Exception {
public void close() {
isTerminated = true;
if (lastSentRequestId != null) {
log.warn("Finished before wait, lastSentRequestId={}", lastSentRequestId);
if (syncObject != null) {
synchronized (syncObject) {
lastResponseId = null;
syncObject.notifyAll();
}
}
}
syncObject = null;
log.debug("Listener {} for async exchange {}-{} close", this, outQueue, inQueue);
}
@Override
public void afterPropertiesSet() throws Exception {
protected void initReplyListener() {
if (syncObject != null) {
throw new IllegalStateException("Already initialized");
}
callback(CommonIdRequest.class)
.setConsumer(this::continueWaiting)
.forDestination(inQueue, callbacks::put);
init();
syncObject = new Object();
isTerminated = false;
log.debug("Listener {} for async exchange {}-{} ready", this, outQueue, inQueue);
}
protected Long sendMessage(TOut message) throws InterruptedException {
Long sentRequestId = message.getId();
if (sentRequestId == null) {
throw new IllegalArgumentException("Message " + message.getClass().getSimpleName() + " required id.");
}
try {
Future<RecordMetadata> send = producer.send(new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, message));
send.get();
return sentRequestId;
} catch (InterruptedException e) {
log.error("Interrupt when send message, {}", ExceptionUtils.getStackTrace(e));
Thread.currentThread().interrupt();
throw e;
} catch (ExecutionException e) {
log.error("Error at send message, {} cause: {}", e.toString(), ExceptionUtils.getStackTrace(e.getCause()));
throw new RuntimeException("Send message error", e.getCause());
} catch (Exception e) {
log.error("Unexpected exception when send message: {}", ExceptionUtils.getStackTrace(e));
}
return null;
}
protected void continueWaiting(BaseRequest<CommonIdRequest> event) {
synchronized (syncObject) {
CommonIdRequest requestPayload = event.getRequestPayload();
log.debug("continueWaiting {} for id={}", inQueue, requestPayload.getId());
lastResponseId = requestPayload.getId();
syncObject.notifyAll();
}
}
}

View file

@ -5,7 +5,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.company.util.RequestHelper;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.platform.enumeration.UserRole;
import ru.spcex.platform.imdg.api.ImdgProvider;
@ -22,7 +22,7 @@ public class BeanConfiguration {
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RequestHelper requestHelper(IMessageResolver messageResolver) {
return new RequestHelper(messageResolver);
return new RequestHelper(messageResolver, CompanyErrors.GeneralError);
}
@Bean

View file

@ -0,0 +1,162 @@
package ru.spcex.clearing.company.config.validation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.ClientCode;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.platform.dictionary.WorkflowStatusDictionary;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
@Configuration
public class ClientCodeValidationConfig {
@Bean("clientCodeNewRequestValidator")
public Function<ClientCodeNewRequest, IValidator> clientCodeNewRequestValidator(Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation) {
return clientCodeUpdateRequest -> {
ImdgValidationContext<ClientCodeNewRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(clientCodeUpdateRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Company);
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry);
addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary);
return new ValidatorImpl<>(context,
FieldRequiredRule.instance("companyId", ClientCodeNewRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty),
IdPresentRule.instance("companyId",
ClientCodeNewRequest::getCompanyId,
IMDGDistributedNames.Map_Company,
Company.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.CompanyNotFound),
IdPresentRule.instance("moneyAccountId",
ClientCodeNewRequest::getMoneyAccountId,
IMDGDistributedNames.Map_Account,
Account.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.AccountNotFound,
false,
acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId())
? null : CompanyErrors.AccountNotFound
),
IdPresentRule.instance("depoAccountId",
ClientCodeNewRequest::getDepoAccountId,
IMDGDistributedNames.Map_Account,
Account.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.AccountNotFound,
false,
acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId())
? null : CompanyErrors.AccountNotFound
),
DictionaryPresentRule.instance("stauts",
ClientCodeNewRequest::getStatus,
IMDGDistributedNames.Map_WorkflowStatusDictionary,
WorkflowStatusDictionary.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.DictionaryNotFound,
false)
);
};
}
@Bean("clientCodeUpdateRequestValidator")
public Function<ClientCodeUpdateRequest, IValidator> clientCodeUpdateRequestValidator(Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation) {
return clientCodeUpdateRequest -> {
ImdgValidationContext<ClientCodeUpdateRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(clientCodeUpdateRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_ClientCode);
addImdg.accept(IMDGDistributedNames.Map_Company);
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry);
addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary);
return new ValidatorImpl<ImdgValidationContext<ClientCodeUpdateRequest>>(context,
IdPresentRule.instance("id",
ClientCodeUpdateRequest::getId,
IMDGDistributedNames.Map_ClientCode,
ClientCode.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.RecordNotFound
),
FieldRequiredRule.instance("companyId", ClientCodeUpdateRequest::getCompanyId, CompanyErrors.RequiredFieldEmpty),
IdPresentRule.instance("companyId",
ClientCodeUpdateRequest::getCompanyId,
IMDGDistributedNames.Map_Company,
Company.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.CompanyNotFound),
IdPresentRule.instance("moneyAccountId",
ClientCodeUpdateRequest::getMoneyAccountId,
IMDGDistributedNames.Map_Account,
Account.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.AccountNotFound,
false,
acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId())
? null : CompanyErrors.AccountNotFound
),
IdPresentRule.instance("depoAccountId",
ClientCodeUpdateRequest::getDepoAccountId,
IMDGDistributedNames.Map_Account,
Account.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.AccountNotFound,
false,
acc -> Objects.equals(context.getValidatedObject().getCompanyId(), acc.getCompanyId())
? null : CompanyErrors.AccountNotFound
),
DictionaryPresentRule.instance("stauts",
ClientCodeUpdateRequest::getStatus,
IMDGDistributedNames.Map_WorkflowStatusDictionary,
WorkflowStatusDictionary.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.DictionaryNotFound,
false)
);
};
}
@Bean("clientCodeDeleteRequestValidator")
public Function<CommonDeleteRequest, IValidator> clientCodeDeleteRequestValidator(Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation) {
return companyDeleteRequest -> {
ImdgValidationContext<CommonDeleteRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(companyDeleteRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_ClientCode);
return new ValidatorImpl<>(context,
// FieldRequiredRule.instance("id", CommonDeleteRequest::getId, CompanyErrors.RequiredFieldEmpty),
IdPresentRule.instance("id",
CommonDeleteRequest::getId,
IMDGDistributedNames.Map_ClientCode,
ClientCode.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.RecordNotFound)
);
};
}
}

View file

@ -73,7 +73,7 @@ public class ContactValidationConfig {
IMDGDistributedNames.Map_Contact,
Contact.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.CompanyNotFound,
CompanyErrors.ContactNotFound,
contact -> {
if (contactUpdateRequest.getContactType() == null) return null;
if (!contactUpdateRequest.getContactType().equalsIgnoreCase(contact.getContactType())) {

View file

@ -44,7 +44,7 @@ public class ProfileDocumentValidationConfig {
Company.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.CompanyNotFound,
company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled),
company -> WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? null : CompanyErrors.CompanyDisabled),
DictionaryPresentRule.instance("documentType",
ProfileDocumentNewRequest::getDocumentType,
IMDGDistributedNames.Map_DocumentTypeDictionary,
@ -138,7 +138,15 @@ public class ProfileDocumentValidationConfig {
IMDGDistributedNames.Map_ProfileDocument,
ProfileDocument.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.RecordNotFound)
CompanyErrors.RecordNotFound,
profileDoc -> {
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
Company company = companyImdg.getSingleObjectByID(profileDoc.getCompanyId());
if (company == null) {
return CompanyErrors.CompanyNotFound;
}
return null;
})
);
};
}

View file

@ -0,0 +1,134 @@
package ru.spcex.clearing.company.config.validation;
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.platform.dictionary.ClearingCategoryDictionary;
import ru.clearing.platform.dictionary.WorkflowStatusDictionary;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.RelationNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.RelationUpdateRequest;
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@Configuration
public class RelationValidationConfig {
@Bean("relationNewRequestValidation")
public Function<RelationNewRequest, IValidator> relationNewRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return relationNewRequest -> {
ImdgValidationContext<RelationNewRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(relationNewRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Company);
addImdg.accept(IMDGDistributedNames.Map_ClearingCategoryDictionary);
addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary);
return new ValidatorImpl<>(context,
IdPresentRule.instance("companyId",
RelationNewRequest::getCompanyId,
IMDGDistributedNames.Map_Company,
Company.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.CompanyNotFound),
DictionaryPresentRule.instance("documentType",
RelationNewRequest::getClearingMemberCategory,
IMDGDistributedNames.Map_ClearingCategoryDictionary,
ClearingCategoryDictionary.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.WrongFieldValue),
DictionaryPresentRule.instance("serviceStatus",
RelationNewRequest::getServiceStatus,
IMDGDistributedNames.Map_WorkflowStatusDictionary,
WorkflowStatusDictionary.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.WrongFieldValue)
);
};
}
@Bean("relationUpdateRequestValidation")
public Function<RelationUpdateRequest, IValidator> relationUpdateRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return relationUpdateRequest -> {
ImdgValidationContext<RelationUpdateRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(relationUpdateRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Relation);
addImdg.accept(IMDGDistributedNames.Map_Company);
// addImdg.accept(IMDGDistributedNames.Map_ClearingCategoryDictionary);
addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary);
return new ValidatorImpl<>(context,
IdPresentRule.instance("id",
RelationUpdateRequest::getId,
IMDGDistributedNames.Map_Relation,
Relation.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.RelationNotFound,
relation -> {
if (relation.getConsumerId() == null) return null;
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
Company company = companyImdg.getSingleObjectByID(relation.getConsumerId());
if (company == null) {
return CompanyErrors.CompanyNotFound;
} else {
return null;
}
}),
// IdPresentRule.instance("companyId",
// RelationUpdateRequest::getCompanyId,
// IMDGDistributedNames.Map_Company,
// Company.class,
// CompanyErrors.RequiredFieldEmpty,
// CompanyErrors.CompanyNotFound),
// DictionaryPresentRule.instance("documentType",
// RelationUpdateRequest::getClearingMemberCategory,
// IMDGDistributedNames.Map_ClearingCategoryDictionary,
// ClearingCategoryDictionary.class,
// CompanyErrors.RequiredFieldEmpty,
// CompanyErrors.WrongFieldValue),
DictionaryPresentRule.instance("serviceStatus",
RelationUpdateRequest::getServiceStatus,
IMDGDistributedNames.Map_WorkflowStatusDictionary,
WorkflowStatusDictionary.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.WrongFieldValue)
);
};
}
@Bean("relationDeleteRequestValidation")
public Function<CommonDeleteRequest, IValidator> relationDeleteRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return relationDeleteRequest -> {
ImdgValidationContext<CommonDeleteRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(relationDeleteRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Relation);
return new ValidatorImpl<>(context,
IdPresentRule.instance("id",
CommonDeleteRequest::getId,
IMDGDistributedNames.Map_Relation,
Relation.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.RelationNotFound
)
);
};
}
}

View file

@ -2,11 +2,15 @@ package ru.spcex.clearing.company.config.validation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.ClientCode;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.clearing.classes.statics.data.profile.ProfileDocument;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.platform.dictionary.*;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.validation.common.ValidationHelper;
@ -34,6 +38,7 @@ public class ValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_DocumentTypeDictionary, DocumentTypeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_ContactTypeDictionary, ContactTypeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_Contact, Contact.class);
addImdg.accept(IMDGDistributedNames.Map_Relation, Relation.class);
addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary, WorkflowStatusDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
@ -44,6 +49,10 @@ public class ValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_LegalKindDictionary, LegalKindDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_OrganizationTypeDictionary, OrganizationTypeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_ClientCode, ClientCode.class);
addImdg.accept(IMDGDistributedNames.Map_Account, Account.class);
addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
return imdg;
}

View file

@ -22,7 +22,12 @@ public enum CompanyErrors implements IErrorEnumId {
CompanyAlreadyHasLiabilities(3018L), // У компании %s присутствуют обязательства.
CompanyWithCompanySymbolAlreadyExist(3019L), // Компания с %s = %s уже создана" (где первый %s - companySymbol, второй %s - companySymbolValue)
EditCompanySymbols(3020L), // Тип реквизита компании %s не может быть изменен.
EditContactType(3021L) // Тип контакта компании %s не может быть изменен.
EditContactType(3021L), // Тип контакта компании %s не может быть изменен.
TradingClearingRegistryNotFound(3022L), // ТКР с %s не найден
AccountNotFound(3023L), // Счет %s не найден
ClearingMemberCategoryOnMKRAlreadyExist(3024L), // Договорные отношения %s в секции МКР уже созданы.
ClearingMemberCategoryOnFONDAlreadyExist(3025L), // Договорные отношения %s на фондовой секции уже созданы.
RelationNotFound(3026L), // Запись о договорных отношениях не найдена
;
private final Long id;

View file

@ -0,0 +1,413 @@
package ru.spcex.clearing.company.service;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.ClientCode;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.util.services.exchangers.BiDirectionQueueExchanger;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.TradingClearingRegistryType;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgIdGeneratorHazelcast;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.error.ClearingBaseException;
import ru.spcex.platform.utils.log.ExceptionUtils;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Function;
@Service
public class ClientCodeService extends QueueConsumer implements InitializingBean, DisposableBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Producer<String, Object> kafkaProducer;
private final ImdgId idGenerator;
private final Imdg<ClientCode> clientCodeMap;
private final Imdg<Company> companyMap;
private final Imdg<TradingClearingRegistry> tradingClearingRegistryMap;
private final Function<ClientCodeNewRequest, IValidator> clientCodeNewRequestValidator;
private final Function<ClientCodeUpdateRequest, IValidator> clientCodeUpdateRequestValidator;
private final Function<CommonDeleteRequest, IValidator> clientCodeDeleteRequestValidator;
private final ValidationHelper validationHelper;
private final UserRoleVerification userRoleVerification;
private final IMessageResolver messageResolver;
BiDirectionQueueExchanger<BaseRequest<TradingClearingRegistryNewRequest>> accountServiceExchanger;
@Autowired
public ClientCodeService(Consumer<String, Object> kafkaQueue1, Consumer<String, Object> kafkaQueue2,
Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider,
ValidationHelper validationHelper,
IMessageResolver messageResolver,
UserRoleVerification userRoleVerification,
@Qualifier("clientCodeNewRequestValidator") Function<ClientCodeNewRequest, IValidator> clientCodeNewRequestValidator,
@Qualifier("clientCodeUpdateRequestValidator") Function<ClientCodeUpdateRequest, IValidator> clientCodeUpdateRequestValidator,
@Qualifier("clientCodeDeleteRequestValidator") Function<CommonDeleteRequest, IValidator> clientCodeDeleteRequestValidator) {
super(kafkaQueue1, kafkaProducer);
this.kafkaProducer = kafkaProducer;
this.idGenerator = imdgProvider.getImdgIdGenerator();
this.clientCodeMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class);
this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.tradingClearingRegistryMap = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
this.clientCodeNewRequestValidator = clientCodeNewRequestValidator;
this.clientCodeUpdateRequestValidator = clientCodeUpdateRequestValidator;
this.clientCodeDeleteRequestValidator = clientCodeDeleteRequestValidator;
this.validationHelper = validationHelper;
this.messageResolver = messageResolver;
this.userRoleVerification = userRoleVerification;
this.accountServiceExchanger = new BiDirectionQueueExchanger<>(kafkaQueue2, kafkaProducer,
Consts.DESTINATION_TRADING_CLEARING_REGISTRY_NEW,
Consts.REQUEST_INFO_UPDATE, true, // REQUEST_INFO_UPDATE - стандартная очередь, для результатов всех реквестов. DESTINATION_TRADING_CLEARING_REGISTRY_REPLY,
60000
);
}
@Override
public void afterPropertiesSet() {
callback(ClientCodeNewRequest.class)
.setConsumer(this::clientCodeNew)
.forDestination(Consts.DESTINATION_CLIENT_CODE_NEW, callbacks::put);
callback(ClientCodeNewRequest.class)
.setConsumer(this::clientCodeNewFromApiUmCompany)
.forDestination(Consts.DESTINATION_CLIENT_CODE_NEW_UM_COMPANY, callbacks::put);
callback(ClientCodeUpdateRequest.class)
.setConsumer(this::clientCodeUpdate)
.forDestination(Consts.DESTINATION_CLIENT_CODE_UPDATE, callbacks::put);
callback(CommonDeleteRequest.class)
.setConsumer(this::clientCodeDelete)
.forDestination(Consts.DESTINATION_CLIENT_CODE_DELETE, callbacks::put);
init();
}
@Override
public void destroy() {
accountServiceExchanger.close();
}
protected RequestInfoUpdate clientCodeNew(BaseRequest<ClientCodeNewRequest> userRequest) {
log.debug("ClientCodeNewRequest received {}", userRequest.getId());
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeNewRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
ClientCodeNewRequest req = userRequest.getRequestPayload();
boolean doCreateTCR = checkNeedCreateTCR(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
if (doCreateTCR) {
try {
createAndWaitTCR(userRequest.getId(), null,
req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
} catch (ClearingBaseException e) {
log.error("Can not wait creation of TCR. request id={};CompanyId={}, MoneyAccountId={}, DepoAccountId={}; {}",
userRequest.getId(), req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId(),
e.toString());
return makeErrorResponse(userRequest, CompanyErrors.GeneralError, "Can not create TCR at this moment");
}
}
ClientCode newClientCode = buildClientCode(req);
clientCodeMap.insert(newClientCode);
log.debug("successfully processed, new clientCode id {}", newClientCode.getId());
return null;
}
protected RequestInfoUpdate clientCodeNewFromApiUmCompany(BaseRequest<ClientCodeNewRequest> userRequest) {
log.debug("ClientCodeNewRequest received {}", userRequest.getId());
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeNewRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
ClientCodeNewRequest req = userRequest.getRequestPayload();
boolean doCreateTCR = checkNeedCreateTCR(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
if (doCreateTCR) {
try {
createAndWaitTCR(userRequest.getId(), null,
req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
} catch (ClearingBaseException e) {
log.error("Can not wait creation of TCR. request id={};CompanyId={}, MoneyAccountId={}, DepoAccountId={}; {}",
userRequest.getId(), req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId(),
e.toString());
return makeErrorResponse(userRequest, CompanyErrors.GeneralError, "Can not create TCR at this moment");
}
}
ClientCode newClientCode = buildClientCode(req);
clientCodeMap.insert(newClientCode);
log.debug("successfully processed, new clientCode id {}", newClientCode.getId());
return null;
}
protected RequestInfoUpdate clientCodeUpdate(BaseRequest<ClientCodeUpdateRequest> userRequest) {
ClientCodeUpdateRequest req = userRequest.getRequestPayload();
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeUpdateRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
log.debug("ClientCodeUpdateRequest received, id={}", req.getId());
ClientCode clientCode = clientCodeMap.getSingleObjectByID(req.getId());
if (clientCode == null) {
return makeErrorResponse(userRequest, CompanyErrors.RecordNotFound, req.getId());
}
boolean doCreateTCR = checkNeedCreateTCR(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
if (doCreateTCR) {
try {
createAndWaitTCR(userRequest.getId(), clientCode.getId(),
req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
} catch (ClearingBaseException e) {
log.error("Can not wait creation of TCR. request id={};CompanyId={}, MoneyAccountId={}, DepoAccountId={}; {}",
userRequest.getId(), req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId(),
e.toString());
return makeErrorResponse(userRequest, CompanyErrors.GeneralError, "Can not create TCR at this moment");
}
}
updateClientCode(clientCode, req);
clientCodeMap.update(clientCode);
log.debug("successfully processed update, id {}", clientCode.getId());
return null;
}
private RequestInfoUpdate makeErrorResponse(BaseRequest<?> req, CompanyErrors err, Object... arg) {
String errMsg = messageResolver.resolve(new EnumMessage(err, arg));
return new RequestInfoUpdate()
.setId(req.getId())
.setStatus(ru.spcex.clearing.platform.messaging.service.Status.Error)
.setMessage(errMsg);
}
protected RequestInfoUpdate clientCodeDelete(BaseRequest<CommonDeleteRequest> userRequest) {
log.debug("CommonDeleteRequest received id = {}", userRequest.getId());
CommonDeleteRequest req = userRequest.getRequestPayload();
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, clientCodeDeleteRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
ClientCode clientCode = clientCodeMap.getSingleObjectByID(req.getId());
if (clientCode.getMoneyAccountId() != null) {
log.debug("Delete clientCode.id = {}: send message to account-service", clientCode.getId());
sendBlockTCR(clientCode.getTradingClearingRegistryId(), clientCode.getMoneyAccountId());
}
log.debug("Delete clientCode.id={}", clientCode.getId());
clientCodeMap.delete(clientCode);
return null;
}
TradingClearingRegistry selectTradingClearingRegistry(Long companyId, Long moneyAccountId, Long depoAccountId) {
Map<String, Comparable<?>> query = new HashMap<>();
query.put("companyId", companyId);
query.put("moneyAccountId", moneyAccountId);
query.put("tradingClearingRegistryType", TradingClearingRegistryType.Client_B.getKey());
if (depoAccountId != null) {
query.put("depoAaccountId", depoAccountId); // todo опечатка в поле класса, см. meta.xml!
}
TradingClearingRegistry result = tradingClearingRegistryMap.getSingleObjectByFieldValues(query);
log.trace("TradingClearingRegistry by: {}; {}found", query, result == null ? "not " : "");
return result;
}
private boolean checkNeedCreateTCR(Long companyId, Long moneyAccountId, Long depoAccountId) {
// moneyAccountId обязателен, depoAccountId опционален
if (moneyAccountId == null) {
return false;
}
TradingClearingRegistry result = selectTradingClearingRegistry(companyId, moneyAccountId, depoAccountId);
if (result == null) {
return true;
} else {
return false;
}
}
protected void createAndWaitTCR(Long reqId, Long clientCode,
Long companyId, Long moneyAccountId, Long depoAccountId) throws ClearingBaseException {
log.debug("For request {}, clientCode={} need create TCR: companyId={}, moneyAccountId={}, depoAccountId={}",
reqId, clientCode == null ? "new" : clientCode,
companyId, moneyAccountId, depoAccountId);
BaseRequest<TradingClearingRegistryNewRequest> request = new BaseRequest<>();
request.setId(idGenerator.nextId());
request.setActionType(ActionType.NEW);
TradingClearingRegistryNewRequest requestPayload = new TradingClearingRegistryNewRequest();
requestPayload.setCompanyId(companyId);
requestPayload.setMoneyAccountId(moneyAccountId);
requestPayload.setDepoAccountId(depoAccountId);
// requestPayload.setStatus(WorkflowStatus.Active.getKey());
requestPayload.setTradingClearingRegistryType(TradingClearingRegistryType.Client_B.getKey());
request.setRequestPayload(requestPayload);
try {
Long reply = accountServiceExchanger.exchange(request);
if (reply == null) {
throw new ClearingBaseException(CompanyErrors.GeneralError, "Waiting account-service timeout");
}
// примечание: ошибка и сбой (непредвиденное завершение программы) не приведёт к необратимым последствиям,
// т.к. пользователь сможет повторить запрос, а созданный на предыдущем запросе ТКР уже будет создан и найдётся.
} catch (InterruptedException e) {
throw new ClearingBaseException(CompanyErrors.GeneralError, "Waiting account-service timeout");
}
}
protected void sendBlockTCR(Long tradingClearingRegistryId, Long moneyAccountId) {
if (tradingClearingRegistryId == null) {
throw new IllegalArgumentException("tradingClearingRegistryId was null");
}
BaseRequest<TradingClearingRegistryUpdateRequest> request = new BaseRequest<>();
request.setId(idGenerator.nextId());
request.setActionType(ActionType.UPDATE);
TradingClearingRegistryUpdateRequest requestPayload = new TradingClearingRegistryUpdateRequest();
requestPayload.setId(tradingClearingRegistryId);
requestPayload.setStatus(WorkflowStatus.Blocked.getKey());
request.setRequestPayload(requestPayload);
try {
sendMessage(Consts.DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE, request);
} catch (Exception e) {
log.error("Can not send block TCR message, {}", e.toString());
throw e;
}
}
/**
* @param queue Consts.*
* @param message BaseRequest
* @return
*/
private Long sendMessage(String queue, BaseRequest<?> message) {
Long sentRequestId = message.getId();
if (sentRequestId == null) {
throw new IllegalArgumentException("Message " + message.getClass().getSimpleName() + " required id.");
}
log.debug("Send to \"{}\" message {} id={}", queue, message.getActionType(), sentRequestId);
try {
Future<RecordMetadata> send = kafkaProducer.send(new ProducerRecord<>(queue, message));
send.get();
return sentRequestId;
} catch (InterruptedException e) {
log.error("Interrupt when send message, {}", ExceptionUtils.getStackTrace(e));
Thread.currentThread().interrupt();
throw new RuntimeException("Thread interrupted when send message to " + queue, e);
} catch (ExecutionException e) {
log.error("Error at send message, {} cause: {}", e.toString(), ExceptionUtils.getStackTrace(e.getCause()));
throw new RuntimeException("Send message error", e.getCause());
} catch (Exception e) {
log.error("Unexpected exception when send message: {}", ExceptionUtils.getStackTrace(e));
}
return null;
}
/**
* @param req требуется заполнить tradingClearingRegistryId по tradingClearingRegistry.code
* @return
*/
private ClientCode buildClientCode(ClientCodeNewRequest req) {
ClientCode clientCode = new ClientCode();
// clientCode.setId(idSequence.newId()); add in insert
clientCode.setCreated(Instant.now());
clientCode.setUpdated(clientCode.getCreated());
clientCode.setCompanyId(req.getCompanyId());
clientCode.setCode(req.getCode());
if (req.getMoneyAccountId() != null) {
TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
if (tradingClearingRegistry == null) {
log.warn("TCR not found: CompanyId {}, MoneyAccountId {}, DepoAccountId {}",
req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
} else {
clientCode.setTradingClearingRegistryId(tradingClearingRegistry.getId());
}
}
clientCode.setMoneyAccountId(req.getMoneyAccountId());
clientCode.setDepoAccountId(req.getDepoAccountId());
clientCode.setStatus(req.getStatus());
return clientCode;
}
private void updateClientCode(ClientCode clientCode, ClientCodeUpdateRequest req) {
assert clientCode.getId() != null && clientCode.getId().equals(req.getId());
clientCode.setCompanyId(req.getCompanyId());
clientCode.setCode(req.getCode());
if (req.getMoneyAccountId() != null) {
TradingClearingRegistry tradingClearingRegistry = selectTradingClearingRegistry(req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
if (tradingClearingRegistry == null) {
log.warn("TCR not found: CompanyId {}, MoneyAccountId {}, DepoAccountId {}",
req.getCompanyId(), req.getMoneyAccountId(), req.getDepoAccountId());
} else {
clientCode.setTradingClearingRegistryId(tradingClearingRegistry.getId());
}
}
clientCode.setTradingClearingRegistryId(req.getTradingClearingRegistryId());
clientCode.setMoneyAccountId(req.getMoneyAccountId());
clientCode.setDepoAccountId(req.getDepoAccountId());
clientCode.setStatus(req.getStatus());
clientCode.setUpdated(Instant.now());
}
}

View file

@ -11,7 +11,7 @@ import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.profile.CompanyInfo;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.company.util.RequestHelper;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
@ -22,14 +22,18 @@ import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
import ru.spcex.platform.utils.error.ValidationException;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.Objects;
import java.util.function.Function;
@Service
public class CompanyInfoService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ImdgProvider imdgProvider;
private final Imdg<Company> companyMap;
protected final CompanyService companyService;
private final RequestHelper requestHelper;
@ -46,6 +50,7 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea
Function<CompanyInfoUpdateRequest, IValidator> companyInfoUpdateRequestValidator) {
super(kafkaQueue, kafkaProducer);
this.companyService = companyService;
this.imdgProvider = imdgProvider;
this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.validationHelper = validationHelper;
this.userRoleVerification = userRoleVerification;
@ -56,16 +61,16 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea
@Override
public void afterPropertiesSet() {
callback(CompanyInfoUpdateRequest.class)
.setFunction(this::companyInfoUpdate)
.setFunction(request -> requestHelper.requestFunction(this::companyInfoUpdate, request))
.forDestination(Consts.DESTINATION_COMPANY_INFO_UPDATE, callbacks::put);
callback(CompanyInfoUpdateRequest.class)
.setFunction(this::companyInfoUpdate)
.setFunction(request -> requestHelper.requestFunction(this::companyInfoUpdate, request))
.forDestination(Consts.DESTINATION_COMPANY_INFO_NEW, callbacks::put); // логика заполнения одинакова с companyInfoUpdate
init();
}
public RequestInfoUpdate companyInfoUpdate(BaseRequest<CompanyInfoUpdateRequest> companyInfoReq) {
public RequestInfoUpdate companyInfoUpdate(BaseRequest<CompanyInfoUpdateRequest> companyInfoReq) throws ValidationException {
CompanyInfoUpdateRequest req = companyInfoReq.getRequestPayload();
log.debug("{} received", req.getClass().getSimpleName());
{ // Валидация, ValidationException
@ -81,6 +86,7 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea
log.trace("Company {} not found", req.getId());
return requestHelper.makeErrorResponse(companyInfoReq, CompanyErrors.CompanyNotFound, companyInfoReq.getId());
}
company.setUpdated(Instant.now());
CompanyInfo companyInfo = company.getProfile();
companyInfo.setCorporationSoleType(req.getCorporationSoleType());
@ -93,8 +99,39 @@ public class CompanyInfoService extends QueueConsumer implements InitializingBea
companyInfo.setShortNameEng(req.getShortNameEng());
companyInfo.setFullNameEng(req.getFullNameEng());
company.setUpdated(Instant.now());
companyMap.update(company);
company.setShortName(req.getShortName());
company.setFullName(req.getFullName());
boolean simpleUpdate = true;
if (req.getWorkflowStatus() != null) {
String prevStatus = company.getWorkflowStatus();
company.setWorkflowStatus(req.getWorkflowStatus());
if (!Objects.equals(prevStatus, company.getWorkflowStatus())) {
simpleUpdate = false;
ImdgTransaction transaction = imdgProvider.newTransaction();
transaction.beginTransaction();
boolean txOk = false;
try {
companyService.relationService.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus());
Imdg<Company> txCompanyMap = transaction.getImdg(IMDGDistributedNames.Map_Company, Company.class);
txCompanyMap.update(company);
log.trace("Company {} updated", company.getId());
txOk = true;
} finally {
if (txOk)
transaction.commitTransaction();
else
transaction.rollbackTransaction();
}
} else {
log.trace("Status was not changed");
}
} else {
log.trace("Null new WorkflowStatus");
}
if (simpleUpdate) {
companyMap.update(company);
log.trace("Company {} updated", company.getId());
}
log.debug("successfully CompanyInfo processed, id {}", companyInfo.getId());
}
return null;

View file

@ -9,7 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.CompanyRoleSet;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.company.util.RequestHelper;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;

View file

@ -11,7 +11,7 @@ import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.company.util.RequestHelper;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
@ -29,13 +29,11 @@ import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.error.ClearingBaseException;
import ru.spcex.platform.utils.error.ValidationException;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
@ -56,7 +54,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
protected CompanySymbolService companySymbolService;
protected AccountNotificationHelper accountNotification;
protected RelationHelper relationHelper;
protected RelationService relationService;
@Autowired
public CompanyService(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer,
@ -73,7 +71,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
CompanySymbolService companySymbolService,
AccountNotificationHelper accountNotification,
RelationHelper relationHelper
RelationService relationService
) {
super(kafkaQueue, kafkaProducer);
this.imdgProvider = imdgProvider;
@ -89,7 +87,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
this.companySymbolService = companySymbolService;
companySymbolService.setCompanyService(this);
this.accountNotification = accountNotification;
this.relationHelper = relationHelper;
this.relationService = relationService;
companyIMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
}
@ -145,9 +143,9 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
companyMap.insert(company);
log.debug("company-new request processed, BaseRequest.id = {}, company.id={}",
companyNewRequestBaseRequest.getId(), company.getId());
relationHelper.createNewRelation(transaction, company);
relationService.createNewRelation(transaction, company);
if (!(WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()))) { // Block
relationHelper.onChangeWorkflowStatus(transaction, company, null, company.getWorkflowStatus());
relationService.onChangeWorkflowStatus(transaction, company, null, company.getWorkflowStatus());
}
txOk = true;
} finally {
@ -180,10 +178,10 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
log.trace("Company {} not found", updateRequest.getId());
return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyNotFound, updateRequest.getId());
}
if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) {
log.trace("Company {} not active: {}", company.getId(), company.getWorkflowStatus());
return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyDisabled, updateRequest.getId());
}
// if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) {
// log.trace("Company {} not active: {}", company.getId(), company.getWorkflowStatus());
// return requestHelper.makeErrorResponse(companyUpdateRequestBaseRequest, CompanyErrors.CompanyDisabled, updateRequest.getId());
// }
company.setUpdated(Instant.now());
company.setShortName(updateRequest.getShortName());
@ -199,7 +197,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
if (updateRequest.getWorkflowStatus() != null) {
company.setWorkflowStatus(updateRequest.getWorkflowStatus());
if (!Objects.equals(prevStatus, company.getWorkflowStatus())) {
relationHelper.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus());
relationService.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus());
} else {
log.trace("Status was not changed");
}
@ -286,7 +284,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
String prevStatus = company.getWorkflowStatus();
company.setWorkflowStatus(WorkflowStatus.Blocked.getKey());
relationHelper.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus());
relationService.onChangeWorkflowStatus(transaction, company, prevStatus, company.getWorkflowStatus());
log.debug("Update company.id={}", company.getId());
companyMap.update(company);
@ -339,7 +337,7 @@ public class CompanyService extends QueueConsumer implements InitializingBean {
company.setWorkflowStatus(WorkflowStatus.Blocked.getKey());
relationHelper.onChangeWorkflowStatusOnlyRelationChange(transaction, company, company.getWorkflowStatus());
relationService.onChangeWorkflowStatusOnlyRelationChange(transaction, company, company.getWorkflowStatus());
log.debug("Update company.id={}", company.getId());
companyMap.update(company);

View file

@ -10,7 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.spcex.clearing.company.util.RequestHelper;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;

View file

@ -12,7 +12,7 @@ import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.profile.ProfileDocument;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.company.util.RequestHelper;
import ru.spcex.clearing.util.services.RequestHelper;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
@ -21,7 +21,6 @@ import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentNe
import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.DocumentTypes;
@ -174,8 +173,10 @@ public class ProfileDocumentService extends QueueConsumer implements Initializin
ProfileDocument profileDocument = profileDocumentMap.getSingleObjectByID(profileDocumentUpdateRequest.getId());
String prevDocType = profileDocument.getDocumentType();
if (profileDocumentUpdateRequest.getCompanyId() != null)
profileDocument.setCompanyId(profileDocumentUpdateRequest.getCompanyId());
if (profileDocumentUpdateRequest.getCompanyId() != null && !profileDocumentUpdateRequest.getCompanyId().equals(profileDocument.getCompanyId())) {
log.warn("profileDocumentUpdateRequest[{}] CompanyId {} not match", profileDocumentUpdateRequest.getId(), profileDocumentUpdateRequest.getCompanyId());
return requestHelper.makeErrorResponse(profileDocumentUpdateRequestBaseRequest, CompanyErrors.WrongFieldValue, "companyId");
}
if (profileDocumentUpdateRequest.getDocumentType() != null)
profileDocument.setDocumentType(profileDocumentUpdateRequest.getDocumentType());

View file

@ -1,97 +0,0 @@
package ru.spcex.clearing.company.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.company.Company;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.ServiceProduct;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgTransaction;
import ru.spcex.platform.utils.error.ValidationException;
import java.time.Instant;
import java.util.Collection;
import java.util.Objects;
@Service
public class RelationHelper {
protected static final Long SPVB_ID = 1L; // СПВБ
protected final Logger log = LoggerFactory.getLogger(getClass());
protected AccountNotificationHelper accountNotification;
@Autowired
public RelationHelper(AccountNotificationHelper accountNotification) {
this.accountNotification = accountNotification;
}
protected void createNewRelation(ImdgTransaction transaction, Company company) {
Relation relation = new Relation();
// relation.setId(idSequence.nextId());
relation.setCreated(Instant.now());
relation.setUpdated(relation.getCreated());
relation.setConsumerId(company.getId());
relation.setSupplierId(SPVB_ID); // 1 СПВБ
relation.setServiceStatus(WorkflowStatus.Active.getKey());
relation.setService(ru.spcex.platform.enumeration.Service.MKR.getKey()); // MKR
relation.setServiceProduct(ServiceProduct.ZERO.getKey());
log.debug("New Relation[{}] created.", relation.getId());
Imdg<Relation> relationMap = transaction.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
relationMap.insert(relation);
}
/**
* @param company
* @param oldStatus
* @param newStatus WorkflowStatus.Active - при возобналвении; WorkflowStatus.Blocked - при блокировки/расторжении
*/
public void onChangeWorkflowStatus(ImdgTransaction transaction, Company company, String oldStatus, String newStatus) throws ValidationException {
log.debug("Company id={} status changed from {} to {}",
company.getId(), oldStatus, company.getWorkflowStatus());
onChangeWorkflowStatusOnlyRelationChange(transaction, company, newStatus);
if (WorkflowStatus.Blocked.equalsByKey(newStatus)) {
// IV - сообщения на добавления документа расторжения договора
CompanyErrors hasError = accountNotification.accountTerminationNotification(company.getId());
if (hasError != null) {
log.warn("Can not block company, cause error {}", hasError);
throw new ValidationException(hasError);
}
}
}
protected void onChangeWorkflowStatusOnlyRelationChange(ImdgTransaction transaction, Company company, String newStatus) throws ValidationException {
assert Objects.equals(newStatus, company.getWorkflowStatus());
String query = String.format("consumerId=%s", company.getId());
Imdg<Relation> relationMap = transaction.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
Collection<Relation> relations = relationMap.getCollectionObjectsBySQL(query);
log.trace("Selected {} Relation by query: {}", relations.size(), query);
Instant now = Instant.now();
for (Relation relation : relations) {
boolean modified = false;
if (WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) {
if (!ServiceStatus.Reopened.equalsByKey(relation.getServiceStatus())) {
relation.setServiceStatus(ServiceStatus.Reopened.getKey());
modified = true;
}
} else if (WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus())) {
if (!ServiceStatus.Closed.equalsByKey(relation.getServiceStatus())) {
relation.setServiceStatus(ServiceStatus.Closed.getKey());
modified = true;
}
}
if (modified) {
relation.setUpdated(now);
log.debug("Relation id={} updated", relation.getId());
relationMap.update(relation);
}
}
}
}

View file

@ -0,0 +1,331 @@
package ru.spcex.clearing.company.service;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.producer.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.util.services.RequestHelper;
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.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.*;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.enumeration.ServiceProduct;
import ru.spcex.platform.enumeration.ServiceStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.ImdgTransaction;
import ru.spcex.platform.utils.error.ValidationException;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
@Service
public class RelationService extends QueueConsumer implements InitializingBean {
protected static final Long SPVB_ID = 1L; // СПВБ
protected final Logger log = LoggerFactory.getLogger(getClass());
protected ImdgProvider imdgProvider;
protected ImdgId idSequence;
protected Imdg<Relation> relationMap;
protected Imdg<Company> companyMap;
protected AccountNotificationHelper accountNotification;
protected UserRoleVerification userRoleVerification;
protected RequestHelper requestHelper;
protected ValidationHelper validationHelper;
private Function<RelationNewRequest, IValidator> relationNewRequestValidator;
private Function<RelationUpdateRequest, IValidator> relationUpdateRequestValidator;
private Function<CommonDeleteRequest, IValidator> relationDeleteRequestValidator;
@Autowired
public RelationService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider,
RequestHelper requestHelper,
UserRoleVerification userRoleVerification,
ValidationHelper validationHelper,
@Qualifier("relationNewRequestValidation") Function<RelationNewRequest, IValidator> relationNewRequestValidator,
@Qualifier("relationUpdateRequestValidation") Function<RelationUpdateRequest, IValidator> relationUpdateRequestValidator,
@Qualifier("relationDeleteRequestValidation") Function<CommonDeleteRequest, IValidator> relationDeleteRequestValidator,
AccountNotificationHelper accountNotification) {
super(kafkaQueue, kafkaProducer);
this.imdgProvider = imdgProvider;
this.idSequence = imdgProvider.getImdgIdGenerator();
this.accountNotification = accountNotification;
this.userRoleVerification = userRoleVerification;
this.validationHelper = validationHelper;
this.relationNewRequestValidator = relationNewRequestValidator;
this.relationUpdateRequestValidator = relationUpdateRequestValidator;
this.relationDeleteRequestValidator = relationDeleteRequestValidator;
relationMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.requestHelper = requestHelper.setLogger(log);
}
// --- external API ---
@Override
public void afterPropertiesSet() {
// this.profileDocumentMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class);
// this.companyMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
callback(RelationNewRequest.class)
.setFunction(this::relationNew)
.forDestination(Consts.DESTINATION_RELATION_NEW, callbacks::put);
callback(RelationUpdateRequest.class)
.setFunction(this::relationUpdate)
.forDestination(Consts.DESTINATION_RELATION_UPDATE, callbacks::put);
callback(CommonDeleteRequest.class)
.setFunction(this::relationDelete)
.forDestination(Consts.DESTINATION_RELATION_DELETE, callbacks::put);
init();
}
private synchronized RequestInfoUpdate relationNew(BaseRequest<RelationNewRequest> relationNewBaseRequest) {
RelationNewRequest req = relationNewBaseRequest.getRequestPayload();
log.debug("relation-new request received, BaseRequest.id = {}", relationNewBaseRequest.getId());
{ // Валидация
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(relationNewBaseRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(relationNewBaseRequest, relationNewRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
}
Company company = companyMap.getSingleObjectByID(req.getCompanyId());
Relation existRelation = searchRelation(req.getClearingMemberCategory(), req.getCompanyId());
if (existRelation != null && !WorkflowStatus.Blocked.equalsByKey(existRelation.getServiceStatus())) {
CompanyErrors errorType;
if (ru.spcex.platform.enumeration.Service.MKR.equalsByKey(existRelation.getService())) {
errorType = CompanyErrors.ClearingMemberCategoryOnMKRAlreadyExist;
} else if (ru.spcex.platform.enumeration.Service.FOND.equalsByKey(existRelation.getService())) {
errorType = CompanyErrors.ClearingMemberCategoryOnFONDAlreadyExist;
} else {
log.warn("Unknown relation[{}] service={}", existRelation.getId(), existRelation.getService());
errorType = CompanyErrors.GeneralError;
}
return requestHelper.makeErrorResponse(relationNewBaseRequest, errorType);
}
Relation relation;
if (existRelation == null) {
relation = new Relation();
relation.setId(idSequence.nextId());
relation.setCreated(Instant.now());
relation.setUpdated(relation.getCreated());
} else {
log.info("Found exist relation id={}, it will be update.", existRelation.getId());
relation = existRelation;
relation.setUpdated(Instant.now());
}
relation.setConsumerId(req.getCompanyId());
relation.setSupplierId(SPVB_ID); // 1 СПВБ
if (req.getServiceStatus() != null) {
relation.setServiceStatus(req.getServiceStatus());
} else {
if (existRelation != null) {
relation.setServiceStatus(ServiceStatus.Reopened.getKey());
log.debug("Request has no status. Set status by resume: {}", relation.getServiceStatus());
} else {
String toStatus = WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Active.getKey() :
WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Closed.getKey() :
null;
log.debug("Request has no status. Set status by company[{}].status={}. Relation[{}].serviceSStatus={}",
company.getId(), company.getWorkflowStatus(), toStatus);
relation.setServiceStatus(toStatus);
}
}
relation.setService(ru.spcex.platform.enumeration.Service.MKR.getKey()); // MKR
relation.setServiceProduct(ServiceProduct.ZERO.getKey());
relation.setComment(req.getComment());
relationMap.insert(relation);
log.debug("New Relation[{}] created.", relation.getId());
return null;
}
private Relation searchRelation(String clearingMemberCategory, Long consumerId) {
String svc;
if (ClearingCategory.B.equalsByKey(clearingMemberCategory)
|| ClearingCategory.I.equalsByKey(clearingMemberCategory)
|| ClearingCategory.V.equalsByKey(clearingMemberCategory)
) {
svc = ru.spcex.platform.enumeration.Service.MKR.getKey();
} else if (ClearingCategory.C.equalsByKey(clearingMemberCategory)
|| ClearingCategory.F.equalsByKey(clearingMemberCategory)
) {
svc = ru.spcex.platform.enumeration.Service.FOND.getKey();
} else {
log.warn("Unexpected relation Relation={}", clearingMemberCategory);
return null;
}
Relation existRelation = relationMap.getSingleObjectByFieldValues(Map.of(
"consumerId", consumerId,
"service", svc
));
return existRelation;
}
private synchronized RequestInfoUpdate relationUpdate(BaseRequest<RelationUpdateRequest> relationUpdateBaseRequest) {
RelationUpdateRequest req = relationUpdateBaseRequest.getRequestPayload();
log.debug("relation-update request received, BaseRequest.id = {}", relationUpdateBaseRequest.getId());
{ // Валидация
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(relationUpdateBaseRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(relationUpdateBaseRequest, relationUpdateRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
}
Relation relation = relationMap.getSingleObjectByID(req.getId());
relation.setUpdated(relation.getCreated());
if (req.getServiceStatus() != null) {
log.debug("To relation {} set serivceStatus=\"{}\" by user request.", relation.getId(), req.getServiceStatus());
relation.setServiceStatus(req.getServiceStatus());
} else {
if (relation.getConsumerId() == null) {
log.warn("Relation[{}]. consumerId was null", relation.getId());
}
Company company = companyMap.getSingleObjectByID(relation.getConsumerId());
String toStatus = WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Active.getKey() :
WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus()) ? ServiceStatus.Closed.getKey() :
null;
if (ServiceStatus.Active.equalsByKey(toStatus) && ServiceStatus.Closed.equalsByKey(relation.getServiceStatus())) {
relation.setServiceStatus(ServiceStatus.Reopened.getKey());
log.debug("Set status by resume: {}", relation.getServiceStatus());
} else {
relation.setServiceStatus(toStatus);
log.debug("Request has no status. Set status by company[{}].status={}. Relation[{}].serviceSStatus={}",
company.getId(), company.getWorkflowStatus(), toStatus, relation.getServiceStatus());
}
}
relation.setComment(req.getComment());
relationMap.insert(relation);
log.debug("Update Relation[{}] created.", relation.getId());
return null;
}
private synchronized RequestInfoUpdate relationDelete(BaseRequest<CommonDeleteRequest> relationDeleteBaseRequest) {
CommonDeleteRequest req = relationDeleteBaseRequest.getRequestPayload();
log.debug("relation-delete request received, BaseRequest.id = {}", relationDeleteBaseRequest.getId());
{ // Валидация
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(relationDeleteBaseRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(relationDeleteBaseRequest, relationDeleteRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
}
Relation relation = relationMap.getSingleObjectByID(req.getId());
if (WorkflowStatus.Blocked.equalsByKey(relation.getServiceStatus())) {
log.warn("Relation {} already blocked.", relation.getId());
} else {
relation.setUpdated(relation.getCreated());
relation.setServiceStatus(WorkflowStatus.Blocked.getKey());
relationMap.insert(relation);
log.debug("Relation[{}] block.", relation.getId());
}
return null;
}
// --- internal API ---
protected void createNewRelation(ImdgTransaction transaction, Company company) {
Relation relation = new Relation();
// relation.setId(idSequence.nextId());
relation.setCreated(Instant.now());
relation.setUpdated(relation.getCreated());
relation.setConsumerId(company.getId());
relation.setSupplierId(SPVB_ID); // 1 СПВБ
relation.setServiceStatus(WorkflowStatus.Active.getKey());
relation.setService(ru.spcex.platform.enumeration.Service.MKR.getKey()); // MKR
relation.setServiceProduct(ServiceProduct.ZERO.getKey());
log.debug("New Relation[{}] created.", relation.getId());
Imdg<Relation> relationMap = transaction.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
relationMap.insert(relation);
}
/**
* @param company
* @param oldStatus
* @param newStatus WorkflowStatus.Active - при возобналвении; WorkflowStatus.Blocked - при блокировки/расторжении
*/
public void onChangeWorkflowStatus(ImdgTransaction transaction, Company company, String oldStatus, String newStatus) throws ValidationException {
log.debug("Company id={} status changed from {} to {}",
company.getId(), oldStatus, company.getWorkflowStatus());
onChangeWorkflowStatusOnlyRelationChange(transaction, company, newStatus);
if (WorkflowStatus.Blocked.equalsByKey(newStatus)) {
// IV - сообщения на добавления документа расторжения договора
CompanyErrors hasError = accountNotification.accountTerminationNotification(company.getId());
if (hasError != null) {
log.warn("Can not block company, cause error {}", hasError);
throw new ValidationException(hasError);
}
}
}
protected synchronized void onChangeWorkflowStatusOnlyRelationChange(ImdgTransaction transaction, Company company, String newStatus) throws ValidationException {
assert Objects.equals(newStatus, company.getWorkflowStatus());
String query = String.format("consumerId=%s", company.getId());
Imdg<Relation> relationMap = transaction.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
Collection<Relation> relations = relationMap.getCollectionObjectsBySQL(query);
log.trace("Selected {} Relation by query: {}", relations.size(), query);
Instant now = Instant.now();
for (Relation relation : relations) {
boolean modified = false;
if (WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) {
if (!ServiceStatus.Reopened.equalsByKey(relation.getServiceStatus())) {
relation.setServiceStatus(ServiceStatus.Reopened.getKey());
modified = true;
}
} else if (WorkflowStatus.Blocked.equalsByKey(company.getWorkflowStatus())) {
if (!ServiceStatus.Closed.equalsByKey(relation.getServiceStatus())) {
relation.setServiceStatus(ServiceStatus.Closed.getKey());
modified = true;
}
}
if (modified) {
relation.setUpdated(now);
log.debug("Relation id={} updated", relation.getId());
relationMap.update(relation);
}
}
}
}

View file

@ -0,0 +1,367 @@
package ru.spcex.clearing.company.service;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.producer.MockProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.ClientCode;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.profile.CompanyInfo;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.platform.dictionary.*;
import ru.spcex.clearing.company.config.BeanConfiguration;
import ru.spcex.clearing.company.config.validation.ClientCodeValidationConfig;
import ru.spcex.clearing.company.config.validation.ValidationConfig;
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.account.ClientCodeNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.test.MatcherFactory;
import ru.spcex.clearing.test.TestUtils;
import ru.spcex.clearing.test.config.ImdgTestConfig;
import ru.spcex.clearing.test.config.KafkaTestConfig;
import ru.spcex.platform.enumeration.TradingClearingRegistryType;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import javax.annotation.PostConstruct;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparator;
import static ru.spcex.clearing.test.TestUtils.*;
import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
ClientCodeService.class,
ClientCodeValidationConfig.class,
ValidationConfig.class,
BeanConfiguration.class,
KafkaTestConfig.class,
ImdgTestConfig.class})
class ClientCodeServiceTest {
private static final int PARTITION = 0;
private static final Long ID = 4L;
public static final MatcherFactory.Matcher<ClientCode> CLIENT_CODE_MATCHER = usingIgnoringFieldsComparator("created","updated");
private static final Long TCR_ID = 41L;
private static final Long COMPANY_ID = 42L;
@Autowired
ClientCodeService clientCodeService;
@Autowired
@Qualifier("hazelcastServiceTest")
private ImdgProvider hazelcastServiceTest;
@Captor
private ArgumentCaptor<ProducerRecord> producerRecord;
@SpyBean
private MockProducer<String, Object> mockProducer;
private Imdg<ClientCode> clientCodeImdg;
// ****************************-*******************
@PostConstruct
private void init() {
waitAvailableImdgProviderAndAddAdminWithDefaultId();
clientCodeImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class);
// Словари для теста, применяются в ValidationConfig
putToDictionary(IMDGDistributedNames.Map_WorkflowStatusDictionary, new WorkflowStatusDictionary(), "ACTV");
putToDictionary(IMDGDistributedNames.Map_CompanySymbolDictionary, new CompanySymbolDictionary(), "CLRC");
putToDictionary(IMDGDistributedNames.Map_CorporationSoleTypeDictionary, new CorporationSoleTypeDictionary(), "GDIR");
putToDictionary(IMDGDistributedNames.Map_CountryCodeDictionary, new CountryCodeDictionary(), "RUS");
putToDictionary(IMDGDistributedNames.Map_AllowedDictionary, new AllowedDictionary(), "ALWD");
putToDictionary(IMDGDistributedNames.Map_LegalKindDictionary, new LegalKindDictionary(), "JURD");
putToDictionary(IMDGDistributedNames.Map_OrganizationTypeDictionary, new OrganizationTypeDictionary(), "NCRD");
Imdg<Company> companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class);
Company company1 = new Company();
company1.setId(COMPANY_ID);
company1.setWorkflowStatus(WorkflowStatus.Active.getKey());
company1.setFullName("Company prime");
company1.setShortName("Seizwell");
company1.setProfile(new CompanyInfo());
company1.getProfile().setCompanyId(COMPANY_ID);
company1.getProfile().setCountryCode("TLDI");
company1.getProfile().setDescription("Big profit from TLD Company Prime.");
company1.getProfile().setLegalKind("TLDI");
company1.getProfile().setResidence("TLDI");
companyImdg.insert(company1);
Imdg<TradingClearingRegistry> tcrImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
TradingClearingRegistry registry1 = new TradingClearingRegistry();
registry1.setId(TCR_ID);
registry1.setCompanyId(COMPANY_ID);
registry1.setCode("code-120-101");
registry1.setMoneyAccountId(131L);
registry1.setDepoAaccountId(132L);
registry1.setTradingClearingRegistryType(TradingClearingRegistryType.Client_B.getKey());
registry1.setStatus(WorkflowStatus.Active.getKey());
tcrImdg.insert(registry1);
Imdg<Account> accounts = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Account, Account.class);
Account moneyAccount=new Account();
moneyAccount.setId(131L);
moneyAccount.setAccount("AAAA-4444");
moneyAccount.setStatus("ACTV");
moneyAccount.setCompanyId(COMPANY_ID); // для валидации принадлежности счёта
accounts.insert(moneyAccount);
Account depoAccount=new Account();
depoAccount.setId(132L);
depoAccount.setAccount("AAAB-44654");
depoAccount.setStatus("ACTV");
depoAccount.setCompanyId(COMPANY_ID); // для валидации принадлежности счёта
accounts.insert(depoAccount);
TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class);
doReturn(future).when(mockProducer).send(producerRecord.capture());
}
private <D extends AbstractDictionary> void putToDictionary(String mapName, D object, String code) {
Imdg<D> dMap = (Imdg) hazelcastServiceTest.getImdg(mapName, object.getClass());
object.setId(2L);
object.setCode(code);
object.setName("name of " + code);
dMap.insert(object);
}
@Test
void selectTradingClearingRegistry() {
TradingClearingRegistry tcr = clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 131L, 132L);
assertNotNull(tcr);
assertEquals(41L, tcr.getId());
tcr = clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 131L, null);
assertNotNull(tcr);
assertEquals(41L, tcr.getId());
assertNull(clientCodeService.selectTradingClearingRegistry(0L, 131L, 132L));
assertNull(clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 0L, 132L));
assertNull(clientCodeService.selectTradingClearingRegistry(COMPANY_ID, 131L, 0L));
}
/**
* {@link ClientCodeService#clientCodeUpdate(BaseRequest)}<br>
* Тест проверяет создание {@link ClientCode} в IMDG при передаче из Apache Kafka (очередь 1).<br>
* Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest}:<br>
**/
@Test
void clientCodeNew1() {
//ARRANGE
final String ccCode = "Lucky planet";
ClientCodeNewRequest clientCodeNewRequest = new ClientCodeNewRequest();
clientCodeNewRequest.setCompanyId(COMPANY_ID);
clientCodeNewRequest.setCode(ccCode);
clientCodeNewRequest.setTradingClearingRegistryId(TCR_ID);
clientCodeNewRequest.setDepoAccountId(null);
clientCodeNewRequest.setMoneyAccountId(null);
clientCodeNewRequest.setStatus("ACTV");
ClientCode predictableClientCode = new ClientCode();
predictableClientCode.setCode(ccCode);
predictableClientCode.setStatus("ACTV");
predictableClientCode.setCompanyId(COMPANY_ID);
// predictableClientCode.setMoneyAccountId(131L);
// predictableClientCode.setDepoAccountId(132L);
// predictableClientCode.setTradingClearingRegistryId(TCR_ID);
//ACT
String jsonString = getJsonStringForNew(clientCodeNewRequest, ID);
addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_NEW, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = '%s'", ccCode));
predictableClientCode.setId(resultNew.getId());
CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode);
assertNotNull(resultNew.getCreated());
}
/**
* {@link ClientCodeService#clientCodeUpdate(BaseRequest)}<br>
* Тест проверяет создание {@link ClientCode} в IMDG при передаче из Apache Kafka (очередь 2).<br>
* Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeNewRequest}:<br>
**/
@Test
void clientCodeNew2() {
//ARRANGE
final String ccCode = "Lucky planet";
ClientCodeNewRequest clientCodeNewRequest = new ClientCodeNewRequest();
clientCodeNewRequest.setCompanyId(COMPANY_ID);
clientCodeNewRequest.setCode(ccCode);
clientCodeNewRequest.setTradingClearingRegistryId(TCR_ID);
clientCodeNewRequest.setDepoAccountId(null);
clientCodeNewRequest.setMoneyAccountId(null);
clientCodeNewRequest.setStatus("ACTV");
ClientCode predictableClientCode = new ClientCode();
predictableClientCode.setCode(ccCode);
predictableClientCode.setStatus("ACTV");
predictableClientCode.setCompanyId(COMPANY_ID);
// predictableClientCode.setMoneyAccountId(131L);
// predictableClientCode.setDepoAccountId(132L);
// predictableClientCode.setTradingClearingRegistryId(TCR_ID);
//ACT
String jsonString = getJsonStringForNew(clientCodeNewRequest, ID);
addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_NEW_UM_COMPANY, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
ClientCode resultNew = clientCodeImdg.getSingleObjectBySQL(String.format("code = '%s'", ccCode));
predictableClientCode.setId(resultNew.getId());
CLIENT_CODE_MATCHER.assertMatch(resultNew, predictableClientCode);
assertNotNull(resultNew.getCreated());
}
//todo добавить тест NEW заполненными MoneyAccountId(131L), DepoAccountId(132L); - от этого направляется дополнительное сообщение в очередь и используется ожидание ответа.
/**
* {@link ClientCodeService#clientCodeUpdate(BaseRequest)}<br>
* Тест проверяет обновление сущности {@link ClientCode} в IMDG при передаче из Apache Kafka.<br>
* Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.account.ClientCodeUpdateRequest}:<br>
**/
@Test
void clientCodeUpdate() {
//ARRANGE
ClientCode existsClientCode = new ClientCode();
existsClientCode.setId(ID);
existsClientCode.setCompanyId(COMPANY_ID);
existsClientCode.setCode("0000");
existsClientCode.setTradingClearingRegistryId(TCR_ID);
existsClientCode.setMoneyAccountId(131L);
existsClientCode.setDepoAccountId(132L);
existsClientCode.setStatus("ACTV");
clientCodeImdg.insert(existsClientCode);
ClientCodeUpdateRequest clientCodeUpdateRequest = new ClientCodeUpdateRequest();
clientCodeUpdateRequest.setId(ID);
clientCodeUpdateRequest.setCompanyId(COMPANY_ID);
clientCodeUpdateRequest.setCode("1111");
clientCodeUpdateRequest.setTradingClearingRegistryId(TCR_ID);
clientCodeUpdateRequest.setMoneyAccountId(131L);
clientCodeUpdateRequest.setDepoAccountId(132L);
clientCodeUpdateRequest.setStatus("ACTV");
ClientCode predictableClientCode = new ClientCode();
predictableClientCode.setId(ID);
predictableClientCode.setCompanyId(COMPANY_ID);
predictableClientCode.setCode("1111");
predictableClientCode.setTradingClearingRegistryId(TCR_ID);
predictableClientCode.setMoneyAccountId(131L);
predictableClientCode.setDepoAccountId(132L);
predictableClientCode.setStatus("ACTV");
//ACT
String jsonString = getJsonStringForUpdate(clientCodeUpdateRequest, ID);
addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_UPDATE, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
ClientCode resultUpdating = clientCodeImdg.getSingleObjectByID(ID);
CLIENT_CODE_MATCHER.assertMatch(resultUpdating, predictableClientCode);
assertNotNull(resultUpdating.getUpdated());
}
/**
* {@link ClientCodeService#clientCodeUpdate(BaseRequest)}<br>
* Тест проверяет удаление {@link ClientCode} из IMDG при передаче из Apache Kafka.<br>
* Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest}:<br>
**/
@Test
void clientCodeDelete1() {
//ARRANGE
ClientCode existsClientCode = new ClientCode();
existsClientCode.setId(ID);
existsClientCode.setCompanyId(COMPANY_ID);
existsClientCode.setCode("0000");
// Если следующие поля заполнить, то дополнительно отправит сообщение в trading-clearing-registry-update:
existsClientCode.setTradingClearingRegistryId(null);
existsClientCode.setMoneyAccountId(null);
existsClientCode.setDepoAccountId(null);
existsClientCode.setStatus("ACTV");
clientCodeImdg.insert(existsClientCode);
CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest();
clientCodeDeleteRequest.setId(ID);
Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data
//ACT
String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID);
addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID);
Assertions.assertNull(resultUpdate);
}
// /**
// * {@link ClientCodeService#clientCodeUpdate(BaseRequest)}<br>
// * Тест проверяет удаление {@link ClientCode} из IMDG при передаче из Apache Kafka.<br>
// * У ClientCode заполнены MoneyAccountId, DepoAccountId - по этому при удалении должно направиться дополнительное сообщение в очередь DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE<br>
// * Входной запрос {@link ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest}:<br>
// **/
// @Test
// void clientCodeDelete2() {
// //ARRANGE
// ClientCode existsClientCode = new ClientCode();
// existsClientCode.setId(ID);
// existsClientCode.setCompanyId(COMPANY_ID);
// existsClientCode.setCode("0000");
// // Если следующие поля заполнить, то дополнительно отправит сообщение в trading-clearing-registry-update:
// existsClientCode.setTradingClearingRegistryId(TCR_ID);
// existsClientCode.setMoneyAccountId(131L);
// existsClientCode.setDepoAccountId(132L);
// existsClientCode.setStatus("ACTV");
//
// clientCodeImdg.insert(existsClientCode);
//
// CommonDeleteRequest clientCodeDeleteRequest = new CommonDeleteRequest();
// clientCodeDeleteRequest.setId(ID);
//
// Assertions.assertNotNull(clientCodeImdg.getSingleObjectByID(ID)); // verify test data
//
// //ACT
// String jsonString = getJsonStringForUpdate(clientCodeDeleteRequest, ID);
//
// addRecordToKafka((MockConsumer) clientCodeService.getConsumer(), Consts.DESTINATION_CLIENT_CODE_DELETE, PARTITION, 0, jsonString);
//
// //ASSERT
//
// waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
// ClientCode resultUpdate = clientCodeImdg.getSingleObjectByID(ID);
// Assertions.assertNull(resultUpdate);
// }
}

View file

@ -18,6 +18,7 @@ import ru.clearing.platform.dictionary.*;
import ru.spcex.clearing.company.config.BeanConfiguration;
import ru.spcex.clearing.company.config.validation.CompanySymbolValidationConfig;
import ru.spcex.clearing.company.config.validation.CompanyValidationConfig;
import ru.spcex.clearing.company.config.validation.RelationValidationConfig;
import ru.spcex.clearing.company.config.validation.ValidationConfig;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
@ -50,7 +51,8 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv
ValidationConfig.class,
CompanySymbolService.class,
AccountNotificationHelper.class,
RelationHelper.class,
RelationService.class,
RelationValidationConfig.class,
BeanConfiguration.class,
KafkaTestConfig.class,

View file

@ -21,6 +21,7 @@ import ru.clearing.platform.dictionary.WorkflowStatusDictionary;
import ru.spcex.clearing.company.config.BeanConfiguration;
import ru.spcex.clearing.company.config.validation.CompanySymbolValidationConfig;
import ru.spcex.clearing.company.config.validation.CompanyValidationConfig;
import ru.spcex.clearing.company.config.validation.RelationValidationConfig;
import ru.spcex.clearing.company.config.validation.ValidationConfig;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
@ -54,7 +55,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv
ValidationConfig.class,
CompanySymbolService.class,
AccountNotificationHelper.class,
RelationHelper.class,
RelationService.class, RelationValidationConfig.class,
CompanySymbolService.class,
CompanySymbolValidationConfig.class,

View file

@ -12,11 +12,13 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.platform.dictionary.CompanySymbolDictionary;
import ru.spcex.clearing.company.config.BeanConfiguration;
import ru.spcex.clearing.company.config.validation.CompanySymbolValidationConfig;
import ru.spcex.clearing.company.config.validation.CompanyValidationConfig;
import ru.spcex.clearing.company.config.validation.RelationValidationConfig;
import ru.spcex.clearing.company.config.validation.ValidationConfig;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
@ -49,7 +51,7 @@ import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProv
CompanyService.class,
CompanyValidationConfig.class,
AccountNotificationHelper.class,
RelationHelper.class,
RelationService.class, RelationValidationConfig.class,
KafkaTestConfig.class,
ImdgTestConfig.class})
@ -92,6 +94,14 @@ class CompanySymbolServiceTest {
cioSymbol.setName(CompanySymbol.CIO.getKey());
companySymbolDictionaryImdg.insert(cioSymbol);
}
Imdg<Company> companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class);
{
Company company = new Company();
company.setId(ID);
company.setShortName("TST");
company.setWorkflowStatus("ACTV");
companyImdg.insert(company);
}
TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class);

View file

@ -0,0 +1,214 @@
package ru.spcex.clearing.company.service;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.producer.MockProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.clearing.platform.dictionary.ClearingCategoryDictionary;
import ru.clearing.platform.dictionary.WorkflowStatusDictionary;
import ru.spcex.clearing.company.config.BeanConfiguration;
import ru.spcex.clearing.company.config.validation.RelationValidationConfig;
import ru.spcex.clearing.company.config.validation.ValidationConfig;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.RelationNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.RelationUpdateRequest;
import ru.spcex.clearing.test.MatcherFactory;
import ru.spcex.clearing.test.TestUtils;
import ru.spcex.clearing.test.config.ImdgTestConfig;
import ru.spcex.clearing.test.config.KafkaTestConfig;
import ru.spcex.platform.enumeration.ClearingCategory;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import javax.annotation.PostConstruct;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparator;
import static ru.spcex.clearing.test.TestUtils.*;
import static ru.spcex.clearing.test.config.ImdgTestConfig.currentID;
import static ru.spcex.clearing.test.config.ImdgTestConfig.waitAvailableImdgProviderAndAddAdminWithDefaultId;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
BeanConfiguration.class,
ValidationConfig.class,
RelationService.class,
AccountNotificationHelper.class,
RelationValidationConfig.class,
KafkaTestConfig.class,
ImdgTestConfig.class})
class RelationServiceTest {
public static final MatcherFactory.Matcher<Relation> RELATION_MATCHER = usingIgnoringFieldsComparator("created", "updated");
private static final int PARTITION = 0;
private static final Long ID = currentID.getAndIncrement();
@Autowired
RelationService relationService;
@Autowired
@Qualifier("hazelcastServiceTest")
private ImdgProvider hazelcastServiceTest;
private Imdg<Relation> relationMap;
private Imdg<Company> companyMap;
@Captor
private ArgumentCaptor<ProducerRecord> producerRecord;
@SpyBean
private MockProducer<String, Object> mockProducer;
private long COMPANY_ID;
private final long RELATION_ID = ID;
@PostConstruct
private void init() {
waitAvailableImdgProviderAndAddAdminWithDefaultId();
this.relationMap = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
this.companyMap = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class);
Company testCompany = new Company();
testCompany.setWorkflowStatus(WorkflowStatus.Active.getKey());
COMPANY_ID = companyMap.insert(testCompany);
Imdg<WorkflowStatusDictionary> workflowStatusDictionaryImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_WorkflowStatusDictionary,
WorkflowStatusDictionary.class
);
WorkflowStatusDictionary workflowStatusDictionary = new WorkflowStatusDictionary();
workflowStatusDictionary.setId(1L);
workflowStatusDictionary.setCode(WorkflowStatus.Active.getKey());
workflowStatusDictionary.setName("active");
workflowStatusDictionaryImdg.insert(workflowStatusDictionary);
workflowStatusDictionary = new WorkflowStatusDictionary();
workflowStatusDictionary.setId(2L);
workflowStatusDictionary.setCode(WorkflowStatus.Blocked.getKey());
workflowStatusDictionary.setName("not active");
workflowStatusDictionaryImdg.insert(workflowStatusDictionary);
Imdg<ClearingCategoryDictionary> clearingCategoryDictionaryImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_ClearingCategoryDictionary,
ClearingCategoryDictionary.class
);
ClearingCategoryDictionary clearingCategoryDictionary = new ClearingCategoryDictionary();
clearingCategoryDictionary.setId(1L);
clearingCategoryDictionary.setCode(ClearingCategory.I.getKey());
clearingCategoryDictionary.setName("I");
clearingCategoryDictionaryImdg.insert(clearingCategoryDictionary);
TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class);
doReturn(future).when(mockProducer).send(producerRecord.capture());
}
@Test
void newRelation() {
//ARRANGE
RelationNewRequest relationNewRequest = new RelationNewRequest();
relationNewRequest.setCompanyId(COMPANY_ID);
relationNewRequest.setServiceStatus("ACTV");
relationNewRequest.setClearingMemberCategory("I");
relationNewRequest.setComment(null);
Relation predictableRelation = new Relation();
predictableRelation.setId(RELATION_ID);
predictableRelation.setConsumerId(relationNewRequest.companyId);
predictableRelation.setService("MKR");
predictableRelation.setServiceProduct("ZERO");
predictableRelation.setSupplierId(1L);
predictableRelation.setServiceStatus("ACTV");
//ACT
String jsonString = getJsonStringForNew(relationNewRequest, ID);
addRecordToKafka((MockConsumer) relationService.getConsumer(), Consts.DESTINATION_RELATION_NEW, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
Relation resultNew = relationMap.getSingleObjectBySQL("serviceStatus=ACTV"); // String.format("supplierId = %d", COMPANY_ID));
predictableRelation.setId(resultNew.getId());
RELATION_MATCHER.assertMatch(resultNew, predictableRelation);
}
@Test
void updateRelation() {
//ARRANGE
Relation existsRelation = new Relation();
existsRelation.setId(ID);
existsRelation.setConsumerId(COMPANY_ID);
existsRelation.setSupplierId(1L);
existsRelation.setComment("Test ONE");
existsRelation.setServiceStatus("ACTV");
existsRelation.setServiceProduct("PROD");
existsRelation.setService("MKR");
relationMap.insert(existsRelation);
Relation predictableRelation = new Relation();
predictableRelation.setId(ID);
predictableRelation.setConsumerId(COMPANY_ID);
predictableRelation.setSupplierId(1L);
predictableRelation.setComment("Another Me - ONE");
predictableRelation.setServiceStatus("ACTV");
predictableRelation.setServiceProduct("PROD");
predictableRelation.setService("MKR");
RelationUpdateRequest relationUpdateRequest = new RelationUpdateRequest();
relationUpdateRequest.setId(RELATION_ID);
relationUpdateRequest.setComment("Another Me - ONE");
relationUpdateRequest.setServiceStatus("ACTV");
//ACT
String jsonString = getJsonStringForUpdate(relationUpdateRequest, ID);
addRecordToKafka((MockConsumer) relationService.getConsumer(), Consts.DESTINATION_RELATION_UPDATE, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
Relation resultUpdate = relationMap.getSingleObjectBySQL(String.format("id = %d", RELATION_ID));
// predictableProfileDocument.setId(resultUpdate.getId());
RELATION_MATCHER.assertMatch(resultUpdate, predictableRelation);
}
@Test
void deleteProfileDocument() {
//ARRANGE
Relation existsRelation = new Relation();
existsRelation.setId(ID);
existsRelation.setConsumerId(COMPANY_ID);
existsRelation.setSupplierId(1L);
existsRelation.setComment("Test ONE");
existsRelation.setServiceStatus("ACTV");
existsRelation.setServiceProduct("PROD");
existsRelation.setService("MKR");
relationMap.insert(existsRelation);
CommonDeleteRequest profileDocumentDeleteRequest = new CommonDeleteRequest();
profileDocumentDeleteRequest.setId(RELATION_ID);
//ACT
String jsonString = getJsonStringForUpdate(profileDocumentDeleteRequest, ID);
addRecordToKafka((MockConsumer) relationService.getConsumer(), Consts.DESTINATION_RELATION_DELETE, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
Relation resultUpdate = relationMap.getSingleObjectByID(RELATION_ID);
// Assertions.assertNull(resultUpdate);
assertEquals(WorkflowStatus.Blocked.getKey(), resultUpdate.getServiceStatus());
}
}

View file

@ -1,4 +1,4 @@
-- DB version: 3.5.0.20
-- DB version: 3.5.0.21
-- DATA version: 3.5.0.4
/* Dictionaries */
@ -160,7 +160,7 @@ INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (17, 'RG
INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (18, 'UUID', 'Идентификатор во внешней системе', 'Внешний идентификатор') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME;
INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (19, 'RDPZ', 'Требуется получение документа о подтверждении открытия депозитного счета', 'Подтверждение депозитного счета') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME;
INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (19, 'LICM', 'Лицензия на управление инвестиционными фондами, паевыми инвестиционными фондами, негосударственными пенсионными фондами', 'Лицензия на управление фондами') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME;
INSERT INTO COMPANY_ROLE_DICTIONARY(ID, CODE, NAME) values (1, 'RPRT', 'Отчетная организация') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
@ -394,7 +394,7 @@ INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (12, 'CMBA', 'Формиро
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (14, 'GCMR', 'Формирование реестра участников клиринга') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (15, 'GBRR', 'Формирование реестра остатков денежных средств ') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (15, 'GBRR', 'Формирование реестра остатков денежных средств') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (16, 'GORR', 'Формирование реестра распоряжений, направленных расчетной организации') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
@ -414,9 +414,9 @@ INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (36, 'SPRC', 'Запуск п
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (37, 'SPOC', 'Запуск постклиринга') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (38, 'LIMM', 'Выгрузка в торговую систему остатков секции МКР') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (38, 'LIMM', 'Выгрузка в торговую систему остатков по деньгам') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (39, 'LIMF', 'Выгрузка в торговую систему остатков Фондовой секции') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (39, 'LIMS', 'Выгрузка в торговую систему остатков по бумагам') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;
INSERT INTO TASK_DICTIONARY(ID, CODE, NAME) values (40, 'LIQU', 'Ликвидационная сессия по обязательтсвам участника') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME;

View file

@ -10,7 +10,7 @@ import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
@Configuration
public class SchedulerServiceImdgConfig {
public class ImdgConfig {
private static ThreadPoolTaskExecutor createThreadPoolTaskExecutor(int maxPoolSz, boolean waitForCompletion) {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
if (maxPoolSz > 2) {

View file

@ -0,0 +1,17 @@
package ru.spcex.clearing.scheduler.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@Configuration
public class SchedulerServiceConfig {
@Bean(name = "taskScheduler")
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setThreadNamePrefix("ThreadPoolTaskScheduler");
return threadPoolTaskScheduler;
}
}

View file

@ -43,6 +43,7 @@ public class ClearingCalendarValidationConfig {
IMDGDistributedNames.Map_Company,
Company.class,
ValidationError.CompanyNotFound,
false,
company -> WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive),
DictionaryPresentRule.instance("dayStatus",
ClearingCalendarNewRequest::getDayStatus,
@ -74,6 +75,7 @@ public class ClearingCalendarValidationConfig {
IMDGDistributedNames.Map_Company,
Company.class,
ValidationError.CompanyNotFound,
false,
company -> WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive),
DictionaryPresentRule.instance("dayStatus",
ClearingCalendarUpdateRequest::getDayStatus,

View file

@ -45,7 +45,9 @@ public class PlannerTemplateValidationConfig {
IMDGDistributedNames.Map_TaskDictionary,
TaskDictionary.class),
TimeNotBeforeRule.instance("taskTime",
PlannerTemplateNewRequest::getTaskTime),
PlannerTemplateNewRequest::getTaskTime,
true,
false),
DictionaryPresentRule.instance("taskStatus",
PlannerTemplateNewRequest::getTaskStatus,
IMDGDistributedNames.Map_TaskStatusDictionary,
@ -55,12 +57,14 @@ public class PlannerTemplateValidationConfig {
IMDGDistributedNames.Map_Company,
Company.class,
ValidationError.CompanyNotFound,
false,
company -> WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive),
IdPresentRule.instance("securityId",
PlannerTemplateNewRequest::getSecurityId,
IMDGDistributedNames.Map_Security,
Security.class,
ValidationError.SecurityNotFound,
false,
security -> WorkflowStatus.Active.equalsByKey(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive)
);
};
@ -90,6 +94,7 @@ public class PlannerTemplateValidationConfig {
false),
TimeNotBeforeRule.instance("taskTime",
PlannerTemplateUpdateRequest::getTaskTime,
false,
false),
DictionaryPresentRule.instance("taskStatus",
PlannerTemplateUpdateRequest::getTaskStatus,

View file

@ -62,12 +62,14 @@ public class PlannerValidationConfig {
IMDGDistributedNames.Map_Company,
Company.class,
ValidationError.CompanyNotFound,
false,
company -> WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive),
IdPresentRule.instance("securityId",
PlannerNewRequest::getSecurityId,
IMDGDistributedNames.Map_Security,
Security.class,
ValidationError.SecurityNotFound,
false,
security -> WorkflowStatus.Active.equalsByKey(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive)
);
};

View file

@ -48,7 +48,7 @@ public class TaskManager implements InitializingBean, AutoCloseable {
private final ExecutorService outputExecutor;
@Autowired
TaskManager(TaskScheduler taskScheduler,
TaskManager(@Qualifier("taskScheduler") TaskScheduler taskScheduler,
ImdgProvider imdgProvider,
LauncherSender launcherSender,
@Qualifier("plannerQueue") BlockingQueue<Map.Entry<Process, PlannerAllToday>> plannerQueue) {

View file

@ -55,6 +55,6 @@ public record EnumPresentRule<R, E extends IEnumKey>(String fieldName,
for (E enumValue : enumValues) {
if (enumValue.getKey().equals(enumCode)) return empty();
}
return of(ValidationError.WrongEnumValue, fieldName);
return of(ValidationError.WrongDictionaryValue, fieldName);
}
}

View file

@ -19,7 +19,7 @@ import ru.clearing.platform.dictionary.TaskStatusDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.scheduler.config.ErrorResolverConfig;
import ru.spcex.clearing.scheduler.config.PlannerQueueConfig;
import ru.spcex.clearing.scheduler.config.SchedulerTestConfig;
import ru.spcex.clearing.scheduler.config.SchedulerServiceConfig;
import ru.spcex.clearing.scheduler.config.validation.ClearingCalendarValidationConfig;
import ru.spcex.clearing.scheduler.config.validation.PlannerTemplateValidationConfig;
import ru.spcex.clearing.scheduler.config.validation.PlannerValidationConfig;
@ -60,7 +60,7 @@ import static ru.spcex.platform.enumeration.Market.mkrs;
LauncherService.class,
ErrorResolverConfig.class,
PlannerQueueConfig.class,
SchedulerTestConfig.class,
SchedulerServiceConfig.class,
ImdgTestConfig.class,
KafkaTestConfig.class})
public abstract class AbstractServiceTest {

View file

@ -85,7 +85,7 @@ class EnumPresentRuleTest extends AbstractServiceTest {
setter.accept(record, "BAD_VALUE");
enumMessages = strictValidator.validateAll();
assertEquals(1, enumMessages.size());
assertEquals(ValidationError.WrongEnumValue, enumMessages.iterator().next().getSubject());
assertEquals(ValidationError.WrongDictionaryValue, enumMessages.iterator().next().getSubject());
}
}

View file

@ -0,0 +1,20 @@
package ru.spcex.platform.enumeration;
import ru.spcex.platform.utils.enumeration.IEnumKey;
public enum TradingClearingRegistryPurpose implements IEnumKey {
M("M"),
C("C"),
;
private final String key;
TradingClearingRegistryPurpose(String key) {
this.key = key;
}
@Override
public String getKey() {
return key;
}
}

View file

@ -72,18 +72,23 @@ public interface Consts {
@Deprecated
String ACCOUNT_NEW_SDF01 = "account-new-sdf01";
String DESTINATION_RELATION_NEW = "relation-new";
String DESTINATION_RELATION_UPDATE = "relation-update";
String DESTINATION_RELATION_DELETE = "relation-delete";
String DESTINATION_PROFILE_DOCUMENT_NEW = "profile-document-new";
String DESTINATION_PROFILE_DOCUMENT_UPDATE = "profile-document-update";
String DESTINATION_PROFILE_DOCUMENT_DELETE = "profile-document-delete";
String DESTINATION_CLIENT_CODE_NEW = "client-code-new";
String DESTINATION_CLIENT_CODE_NEW_UM_COMPANY = "client-code-new-from-api-um-company";
String DESTINATION_CLIENT_CODE_UPDATE = "client-code-update";
String DESTINATION_CLIENT_CODE_DELETE = "client-code-delete";
String DESTINATION_TRADING_CLEARING_REGISTRY_NEW = "trading-clearing-registry-new";
String DESTINATION_TRADING_CLEARING_REGISTRY_AUTO_NEW = "trading-clearing-registry-auto-new";
String DESTINATION_TRADING_CLEARING_REGISTRY_UPDATE = "trading-clearing-registry-update";
String DESTINATION_TRADING_CLEARING_REGISTRY_DELETE = "trading-clearing-registry-delete";
// String DESTINATION_TRADING_CLEARING_REGISTRY_REPLY = "trading-clearing-registry";
String DESTINATION_TRADING_CLEARING_REGISTRY_BLOCK = "trading-clearing-registry-block";
String DESTINATION_SDF08_NEW = "s-df-08-new";
String DESTINATION_SDF02_NEW = "s-df-02-new";

View file

@ -0,0 +1,46 @@
package ru.spcex.clearing.platform.messaging.domain.cud.company;
import com.fasterxml.jackson.annotation.JsonProperty;
public class RelationNewRequest {
@JsonProperty
public Long companyId;
@JsonProperty
private String serviceStatus;
@JsonProperty
private String clearingMemberCategory;
@JsonProperty
private String comment;
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getServiceStatus() {
return serviceStatus;
}
public void setServiceStatus(String serviceStatus) {
this.serviceStatus = serviceStatus;
}
public String getClearingMemberCategory() {
return clearingMemberCategory;
}
public void setClearingMemberCategory(String clearingMemberCategory) {
this.clearingMemberCategory = clearingMemberCategory;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}

View file

@ -21,6 +21,8 @@ public class TradingClearingRegistryNewRequest {
private Long depoAccountId;
@JsonProperty
private String status;
@JsonProperty
private String tradingClearingRegistryType;
public Long getCompanyId() {
return companyId;
@ -50,6 +52,14 @@ public class TradingClearingRegistryNewRequest {
return status;
}
public String getTradingClearingRegistryType() {
return tradingClearingRegistryType;
}
public void setTradingClearingRegistryType(String tradingClearingRegistryType) {
this.tradingClearingRegistryType = tradingClearingRegistryType;
}
public void setStatus(String status) {
this.status = status;
}

View file

@ -1,4 +1,16 @@
package ru.spcex.clearing.platform.messaging.domain.cud.utilities;
import com.fasterxml.jackson.annotation.JsonProperty;
public class STradesImportedRequest {
@JsonProperty
private Long tradeNum;
public Long getTradeNum() {
return tradeNum;
}
public void setTradeNum(Long tradeNum) {
this.tradeNum = tradeNum;
}
}

View file

@ -77,6 +77,7 @@ public class QueueConsumer implements AutoCloseable {
public void init() {
inputExecutor.submit(() -> {
try {
log.debug("Using kafka consumer {} for subscribe on \"{}\"", consumer, callbacks.keySet());
if (supportStartOffsetTimeWindow) {
consumer.subscribe(callbacks.keySet(), new OffsetChanger(consumer, callbacks.keySet()));
} else {
@ -86,9 +87,11 @@ public class QueueConsumer implements AutoCloseable {
Header correlationId = null;
int lastErrors = 0;
while (!closed.get()) {
String lastTopic = null;
try {
ConsumerRecords<String, Object> records = consumer.poll(Duration.of(10, ChronoUnit.SECONDS));
for (ConsumerRecord<String, Object> next : records) {
lastTopic = next.topic();
correlationId = next.headers().lastHeader(KafkaHeaders.CORRELATION_ID);
ConsumerSpecificClass<?> callback = callbacks.get(next.topic());
Class<?> clazz = callback.getClazz();
@ -106,7 +109,8 @@ public class QueueConsumer implements AutoCloseable {
}
lastErrors = 0;
} catch (Throwable e) {
log.error(ExceptionUtils.getStackTrace(e));
log.error("Listener {} last topic \"{}\", error: {}",
QueueConsumer.this.getClass().getName(), lastTopic, ExceptionUtils.getStackTrace(e));
if (producer != null && o != null) {
sendErrorResponse((BaseRequest<?>) o, correlationId);
}