account-service http://jira.mfd.msk:8088/browse/CLS-577, imdg http://jira.mfd.msk:8088/browse/CLS-575 добавил AccountSymbolsUpdate в UpdateMapService.java

This commit is contained in:
AKurakin 2023-10-31 17:23:03 +03:00
parent 9eff119ff2
commit a2dcd21867
7 changed files with 365 additions and 2 deletions

View file

@ -0,0 +1,70 @@
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.AccountSymbols;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.account.AccountSymbolsNewRequest;
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.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
@Configuration
public class AccountSymbolsValidationConfig {
@Bean("accountSymbolsNewRequest")
public Function<AccountSymbolsNewRequest, IValidator> correspondentAccountNewRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return accountSymbolsNewRequest -> {
ImdgValidationContext<AccountSymbolsNewRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(accountSymbolsNewRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Account);
addImdg.accept(IMDGDistributedNames.Map_AccountSymbols);
return new ValidatorImpl<>(context,
IdPresentRule.instance("accountId",
AccountSymbolsNewRequest::getAccountId,
IMDGDistributedNames.Map_Account,
Account.class,
AccountError.RequiredFieldEmpty,
AccountError.CompanyNotFound,
false
),
new DuplicateAccountSymbolsRule()
);
};
}
static class DuplicateAccountSymbolsRule implements IValidationRule<ImdgValidationContext<AccountSymbolsNewRequest>> {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<AccountSymbolsNewRequest> context) {
AccountSymbolsNewRequest validatedObject = context.getValidatedObject();
Imdg<AccountSymbols> accountSymbolsImdg = context.obtainMap(IMDGDistributedNames.Map_AccountSymbols, AccountSymbols.class);
Map<String, Comparable<?>> query = new HashMap<>();
query.put("accountId", validatedObject.getAccountId());
query.put("accountSymbolValue", validatedObject.getAccountSymbolValue());
Collection<AccountSymbols> existAccSymbols = accountSymbolsImdg.getCollectionObjectsByFieldValues(query);
if (existAccSymbols.isEmpty()) {
return empty();
} else {
AccountSymbols existAS = existAccSymbols.iterator().next();
return of(AccountError.AccountAlreadyExist, existAS.getAccountId());
}
}
}
}

View file

@ -41,6 +41,7 @@ public class ValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_DepoAccount, DepoAccount.class);
addImdg.accept(IMDGDistributedNames.Map_ServiceStatusDictionary, ServiceStatusDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
addImdg.accept(IMDGDistributedNames.Map_AccountSymbols, AccountSymbols.class);
//for ClientCodeValidationConfig
addImdg.accept(IMDGDistributedNames.Map_ClientCode, ClientCode.class);

View file

@ -0,0 +1,122 @@
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.*;
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.account.AccountSymbolsNewRequest;
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.sender.KafkaSender;
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.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
import java.util.function.Function;
@Service
public class AccountSymbolsService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ValidationHelper validationHelper;
private final UserRoleVerification userRoleVerification;
private final ImdgProvider imdgProvider;
private final Imdg<AccountSymbols> accountSymbolsImdg;
private final RequestHelper requestHelper;
private final Function<AccountSymbolsNewRequest, IValidator> accountSymbolsNewRequestValidator;
private final IMessageResolver messageResolver;
private final Producer<String, Object> kafkaProducer;
private final KafkaSender kafkaSender;
public AccountSymbolsService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
KafkaSender kafkaSender,
ImdgProvider imdgProvider,
ValidationHelper validationHelper,
UserRoleVerification userRoleVerification,
IMessageResolver messageResolver,
RequestHelper requestHelper,
@Qualifier("accountSymbolsNewRequest")
Function<AccountSymbolsNewRequest, IValidator> accountSymbolsNewRequestValidator
) {
super(kafkaQueue, kafkaProducer);
this.kafkaProducer = kafkaProducer;
this.kafkaSender = kafkaSender;
this.validationHelper = validationHelper;
this.userRoleVerification = userRoleVerification;
this.requestHelper = requestHelper;
this.imdgProvider = imdgProvider;
this.accountSymbolsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_AccountSymbols, AccountSymbols.class);
this.accountSymbolsNewRequestValidator = accountSymbolsNewRequestValidator;
this.messageResolver = messageResolver;
}
@Override
public void afterPropertiesSet() throws Exception {
imdgProvider.waitAvailable();
callback(AccountSymbolsNewRequest.class)
.setFunction(this::accountSymbolsNew)
.forDestination(Consts.DESTINATION_DEPO_ACCOUNT_SYMBOLS_NEW, callbacks::put);
callback(CommonIdRequest.class)
.setFunction(this::accountSymbolsDelete)
.forDestination(Consts.DESTINATION_DEPO_ACCOUNT_SYMBOLS_DELETE, callbacks::put);
init();
}
protected RequestInfoUpdate accountSymbolsNew(BaseRequest<AccountSymbolsNewRequest> userRequest) {
log.debug("AccountSymbolsNewRequest received, id={}", userRequest.getId());
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
requestInfoUpdate = validationHelper.validateTillFirstError(userRequest, accountSymbolsNewRequestValidator);
if (requestInfoUpdate != null) return requestInfoUpdate;
AccountSymbolsNewRequest req = userRequest.getRequestPayload();
Long id = accountSymbolsImdg.nextIDSequenceFor();
AccountSymbols accountSymbols = new AccountSymbols();
accountSymbols.setId(id);
accountSymbols.setAccountId(req.getAccountId());
accountSymbols.setAccountSymbolValue(req.getAccountSymbolValue());
accountSymbolsImdg.insert(accountSymbols);
log.debug("successfully processed, id {}. New accountSymbols.id={} was created", id, accountSymbols.getId());
return null;
}
protected RequestInfoUpdate accountSymbolsDelete(BaseRequest<CommonIdRequest> userRequest) {
log.debug("AccountSymbolsDeleteRequest(CommonIdRequest) received, id={}", userRequest.getId());
RequestInfoUpdate requestInfoUpdate = userRoleVerification.validateRoleAndGetResult(userRequest);
if (requestInfoUpdate != null) return requestInfoUpdate;
CommonIdRequest req = userRequest.getRequestPayload();
AccountSymbols accountSymbols = accountSymbolsImdg.getSingleObjectByID(req.getId());
if (accountSymbols == null) {
return requestHelper.makeErrorResponse(userRequest, AccountError.AccountNotFound, req.getId());
}
accountSymbolsImdg.delete(accountSymbols);
log.debug("successfully processed, id {}. New accountSymbols.id={} was deleted", userRequest.getId(), accountSymbols.getId());
return null;
}
}

