akulikov 2023-05-10 13:42:16 +03:00
commit 833e7b670d
46 changed files with 2370 additions and 274 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

@ -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),

View file

@ -19,8 +19,8 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.ClearingAccountUp
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.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
@ -29,7 +29,6 @@ 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;
@ -47,6 +46,7 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
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;
@ -58,6 +58,7 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
ValidationHelper validationHelper,
ImdgProvider imdgProvider,
IMessageResolver messageResolver,
RequestHelper requestHelper,
@Qualifier("clearingAccountNewRequestValidator")
Function<ClearingAccountNewRequest, IValidator> clearingAccountNewRequestValidator,
@Qualifier("clearingAccountUpdateRequestValidator")
@ -70,6 +71,7 @@ public class ClearingAccountService extends QueueConsumer implements Initializin
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;
}
@ -156,13 +158,8 @@ 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(ServiceStatus.Blocked.getKey());

View file

@ -18,8 +18,8 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.InformationAccoun
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.AccountType;
import ru.spcex.platform.enumeration.ServiceStatus;
@ -28,7 +28,6 @@ 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;
@ -44,6 +43,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali
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;
@ -56,6 +56,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali
ImdgProvider imdgProvider,
ValidationHelper validationHelper,
AccountService accountService,
RequestHelper requestHelper,
@Qualifier("informationAccountNewRequestValidator")
Function<InformationAccountNewRequest, IValidator> infoAccountNewRequestValidator) {
super(kafkaQueue, kafkaResponseQueue);
@ -64,6 +65,7 @@ public class InformationAccountService extends QueueConsumer implements Initiali
this.imdgProvider = imdgProvider;
this.validationHelper = validationHelper;
this.accountService = accountService;
this.requestHelper = requestHelper;
this.infoAccountNewRequestValidator = infoAccountNewRequestValidator;
this.informationAccountImdg = imdgProvider.getImdg(
IMDGDistributedNames.Map_InformationAccount, InformationAccount.class
@ -96,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");
}

View file

@ -23,8 +23,8 @@ import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingR
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.Status;
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;
@ -34,7 +34,6 @@ 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.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
@ -61,6 +60,7 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
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;
@ -72,6 +72,7 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
ValidationHelper validationHelper,
UserRoleVerification userRoleVerification,
IMessageResolver messageResolver,
RequestHelper requestHelper,
@Qualifier("tradingClearingRegistryNewRequest")
Function<TradingClearingRegistryNewRequest, IValidator> tradingClearingRegistryNewRequestValidator,
@Qualifier("tradingClearingRegistryUpdateRequest")
@ -81,6 +82,7 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
super(kafkaQueue, kafkaProducer);
this.validationHelper = validationHelper;
this.userRoleVerification = userRoleVerification;
this.requestHelper = requestHelper;
this.tradingClearingRegistryNewRequestValidator = tradingClearingRegistryNewRequestValidator;
this.tradingClearingRegistryImdg = imdgProvider.getImdg(
IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class
@ -149,25 +151,14 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
if (ru.spcex.platform.enumeration.Service.MKR.equalsByKey(relation.getService())) {
TradingClearingRegistry registry = tradingClearingRegistryImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (registry != null) {
String errMsg = messageResolver.resolve(
new EnumMessage(AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.getId())
);
log.error("process failed: {}", errMsg);
return new RequestInfoUpdate()
.setMessage(errMsg)
.setStatus(Status.Error)
.setId(userRequest.getId());
return requestHelper.makeErrorResponse(userRequest,
AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.getId());
}
DepoAccount depoAccountForCheck = depoAccountImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (depoAccountForCheck == null) {
String errMsg = messageResolver.resolve(new EnumMessage(AccountError.DepoAccountNotFound, req.getCompanyId()));
return new RequestInfoUpdate()
.setMessage(errMsg)
.setStatus(Status.Error)
.setId(userRequest.getId());
}
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(
@ -175,24 +166,14 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
"tradingClearingRegistryType", TradingClearingRegistryPurpose.M.getKey()
));
if (registry != null) {
String errMsg = messageResolver.resolve(
new EnumMessage(AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.getId())
);
return new RequestInfoUpdate()
.setMessage(errMsg)
.setStatus(Status.Error)
.setId(userRequest.getId());
return requestHelper.makeErrorResponse(userRequest,
AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.getId());
}
DepoAccount depoAccountForCheck = depoAccountImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (depoAccountForCheck == null) {
String errMsg = messageResolver.resolve(new EnumMessage(AccountError.DepoAccountNotFound, req.getCompanyId()));
return new RequestInfoUpdate()
.setMessage(errMsg)
.setStatus(Status.Error)
.setId(userRequest.getId());
}
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(
@ -204,23 +185,14 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
);
Collection<TradingClearingRegistry> registry = tradingClearingRegistryImdg.getCollectionObjectsByPredicate(predicate);
if (!registry.isEmpty()) {
String errMsg = messageResolver.resolve(
new EnumMessage(AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.iterator().next().getId())
);
return new RequestInfoUpdate()
.setMessage(errMsg)
.setStatus(Status.Error)
.setId(userRequest.getId());
return requestHelper.makeErrorResponse(userRequest,
AccountError.TradingClearingRegistryAlreadyExist,
req.getCompanyId(),
registry.iterator().next().getId());
}
DepoAccount depoAccountForCheck = depoAccountImdg.getSingleObjectByFieldValues(Map.of("companyId", req.getCompanyId()));
if (depoAccountForCheck == null) {
String errMsg = messageResolver.resolve(new EnumMessage(AccountError.DepoAccountNotFound, req.getCompanyId()));
return new RequestInfoUpdate()
.setMessage(errMsg)
.setStatus(Status.Error)
.setId(userRequest.getId());
return requestHelper.makeErrorResponse(userRequest, AccountError.DepoAccountNotFound, req.getCompanyId());
}
} else if (AccountType.Depo.equalsByKey(accountMain.getStatus())) {
InformationAccount infoAccountForCheck = informationAccountImdg.getSingleObjectByFieldValues(
@ -229,15 +201,8 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
ClearingAccount clearingAccountForCheck = clearingAccountImdg.getSingleObjectByFieldValues(
Map.of("companyId", req.getCompanyId())
);
if (infoAccountForCheck == null && clearingAccountForCheck == null) {
String errMsg = messageResolver.resolve(
new EnumMessage(AccountError.MoneyAccountNotFound, req.getCompanyId())
);
return new RequestInfoUpdate()
.setMessage(errMsg)
.setStatus(Status.Error)
.setId(userRequest.getId());
}
if (infoAccountForCheck == null && clearingAccountForCheck == null)
return requestHelper.makeErrorResponse(userRequest, AccountError.MoneyAccountNotFound, req.getCompanyId());
}
}
@ -262,13 +227,8 @@ public class TradingClearingRegistryService extends QueueConsumer implements Ini
if (accountMain.getStatus().equals(ServiceStatus.Closed.getKey()))
status = ServiceStatus.Closed.getKey();
}
if (status == null) {
String errMsg = messageResolver.resolve(new EnumMessage(AccountError.WrongFieldValue, req.getMoneyAccountId()));
return new RequestInfoUpdate()
.setStatus(Status.Error)
.setMessage(errMsg)
.setId(userRequest.getId());
}
if (status == null)
return requestHelper.makeErrorResponse(userRequest, AccountError.WrongFieldValue, req.getMoneyAccountId());
tradingClearingRegistry.setStatus(status);
String tradingRegistryType;

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,7 +153,8 @@ 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);

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,7 +153,8 @@ 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);

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,7 +143,9 @@ 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());

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

@ -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

@ -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

@ -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

@ -68,12 +68,12 @@ public class TradeImporterService {
}
if (byCommand) {
STradesImportedRequest sTradesImportedRequest = new STradesImportedRequest();
producer.send(new ProducerRecord<>(S_TRADES_IMPORTED, sTradesImportedRequest));
log.debug("Successfully import STrades from DB by command. Send to kafka command, topic={}", S_TRADES_IMPORTED);
} else {
log.debug("Successfully import STrades from DB by scheduled");
log.debug("Successfully import STrades from DB by scheduled. Send to kafka command, topic={}", S_TRADES_IMPORTED);
}
STradesImportedRequest sTradesImportedRequest = new STradesImportedRequest();
producer.send(new ProducerRecord<>(S_TRADES_IMPORTED, sTradesImportedRequest));
}
public STrades getSTradesFromImdg(STrades tradesDb, Imdg<STrades> sTradesImdg) {

View file

@ -72,18 +72,22 @@ 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_REPLY = "trading-clearing-registry";
String DESTINATION_TRADING_CLEARING_REGISTRY_BLOCK = "trading-clearing-registry-block";
String DESTINATION_SDF08_NEW = "s-df-08-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

@ -74,6 +74,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 {
@ -82,9 +83,11 @@ public class QueueConsumer implements AutoCloseable {
Object o = 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();
ConsumerSpecificClass<?> callback = callbacks.get(next.topic());
Class<?> clazz = callback.getClazz();
JavaType payloadType = json.getTypeFactory().constructParametricType(BaseRequest.class, clazz);
@ -98,7 +101,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);
}