View file

@ -0,0 +1,164 @@
package ru.spcex.clearing.account.service;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.producer.Producer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.account.*;
import ru.spcex.clearing.account.config.BeanConfiguration;
import ru.spcex.clearing.account.config.validation.AccountSymbolsValidationConfig;
import ru.spcex.clearing.account.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.account.AccountSymbolsNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.test.MatcherFactory;
import ru.spcex.clearing.test.TestObjectCreator;
import ru.spcex.clearing.test.config.ImdgTestConfig;
import ru.spcex.clearing.test.config.KafkaTestConfig;
import ru.spcex.platform.enumeration.*;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import static ru.spcex.clearing.test.MatcherFactory.usingIgnoringFieldsComparator;
import static ru.spcex.clearing.test.TestUtils.*;
import static ru.spcex.clearing.test.config.KafkaTestConfig.setMockFuture;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
BeanConfiguration.class,
ValidationConfig.class,
AccountSymbolsValidationConfig.class,
AccountSymbolsService.class,
ImdgTestConfig.class,
KafkaTestConfig.class})
class AccountSymbolsServiceTest {
public static final MatcherFactory.Matcher<AccountSymbols> ACCOUNT_SYMBOL_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
@Autowired
AccountSymbolsService accountSymbolsService;
@Autowired
@Qualifier("hazelcastServiceTest")
private ImdgProvider hazelcastServiceTest;
@Autowired
@Qualifier("mockProducer")
protected Producer<String, Object> mockProducer;
@Autowired
@Qualifier("kafkaTestTemplate")
protected KafkaTemplate<String, Object> kafkaTemplate;
private Imdg<AccountSymbols> accountSymbolsImdg;
private Imdg<Account> accountImdg;
private Long accountId;
private Imdg<ClearingAccount> clearingAccountImdg;
private Long clearingAccountId;
static int newRequestCnt = 0;
@PostConstruct
private void init() {
hazelcastServiceTest.waitAvailable();
accountSymbolsImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_AccountSymbols, AccountSymbols.class
);
accountImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_Account, Account.class
);
clearingAccountImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_ClearingAccount, ClearingAccount.class
);
Account account = new Account();
account.setStatus(ServiceStatus.Active.getKey());
account.setAccountType(AccountType.Clrn.getKey());
accountId = accountImdg.insert(account);
ClearingAccount clearingAccount = new ClearingAccount();
clearingAccount.setAccountId(accountId);
clearingAccount.setClearingAccountType("CAT");
clearingAccountId = clearingAccountImdg.insert(clearingAccount);
new TestObjectCreator(hazelcastServiceTest).createUserAdmin(1000L);
}
@PreDestroy
private void destroyTest() {
//clean test data
Account account = accountImdg.getSingleObjectByID(accountId);
if (account != null)
accountImdg.delete(account);
ClearingAccount clearingAccount = clearingAccountImdg.getSingleObjectByID(clearingAccountId);
if (clearingAccount != null)
clearingAccountImdg.delete(clearingAccount);
}
@Test
void tradingClearingRegistryNew_moneyAccount_clearingAccount() {
setMockFuture(kafkaTemplate);
AccountSymbolsNewRequest accountSymbolsNewRequest = new AccountSymbolsNewRequest();
accountSymbolsNewRequest.setAccountId(accountId);
accountSymbolsNewRequest.setAccountSymbolValue("SYMBOL1");
AccountSymbols predictableAccountSymbols = new AccountSymbols();
predictableAccountSymbols.setAccountId(accountId);
predictableAccountSymbols.setAccountSymbolValue("SYMBOL1");
String jsonString = getJsonStringForNew(accountSymbolsNewRequest, 0L);
addRecordToKafka((MockConsumer) accountSymbolsService.getConsumer(),
Consts.DESTINATION_DEPO_ACCOUNT_SYMBOLS_NEW,
newRequestCnt,
0,
jsonString);
waitingSendAndCheckRecord(0L, mockProducer);
AccountSymbols resultNew = accountSymbolsImdg.getAllValues().iterator().next();
predictableAccountSymbols.setId(resultNew.getId());
ACCOUNT_SYMBOL_MATCHER.assertMatch(resultNew, predictableAccountSymbols);
accountSymbolsImdg.delete(resultNew); // cleanup test
newRequestCnt++;
}
@Test
void tradingClearingRegistryDelete() {
AccountSymbols existAccountSymbols = new AccountSymbols();
existAccountSymbols.setAccountId(accountId);
existAccountSymbols.setAccountSymbolValue("SYMBOL 2");
Long accountSymbolId = accountSymbolsImdg.insert(existAccountSymbols);
CommonDeleteRequest accountSymbolsDeleteRequest = new CommonDeleteRequest();
accountSymbolsDeleteRequest.setId(accountSymbolId);
String jsonString = getJsonStringForDelete(accountSymbolsDeleteRequest, 0);
//ACT
addRecordToKafka((MockConsumer) accountSymbolsService.getConsumer(),
Consts.DESTINATION_DEPO_ACCOUNT_SYMBOLS_DELETE,
PARTITION,
0,
jsonString);
//ASSERT
waitingSendAndCheckRecord(0L, mockProducer);
AccountSymbols resultUpdating = accountSymbolsImdg.getSingleObjectByID(accountSymbolId);
Assertions.assertNull(resultUpdating, "Должен был удалиться");
}
}

View file

@ -65,7 +65,7 @@ public class AccountSymbolsController extends AbstractQueueController {
@PathVariable("id") Long id) throws ExecutionException, InterruptedException {
CommonDeleteAction deleteAction = new CommonDeleteAction();
deleteAction.setId(id);
return processRequest(Consts.DESTINATION_DEPO_ACCOUNT_SYMBOLS_BLOCK, deleteAction);
return processRequest(Consts.DESTINATION_DEPO_ACCOUNT_SYMBOLS_DELETE, deleteAction);
}
}

View file

@ -73,6 +73,7 @@ public class UpdateMapService extends AbstractUpdateMapService {
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_Registry).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_Session).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_TradingClearingRegistry).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_AccountSymbols).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
}
@Override
@ -214,6 +215,11 @@ public class UpdateMapService extends AbstractUpdateMapService {
createBusinessEvent(tradingClearingRegistryHistory, eventType);
tradingClearingRegistryHistory.setObject((TradingClearingRegistry) value);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_TradingClearingRegistryHistory).put(tradingClearingRegistryHistory.getId(), tradingClearingRegistryHistory);
} else if (value instanceof AccountSymbols) {
AccountSymbolsHistory accountSymbolsHistory = new AccountSymbolsHistory();
createBusinessEvent(accountSymbolsHistory, eventType);
accountSymbolsHistory.setObject((AccountSymbols) value);
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_TradingClearingRegistryHistory).put(accountSymbolsHistory.getId(), accountSymbolsHistory);
} else if (value instanceof Security) { // Существуют наследники этой таблицы, по этому в последнюю очередь делать эту проверку.

View file

@ -156,7 +156,7 @@ public interface Consts {
String LAUNCHER_NEW = "launcher-new";
String DESTINATION_DEPO_ACCOUNT_SYMBOLS_NEW = "depo-accounts-symbols-new";
String DESTINATION_DEPO_ACCOUNT_SYMBOLS_BLOCK = "depo-accounts-symbols-block";
String DESTINATION_DEPO_ACCOUNT_SYMBOLS_DELETE = "depo-accounts-symbols-delete";
String REQUEST_INFO_UPDATE = "request-info-update";