This commit is contained in:
akulikov 2023-01-16 17:25:22 +03:00
commit 5167eb45f0
43 changed files with 562 additions and 92 deletions

View file

@ -24,6 +24,10 @@
<groupId>ru.spcex.platform</groupId> <groupId>ru.spcex.platform</groupId>
<artifactId>platform-imdg-api-hazelcast-impl</artifactId> <artifactId>platform-imdg-api-hazelcast-impl</artifactId>
</dependency> </dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-enum</artifactId>
</dependency>
<dependency> <dependency>
<groupId>ru.spcex.clearing</groupId> <groupId>ru.spcex.clearing</groupId>
<artifactId>classes</artifactId> <artifactId>classes</artifactId>

View file

@ -0,0 +1,14 @@
package ru.spcex.clearing.account.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.enumeration.SimpleMessageResolver;
@Configuration
public class ErrorResolverConfig {
@Bean
public IMessageResolver messageResolver() {
return new SimpleMessageResolver();
}
}

View file

@ -0,0 +1,17 @@
package ru.spcex.clearing.account.errors;
import ru.spcex.platform.utils.enumeration.IEnumId;
public enum AccountError implements IEnumId {
AccountAlreadyExist(5010L);
private final Long id;
AccountError(Long id) {
this.id = id;
}
@Override
public Long getId() {
return id;
}
}

View file

@ -7,7 +7,10 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.BankAccount; import ru.clearing.classes.statics.data.account.BankAccount;
import ru.clearing.classes.statics.data.company.relation.Relation;
import ru.spcex.clearing.account.errors.AccountError;
import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.Consts;
@ -15,36 +18,67 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountNewReq
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountUpdateRequest; import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer; 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.platform.enumeration.AccountStatus;
import ru.spcex.platform.enumeration.AccountType;
import ru.spcex.platform.enumeration.Allowed;
import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import java.time.Instant;
import java.util.Collection;
@Service @Service
public class BankAccountService extends QueueConsumer implements InitializingBean { public class BankAccountService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<BankAccount> bankAccountMap; private final Imdg<BankAccount> bankAccountMap;
private final Imdg<Account> accountMap;
private final Imdg<Relation> relationMap;
private final IMessageResolver messageResolver;
@Autowired @Autowired
public BankAccountService(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer, ImdgProvider imdgProvider) { public BankAccountService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider,
IMessageResolver messageResolver) {
super(kafkaQueue, kafkaProducer); super(kafkaQueue, kafkaProducer);
this.bankAccountMap = imdgProvider.getImdg(IMDGDistributedNames.Map_BankAccount, BankAccount.class); this.bankAccountMap = imdgProvider.getImdg(IMDGDistributedNames.Map_BankAccount, BankAccount.class);
this.accountMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Account, Account.class);
this.relationMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class);
this.messageResolver = messageResolver;
} }
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
callback(BankAccountNewRequest.class) callback(BankAccountNewRequest.class)
.setConsumer(this::bankAccountNew) .setFunction(this::bankAccountNew)
.forDestination(Consts.DESTINATION_BANK_ACCOUNT_NEW, callbacks::put); .forDestination(Consts.DESTINATION_BANK_ACCOUNT_NEW, callbacks::put);
callback(BankAccountUpdateRequest.class) callback(BankAccountUpdateRequest.class)
.setConsumer(this::bankAccountUpdate) .setFunction(this::bankAccountUpdate)
.forDestination(Consts.DESTINATION_BANK_ACCOUNT_UPDATE, callbacks::put); .forDestination(Consts.DESTINATION_BANK_ACCOUNT_UPDATE, callbacks::put);
callback(CommonDeleteRequest.class) callback(CommonDeleteRequest.class)
.setConsumer(this::bankAccountDelete) .setFunction(this::bankAccountDelete)
.forDestination(Consts.DESTINATION_BANK_ACCOUNT_DELETE, callbacks::put); .forDestination(Consts.DESTINATION_BANK_ACCOUNT_DELETE, callbacks::put);
init(); init();
} }
private void bankAccountNew(BaseRequest<BankAccountNewRequest> userRequest) { private RequestInfoUpdate bankAccountNew(BaseRequest<BankAccountNewRequest> userRequest) {
BankAccountNewRequest req = userRequest.getRequestPayload(); BankAccountNewRequest req = userRequest.getRequestPayload();
Collection<Account> accountsByKey =
accountMap.getCollectionObjectsBySQL(String.format("account = %s", req.account));
if (!accountsByKey.isEmpty()) {
String errorMsg = messageResolver.resolve(new EnumMessage(AccountError.AccountAlreadyExist));
log.error("cannot process MoneyMarketSecurityNewRequest id={}: {}", userRequest.getId(), errorMsg);
return new RequestInfoUpdate()
.setId(userRequest.getId())
.setStatus(Status.Error)
.setMessage(errorMsg);
}
log.debug("BankAccountNewRequest received"); log.debug("BankAccountNewRequest received");
BankAccount bankAccount = new BankAccount(); BankAccount bankAccount = new BankAccount();
bankAccount.setBankIdentificationCode(req.getBankIdentificationCode()); bankAccount.setBankIdentificationCode(req.getBankIdentificationCode());
@ -57,11 +91,33 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
bankAccount.setTaxRegistrationReasonCode(req.getTaxRegistrationReasonCode()); bankAccount.setTaxRegistrationReasonCode(req.getTaxRegistrationReasonCode());
bankAccount.setAccount(req.getAccount()); bankAccount.setAccount(req.getAccount());
Account account = new Account();
account.setAccount(req.account);
account.setAccountType(AccountType.Bank.getKey());
String relationSqlCondition = String.format("consumerId = %s and service = %s", req.companyId,
ru.spcex.platform.enumeration.Service.MKR.getKey());
Relation relationByCompany = relationMap.getSingleObjectBySQL(relationSqlCondition);
if (relationByCompany != null) {
account.setRelationId(relationByCompany.getId());
account.setCompanyId(relationByCompany.getConsumerId());
} else {
log.warn("Not found relation by condition: {}", relationSqlCondition);
}
account.setAccountStatus(AccountStatus.ACTIVE.getKey());
account.setProcessingSign(Allowed.ALLOWED.getKey());
account.setCreated(Instant.now());
account.setUpdated(Instant.now());
accountMap.insert(account);
bankAccount.setAccountId(account.getId());
bankAccountMap.insert(bankAccount); bankAccountMap.insert(bankAccount);
log.debug("successfully processed, new id {}", bankAccount.getId()); log.debug("successfully processed, new id {}", bankAccount.getId());
return null;
} }
private void bankAccountUpdate(BaseRequest<BankAccountUpdateRequest> userRequest) { private RequestInfoUpdate bankAccountUpdate(BaseRequest<BankAccountUpdateRequest> userRequest) {
BankAccountUpdateRequest req = userRequest.getRequestPayload(); BankAccountUpdateRequest req = userRequest.getRequestPayload();
log.debug("BankAccountUpdateRequest received id = {}", req.getId()); log.debug("BankAccountUpdateRequest received id = {}", req.getId());
BankAccount bankAccount = bankAccountMap.getSingleObjectByID(req.getId()); BankAccount bankAccount = bankAccountMap.getSingleObjectByID(req.getId());
@ -75,17 +131,29 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
bankAccount.setTaxRegistrationReasonCode(req.getTaxRegistrationReasonCode()); bankAccount.setTaxRegistrationReasonCode(req.getTaxRegistrationReasonCode());
bankAccount.setAccount(req.getAccount()); bankAccount.setAccount(req.getAccount());
Account account = accountMap.getSingleObjectByID(bankAccount.getAccountId());
account.setAccount(req.account);
account.setUpdated(Instant.now());
accountMap.update(account);
bankAccountMap.update(bankAccount); bankAccountMap.update(bankAccount);
log.debug("successfully update, existing bankAccount with id {}", bankAccount.getId()); log.debug("successfully update, existing bankAccount with id {}", bankAccount.getId());
return null;
} }
private void bankAccountDelete(BaseRequest<CommonDeleteRequest> userRequest) { private RequestInfoUpdate bankAccountDelete(BaseRequest<CommonDeleteRequest> userRequest) {
CommonDeleteRequest req = userRequest.getRequestPayload(); CommonDeleteRequest req = userRequest.getRequestPayload();
log.debug("CommonDeleteRequest received id = {}", req.getId()); log.debug("CommonDeleteRequest received id = {}", req.getId());
BankAccount bankAccount = bankAccountMap.getSingleObjectByID(req.getId()); BankAccount bankAccount = bankAccountMap.getSingleObjectByID(req.getId());
Account account = accountMap.getSingleObjectByID(bankAccount.getAccountId());
account.setAccountStatus(AccountStatus.BLOCKED.getKey());
account.setUpdated(Instant.now());
accountMap.update(account);
bankAccountMap.delete(bankAccount); bankAccountMap.delete(bankAccount);
log.debug("successfully delete, existing bankAccount with id {}", bankAccount.getId()); log.debug("successfully delete, existing bankAccount with id {}", bankAccount.getId());
return null;
} }
} }

View file

@ -17,6 +17,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.account.BankAccount; import ru.clearing.classes.statics.data.account.BankAccount;
import ru.spcex.clearing.account.config.ErrorResolverConfig;
import ru.spcex.clearing.account.config.HazelcastServiceTestConfiguration; import ru.spcex.clearing.account.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.account.utils.MatcherFactory.Matcher; import ru.spcex.clearing.account.utils.MatcherFactory.Matcher;
import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.imdg.IMDGDistributedNames;
@ -27,6 +28,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountNewReq
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountUpdateRequest; import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -35,7 +37,7 @@ import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFields
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { @ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class}) HazelcastServiceTestConfiguration.class, ErrorResolverConfig.class})
public class BankAccountServiceTest { public class BankAccountServiceTest {
public static final Matcher<BankAccount> BANK_ACCOUNT_MATCHER = usingIgnoringFieldsComparator(); public static final Matcher<BankAccount> BANK_ACCOUNT_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0; private static final int PARTITION = 0;
@ -47,6 +49,8 @@ public class BankAccountServiceTest {
@Autowired @Autowired
@Qualifier("hazelcastServiceTest") @Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest; private HazelcastService hazelcastServiceTest;
@Autowired
private IMessageResolver messageResolver;
private MockConsumer<String, Object> mockConsumer; private MockConsumer<String, Object> mockConsumer;
private MockProducer<String, Object> mockProducer; private MockProducer<String, Object> mockProducer;
@ -120,7 +124,8 @@ public class BankAccountServiceTest {
//ACT //ACT
//service set up //service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer, hazelcastServiceTest); BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer,
hazelcastServiceTest, messageResolver);
Thread.sleep(10000); Thread.sleep(10000);
//callbacks set up //callbacks set up
bankAccountService.afterPropertiesSet(); bankAccountService.afterPropertiesSet();
@ -221,7 +226,8 @@ public class BankAccountServiceTest {
//ACT //ACT
//service set up //service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer, hazelcastServiceTest); BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer,
hazelcastServiceTest, messageResolver);
Thread.sleep(10000); Thread.sleep(10000);
//callbacks set up //callbacks set up
bankAccountService.afterPropertiesSet(); bankAccountService.afterPropertiesSet();
@ -305,7 +311,8 @@ public class BankAccountServiceTest {
//ACT //ACT
//service set up //service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer, hazelcastServiceTest); BankAccountService bankAccountService = new BankAccountService(mockConsumer, mockProducer,
hazelcastServiceTest, messageResolver);
Thread.sleep(10000); Thread.sleep(10000);
//callbacks set up //callbacks set up
bankAccountService.afterPropertiesSet(); bankAccountService.afterPropertiesSet();

View file

@ -81,7 +81,7 @@ public class LauncherController extends AbstractQueueController {
} }
launcherCommand.setTask(dictionaryName); launcherCommand.setTask(dictionaryName);
launcherCommand.setUserId(user.getId()); launcherCommand.setUserId(user.getId());
//пока здесь // пока здесь, это требуется для сохранения истории
saveLauncher(dictionaryName, user.getId()); saveLauncher(dictionaryName, user.getId());
//топики ограничиваются наличием в taskDictionary //топики ограничиваются наличием в taskDictionary
//подписываются на разные топики в разных модулях, см. ru.spcex.platform.enumeration.Task#topic //подписываются на разные топики в разных модулях, см. ru.spcex.platform.enumeration.Task#topic

View file

@ -6,14 +6,16 @@ import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction; import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.BackEndError; import ru.spcex.clearing.backendapi.errors.BackEndError;
import ru.spcex.clearing.platform.messaging.domain.ActionType; import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.reports.ReportWithPeriodRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
import ru.spcex.platform.enumeration.Task;
import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.EnumMessage;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class LauncherNew implements IAction<LauncherCommandRequest> { public class LauncherNew implements IAction<Object> {
@ApiModelProperty(value = "Идентификатор единоличного исполнительного органа", example = "ABCD") @ApiModelProperty(value = "Идентификатор единоличного исполнительного органа", example = "ABCD")
@JsonProperty @JsonProperty
private String task; private String task;
@ -22,11 +24,17 @@ public class LauncherNew implements IAction<LauncherCommandRequest> {
private Long userId; private Long userId;
@Override @Override
public LauncherCommandRequest toRequest() { public Object toRequest() {
LauncherCommandRequest taskRunnerCommandRequest = new LauncherCommandRequest(); if (Task.createReport_GREP.equalsByKey(task)) {
taskRunnerCommandRequest.setTaskName(task); ReportWithPeriodRequest reportCommand = new ReportWithPeriodRequest();
taskRunnerCommandRequest.setUserId(userId); reportCommand.setReportId(task);
return taskRunnerCommandRequest; return reportCommand;
} else {
LauncherCommandRequest taskRunnerCommandRequest = new LauncherCommandRequest();
taskRunnerCommandRequest.setTaskName(task);
taskRunnerCommandRequest.setUserId(userId);
return taskRunnerCommandRequest;
}
} }
@Override @Override

View file

@ -7,7 +7,7 @@ public enum BalanceError implements IEnumId {
CurrencyNotFound(5213L), CurrencyNotFound(5213L),
CurrentDateOnly(5214L), CurrentDateOnly(5214L),
WrongMarket(5215L), WrongMarket(5215L),
WrongAccount(5215L), WrongAccount(5216L),
AccountNotPresent(5217L), AccountNotPresent(5217L),
AccountNotActive(5218L), AccountNotActive(5218L),
BalanceNotEnough(5222L), BalanceNotEnough(5222L),

View file

@ -137,6 +137,9 @@ public class Sdf09Executor extends AbstractExecutor<SDf09> {
statement.setInOutDirection(InOutDirection.in.getKey()); statement.setInOutDirection(InOutDirection.in.getKey());
statement.setAmount(sdf09.getSum()); statement.setAmount(sdf09.getSum());
statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey()); statement.setCashMovementCurrencyCode(CurrencyCode.RUB.getKey());
statement.setInSDfId(sdf09.getId());
// statement.setOutSDfId(sdf10.getId()); заполняется внешним кодом
statement.setInOutSDfType(InOutSDfType.type9.getKey());
statementImdg.update(statement); statementImdg.update(statement);
} }

View file

@ -58,7 +58,6 @@ public enum Sdf01ValidationRule implements IValidationRule<ImdgValidationContext
@Override @Override
public Optional<EnumMessage> validate(ImdgValidationContext<SDf01> context) { public Optional<EnumMessage> validate(ImdgValidationContext<SDf01> context) {
SDf01 sdf01 = context.getValidatedObject(); SDf01 sdf01 = context.getValidatedObject();
//fixme string format???
if (!LocalDate.now().equals(LocalDate.parse(sdf01.getDat(), datFormatter))) { if (!LocalDate.now().equals(LocalDate.parse(sdf01.getDat(), datFormatter))) {
return of(BalanceError.CurrentDateOnly); return of(BalanceError.CurrentDateOnly);
} }

View file

@ -1,5 +1,6 @@
package ru.spcex.clearing.balance.validation; package ru.spcex.clearing.balance.validation;
import org.slf4j.LoggerFactory;
import ru.clearing.classes.statics.data.account.Account; import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols; import ru.clearing.classes.statics.data.company.CompanySymbols;
@ -13,6 +14,7 @@ import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule; import ru.spcex.platform.utils.validation.IValidationRule;
import java.math.RoundingMode;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -23,11 +25,17 @@ public enum Sdf09ValidationRule implements IValidationRule<ImdgValidationContext
SDf09 sdf09 = context.getValidatedObject(); SDf09 sdf09 = context.getValidatedObject();
Imdg<CompanySymbols> companySymbolImdg = context.obtainMap(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); Imdg<CompanySymbols> companySymbolImdg = context.obtainMap(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
if (sdf09.getInn() == null) {
return of( BalanceError.CompanyNotFound, "empty inn");
}
String innStr = sdf09.getInn().setScale(0, RoundingMode.DOWN).toString();
CompanySymbols symbol = companySymbolImdg CompanySymbols symbol = companySymbolImdg
.getSingleObjectByFieldValues(Map.of("companySymbol", CompanySymbol.INN.getKey(), .getSingleObjectByFieldValues(Map.of("companySymbol", CompanySymbol.INN.getKey(),
"companySymbolValue", sdf09.getInn())); "companySymbolValue", innStr));
Company company = companyImdg.getSingleObjectByID(symbol.getCompanyId()); Company company = null;
if (symbol != null) {
company = companyImdg.getSingleObjectByID(symbol.getCompanyId());
}
if (company == null) { if (company == null) {
return of( BalanceError.CompanyNotFound); return of( BalanceError.CompanyNotFound);
} }

View file

@ -1,5 +1,7 @@
package ru.spcex.clearing.balance.validation; package ru.spcex.clearing.balance.validation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols; import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.sdf.SDf16; import ru.clearing.classes.statics.data.sdf.SDf16;
@ -11,6 +13,7 @@ import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule; import ru.spcex.platform.utils.validation.IValidationRule;
import java.math.RoundingMode;
import java.util.Optional; import java.util.Optional;
public enum Sdf16ValidationRule implements IValidationRule<ImdgValidationContext<SDf16>> { public enum Sdf16ValidationRule implements IValidationRule<ImdgValidationContext<SDf16>> {
@ -20,11 +23,26 @@ public enum Sdf16ValidationRule implements IValidationRule<ImdgValidationContext
SDf16 sdf16 = context.getValidatedObject(); SDf16 sdf16 = context.getValidatedObject();
Imdg<CompanySymbols> companySymbolsImdg = context.obtainMap(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); Imdg<CompanySymbols> companySymbolsImdg = context.obtainMap(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class); Imdg<Company> companyImdg = context.obtainMap(IMDGDistributedNames.Map_Company, Company.class);
CompanySymbols companySymbols = companySymbolsImdg.getSingleObjectBySQL( String sql = "";
String.format("(companySymbolValue = '%s' and companySymbol = '%s') " + if (sdf16.getInn() != null) {
"or (companySymbolValue = '%s' and companySymbol = '%s')", String innStr = sdf16.getInn().setScale(0, RoundingMode.DOWN).toString();
sdf16.getInn(), CompanySymbol.INN.getKey(), sdf16.getBic(), CompanySymbol.BIC.getKey())); sql = String.format("(companySymbolValue = '%s' and companySymbol = '%s') ",
innStr, CompanySymbol.INN.getKey());
}
if (sdf16.getBic() != null) {
if (!sql.isEmpty()) sql += " or ";
String bicStr = sdf16.getBic().setScale(0, RoundingMode.DOWN).toString();
sql += String.format("(companySymbolValue = '%s' and companySymbol = '%s') ",
bicStr, CompanySymbol.BIC.getKey());
}
Logger log = LoggerFactory.getLogger(getClass());
log.debug("SQL for search company by sdf16: {}", sql);
if (sql.isEmpty()) {
return of(BalanceError.CompanyNotFound, "inn and bic is empty");
}
Company company = null; Company company = null;
CompanySymbols companySymbols = companySymbolsImdg.getSingleObjectBySQL(sql);
log.debug("By sdf16 found companySymbol: {}", companySymbols == null ? null : companySymbols.getId());
if (companySymbols != null) { if (companySymbols != null) {
company = companyImdg.getSingleObjectByID(companySymbols.getCompanyId()); company = companyImdg.getSingleObjectByID(companySymbols.getCompanyId());
} }

View file

@ -0,0 +1,44 @@
package ru.spcex.clearing.balance.validation;
import org.junit.jupiter.api.Test;
import ru.clearing.classes.statics.data.sdf.SDf16;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import java.math.BigDecimal;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
class Sdf16ValidationRuleTest {
@Test
void values() {
ImdgValidationContext<SDf16> ctx = new ImdgValidationContext<>();
SDf16 object = new SDf16();
// object.setBic(BigDecimal.valueOf(1000004L));
object.setInn(BigDecimal.valueOf(1000024L));
ctx.setValidatedObject(object);
ctx.addImdg(IMDGDistributedNames.Map_CompanySymbols, makeTestMap());
ctx.addImdg(IMDGDistributedNames.Map_Company, makeTestMap());
Optional<EnumMessage> err = Sdf16ValidationRule.CompanyPresent.validate(ctx);
assertTrue(err.isPresent());
}
<T extends SpcexObjectBase> Imdg<T> makeTestMap() {
return new Imdg<T>() {
@Override
public String getMapName() {
return Imdg.super.getMapName();
}
@Override
public T getSingleObjectBySQL(String sql) {
return null;
}
};
}
}

View file

@ -100,7 +100,8 @@ public class ExportFromHazelcast extends Stage implements InitializingBean {
writeOk = true; writeOk = true;
emptyMap = tableRows.isEmpty(); emptyMap = tableRows.isEmpty();
} catch (Exception e) { } catch (Exception e) {
log.error(String.format("uuid %s. Can't export table %s to file %s. Table was skipped.", resultContainer.getUuid(), table, dbfFile), e); log.error(String.format("uuid %s. Can't export table %s (map %s) to file %s. Table was skipped.",
resultContainer.getUuid(), table, table.getHazelcastMapName(), dbfFile), e);
return StageResult.ERROR; return StageResult.ERROR;
} finally { } finally {
if (!writeOk || emptyMap) { if (!writeOk || emptyMap) {

View file

@ -1,24 +1,37 @@
package ru.spcex.clearing.dbf.exporter.services; package ru.spcex.clearing.dbf.exporter.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.spcex.clearing.dbf.exporter.logic.Processor; import ru.spcex.clearing.dbf.exporter.logic.Processor;
import ru.spcex.clearing.dbf.exporter.logic.data.ResultContainer; import ru.spcex.clearing.dbf.exporter.logic.data.ResultContainer;
import ru.spcex.clearing.dbf.exporter.logic.data.enums.Table; import ru.spcex.clearing.dbf.exporter.logic.data.enums.Table;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.util.Arrays;
@Service("dbfExportService") @Service("dbfExportService")
public class DBFExportService { public class DBFExportService {
Logger log = LoggerFactory.getLogger(getClass());
private final ThreadPoolTaskExecutor executor; private final ThreadPoolTaskExecutor executor;
private final Processor processor; private final Processor processor;
protected final ImdgProvider imdgProvider;
public DBFExportService(@Qualifier("executor") ThreadPoolTaskExecutor executor, public DBFExportService(@Qualifier("executor") ThreadPoolTaskExecutor executor,
@Qualifier("processor") Processor processor) { @Qualifier("processor") Processor processor,
ImdgProvider imdgProvider) {
this.executor = executor; this.executor = executor;
this.processor = processor; this.processor = processor;
this.imdgProvider = imdgProvider;
log.debug("Check IMDG...");
imdgProvider.waitAvailable();
log.debug("IMDG ready...");
} }
public void run() { public void run() {
log.debug("Do export for all: {}", Arrays.toString(Table.values()));
for (Table tableForExport : Table.values()) { for (Table tableForExport : Table.values()) {
executor.submit(() -> processor.process(ResultContainer.createNewTask(tableForExport))); executor.submit(() -> processor.process(ResultContainer.createNewTask(tableForExport)));
} }

View file

@ -5,6 +5,7 @@ import com.linuxense.javadbf.DBFField;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.sdf.SDf08; import ru.clearing.classes.statics.data.sdf.SDf08;
import java.time.format.DateTimeFormatter;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -14,7 +15,7 @@ public class S_DF08_Converter extends DFConverter<SDf08> {
public Object[] toObjectArray(SDf08 entity) { public Object[] toObjectArray(SDf08 entity) {
List<Object> values = new LinkedList<>(); List<Object> values = new LinkedList<>();
values.add(convertStrToLong(entity.getNumber())); values.add(convertStrToLong(entity.getNumber()));
values.add(convertStrToLong(entity.getDatetime())); values.add(typeMatch(convertStrToLong(entity.getDatetime()))); // UNIX TIME
return values.toArray(Object[]::new); return values.toArray(Object[]::new);
} }
@ -22,12 +23,16 @@ public class S_DF08_Converter extends DFConverter<SDf08> {
public DBFField[] getDBFHeaders() { public DBFField[] getDBFHeaders() {
List<DBFField> dbfFields = new LinkedList<>(); List<DBFField> dbfFields = new LinkedList<>();
dbfFields.add(new DBFField("NUMBER", DBFDataType.NUMERIC, 10)); dbfFields.add(new DBFField("NUMBER", DBFDataType.NUMERIC, 10));
dbfFields.add(new DBFField("DATETIME", DBFDataType.NUMERIC, 13)); dbfFields.add(new DBFField("DATETIME", DBFDataType.NUMERIC, 13)); // UNIX TIME
return dbfFields.toArray(DBFField[]::new); return dbfFields.toArray(DBFField[]::new);
} }
private Long convertStrToLong(String s) { Long convertStrToLong(String s) {
if (s == null) return null; if (s == null) return null;
return Long.valueOf(s); return Long.valueOf(s);
} }
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("dd.MM.yyyy");
private static final DateTimeFormatter DATE_TIME_FMT = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
} }

View file

@ -10,6 +10,7 @@ import ru.spcex.clearing.dbf.importer.logic.data.enums.ETable;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest; 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.QueueConsumer;
import ru.spcex.platform.enumeration.Task; import ru.spcex.platform.enumeration.Task;
import ru.spcex.platform.utils.log.ExceptionUtils;
@Service @Service
public class LauncherCommandReceiver extends QueueConsumer implements InitializingBean { public class LauncherCommandReceiver extends QueueConsumer implements InitializingBean {
@ -27,7 +28,20 @@ public class LauncherCommandReceiver extends QueueConsumer implements Initializi
public void afterPropertiesSet() { public void afterPropertiesSet() {
callback(LauncherCommandRequest.class) callback(LauncherCommandRequest.class)
.setConsumer(action -> importer.run(ETable.DF_04)) .setConsumer(action -> importer.run(ETable.DF_04))
.forDestination(Task.createOrderConfirm.topic(), callbacks::put); .forDestination(Task.createOrderConfirm.topic(), callbacks::put); // CORC
callback(LauncherCommandRequest.class)
.setConsumer(action -> importer.run(ETable.DF_01))
.forDestination(Task.dbf_GBAL.topic(), callbacks::put); // GBAL
callback(LauncherCommandRequest.class)
.setConsumer(action -> importer.run(ETable.DF_12))
.forDestination(Task.dbf_ABLK.topic(), callbacks::put); // ABLK
callback(LauncherCommandRequest.class)
.setConsumer(action -> importer.run(ETable.DF_09))
.forDestination(Task.dbf_GBLD.topic(), callbacks::put); // GBLD
callback(LauncherCommandRequest.class)
.setConsumer(action -> importer.run(ETable.DF_16))
.forDestination(Task.dbf_ADBL.topic(), callbacks::put); // ADBL
init(); init();
} }
} }

View file

@ -24,6 +24,12 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View file

@ -49,3 +49,8 @@ DAILY - все ежедневные
reports-service.kafka-consumer - группа настроек для подключения к очереди kafka reports-service.kafka-consumer - группа настроек для подключения к очереди kafka
и другие настройки. и другие настройки.
Рабочие папки
-------------
* Из настройки reports-service.ReportModuleOut=./report_out - путь к папке для результатов генерации отчётов

View file

@ -1,19 +1,20 @@
package ru.spcex.clearing.reports.notifications; package ru.spcex.clearing.reports.notifications;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.spcex.clearing.reports.exceptions.ConfigException; import ru.spcex.clearing.reports.exceptions.ConfigException;
import ru.spcex.clearing.reports.services.DOCXService; import ru.spcex.clearing.reports.services.DOCXService;
import java.io.File; import java.io.File;
import java.net.URL; import java.net.URL;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle; import java.time.format.TextStyle;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
public abstract class NotificationBuilder { public abstract class NotificationBuilder {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final DateTimeFormatter filenameDateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy'T'HH:mm:ss"); protected final DateTimeFormatter filenameDateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy'T'HH:mm:ss");
protected final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); protected final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
protected final DOCXService docxService; protected final DOCXService docxService;
@ -41,17 +42,17 @@ public abstract class NotificationBuilder {
} }
protected File getTemplateFile() { protected URL getTemplateFile() {
File templateFile;
String templateResourceName = getTemplateResourceName(); String templateResourceName = getTemplateResourceName();
URL resource = null;
try { try {
URL resource = getClass().getClassLoader().getResource(templateResourceName); resource = getClass().getClassLoader().getResource(templateResourceName);
if (resource == null) throw new Exception(); if (resource == null) throw new Exception();
templateFile = new File(resource.toURI());
} catch (Exception e) { } catch (Exception e) {
throw new ConfigException("Can't read template resource " + templateResourceName, e); throw new ConfigException("Can't read template resource " + templateResourceName +" (URL \""+resource+"\")", e);
} }
return templateFile; log.info("Use resource: {}", resource);
return resource;
} }
protected String normalizeFilenameForOS(String filename) { protected String normalizeFilenameForOS(String filename) {

View file

@ -5,6 +5,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.*; import java.io.*;
import java.net.URL;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -43,7 +44,7 @@ public class DOCXService {
/** /**
* Файл шаблона * Файл шаблона
*/ */
private File templateFile; private URL templateFile;
/** /**
* Флаг инициализации * Флаг инициализации
@ -53,13 +54,14 @@ public class DOCXService {
/** /**
* (ре)Инициализация сервиса * (ре)Инициализация сервиса
*/ */
public boolean init(File templateFile, String keyPattern) { public boolean init(URL templateFile, String keyPattern) {
initialized = false; initialized = false;
if (templateFile == null || !templateFile.exists() || !templateFile.isFile()) { if (templateFile == null /*|| !templateFile.exists() || !templateFile.isFile()*/) {
log.warn("Invalid templateFile"); log.warn("Invalid templateFile {}", templateFile);
return false; return false;
} }
this.templateFile = templateFile; this.templateFile = templateFile;
log.debug("{} use template from {}", getClass().getSimpleName(), templateFile);
if (keyPattern != null) { if (keyPattern != null) {
try { try {
this.keyPattern = Pattern.compile(keyPattern); this.keyPattern = Pattern.compile(keyPattern);
@ -108,7 +110,7 @@ public class DOCXService {
} }
} }
try (InputStream inputStream = new FileInputStream(templateFile); try (InputStream inputStream = templateFile.openStream(); //new FileInputStream(templateFile);
OutputStream outputStream = new FileOutputStream(outputFile)) { OutputStream outputStream = new FileOutputStream(outputFile)) {
XWPFDocument doc = new XWPFDocument(inputStream); XWPFDocument doc = new XWPFDocument(inputStream);
@ -125,7 +127,7 @@ public class DOCXService {
boolean checkOk = checkIntersection(valuesMap, notPresentInMap); boolean checkOk = checkIntersection(valuesMap, notPresentInMap);
if (!checkOk) { if (!checkOk) {
log.error("Can't insert values in file {}. Keys not in map: {}.", log.error("Can't insert values in file {}. Keys not in map: {}.",
templateFile.getAbsolutePath(), templateFile.toExternalForm()/*templateFile.getAbsolutePath()*/,
String.join(", ", notPresentInMap)); String.join(", ", notPresentInMap));
return false; return false;
} }

View file

@ -42,7 +42,7 @@ public class QCommandExecutor extends QueueConsumer implements InitializingBean
log.info("Init queue listener {}", getClass().getSimpleName()); log.info("Init queue listener {}", getClass().getSimpleName());
callback(ReportWithPeriodRequest.class) callback(ReportWithPeriodRequest.class)
.setConsumer(this::newReportWithPeriod) .setConsumer(this::newReportWithPeriod)
.forDestination(Task.createReport.topic(), callbacks::put); .forDestination(Task.createReport_GREP.topic(), callbacks::put);
init(); init();
} }

View file

@ -27,7 +27,7 @@ public class MapUtil {
K key = indexFieldExtractor.apply(obj); K key = indexFieldExtractor.apply(obj);
V exist = index.put(key, obj); V exist = index.put(key, obj);
if (exist != null) { if (exist != null) {
throw new IllegalStateException(String.format("%s with id=%s,%s has duplicate key=\"{}\"", throw new IllegalStateException(String.format("%s with id=%s,%s has duplicate key=\"%s\"",
exist.getClass().getSimpleName(), exist.getId(), obj.getId(), key exist.getClass().getSimpleName(), exist.getId(), obj.getId(), key
)); ));
} }

View file

@ -1,6 +1,3 @@
server.port=8080
server.servlet.context-path=/reports_service
spring.main.web-application-type=servlet
reports-service.kafka-consumer.bootstrap-servers=localhost:9092 reports-service.kafka-consumer.bootstrap-servers=localhost:9092

View file

@ -19,7 +19,7 @@ class DOCXServiceTest {
valuesMap.put("${test3}", "======== TEST 3 ========="); valuesMap.put("${test3}", "======== TEST 3 =========");
DOCXService service = new DOCXService(); DOCXService service = new DOCXService();
service.init(new File(getClass().getClassLoader().getResource("REC.ACTV_TEST.docx").getPath()), null); service.init(getClass().getClassLoader().getResource("REC.ACTV_TEST.docx"), null);
service.insertValues(new File("output.docx"), service.insertValues(new File("output.docx"),
valuesMap, valuesMap,
false); false);

View file

@ -2,11 +2,29 @@ package ru.spcex.clearing.scheduler;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.scheduler.service.PlannerService;
@SpringBootApplication @SpringBootApplication
public class SchedulerServiceApplication { public class SchedulerServiceApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SchedulerServiceApplication.class); SpringApplication springApplication = new SpringApplication(SchedulerServiceApplication.class);
springApplication.run(args); ConfigurableApplicationContext context = springApplication.run(args);
PlannerService plannerService = context.getBean(PlannerService.class);
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
var baseRequest = new BaseRequest<PlannerNewRequest>();
var plannerNewRequest = new PlannerNewRequest();
plannerNewRequest.task = "GBAL";
baseRequest.setId(777L);
baseRequest.setRequestPayload(plannerNewRequest);
RequestInfoUpdate requestInfoUpdate = plannerService.newScheduler(baseRequest);
System.out.println(requestInfoUpdate.toString());
} }
} }

View file

@ -0,0 +1,14 @@
package ru.spcex.clearing.scheduler.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.enumeration.SimpleMessageResolver;
@Configuration
public class ErrorResolverConfig {
@Bean
public IMessageResolver messageResolver() {
return new SimpleMessageResolver();
}
}

View file

@ -2,10 +2,6 @@ package ru.spcex.clearing.scheduler.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.account.Account;
import ru.clearing.classes.statics.data.account.AccountBalance;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.platform.dictionary.TaskDictionary; import ru.clearing.platform.dictionary.TaskDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest;
@ -30,10 +26,7 @@ public class ValidationConfig {
public ValidationConfig(ImdgProvider imdgProvider) { public ValidationConfig(ImdgProvider imdgProvider) {
this.imdgs = new HashMap<>(); this.imdgs = new HashMap<>();
BiConsumer<String, Class<? extends SpcexObjectBase>> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass)); BiConsumer<String, Class<? extends SpcexObjectBase>> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass));
addImdg.accept(IMDGDistributedNames.Map_Account, Account.class); addImdg.accept(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_Company, Company.class);
addImdg.accept(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
addImdg.accept(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class);
} }
/** /**
@ -50,7 +43,6 @@ public class ValidationConfig {
context.setValidatedObject(plannerNewRequest); context.setValidatedObject(plannerNewRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, getImdg(s)); Consumer<String> addImdg = (s) -> context.addImdg(s, getImdg(s));
addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); addImdg.accept(IMDGDistributedNames.Map_TaskDictionary);
addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary);
return new ValidatorImpl<>(context, return new ValidatorImpl<>(context,
EnumPresentRule.instance("task", EnumPresentRule.instance("task",
PlannerNewRequest::getTask, PlannerNewRequest::getTask,

View file

@ -2,14 +2,13 @@ package ru.spcex.clearing.scheduler.error;
import ru.spcex.platform.utils.enumeration.IEnumId; import ru.spcex.platform.utils.enumeration.IEnumId;
public enum Errors implements IEnumId { public enum PlannerErrors implements IEnumId {
WrongFieldValue(10003L) WrongEnumValue(10003L),
; ;
private final Long id; private final Long id;
Errors(Long id) { PlannerErrors(Long id) {
this.id = id; this.id = id;
} }

View file

@ -0,0 +1,68 @@
package ru.spcex.clearing.scheduler.service;
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.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.reports.ReportWithPeriodRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
import ru.spcex.platform.enumeration.Task;
import ru.spcex.platform.imdg.api.ImdgId;
import ru.spcex.platform.imdg.api.ImdgProvider;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Service
public class LauncherSender {
Logger log = LoggerFactory.getLogger(getClass());
private final Producer<String, Object> kafka;
private final ImdgId idGenerator;
@Autowired
public LauncherSender(Producer<String, Object> kafka, ImdgProvider imdgProvider) {
this.kafka = kafka;
this.idGenerator = imdgProvider.getImdgIdGenerator();
}
protected BaseRequest<Object> makeCmdRequest(Task byTask, Long userId) {
Object toRequest;
if (Task.createReport_GREP.equals(byTask)) { // см. ru.spcex.clearing.backendapi.controller.request.cud.schedule.LauncherNew#toRequest
ReportWithPeriodRequest reportCommand = new ReportWithPeriodRequest();
reportCommand.setReportId(byTask.getKey());
toRequest = reportCommand;
} else {
LauncherCommandRequest taskRunnerCommandRequest = new LauncherCommandRequest();
taskRunnerCommandRequest.setTaskName(byTask.getKey());
taskRunnerCommandRequest.setUserId(userId);
toRequest = taskRunnerCommandRequest;
}
BaseRequest<Object> request = new BaseRequest<>();
request.setId(idGenerator.nextId());
request.setActionType(ActionType.NEW);
request.setRequestPayload(toRequest);// iAction.toRequest()
return request;
}
public void sendCommandToQueue(Task toTaskQueue, Long userId) {
BaseRequest<Object> request = makeCmdRequest(toTaskQueue, userId);
String destination = toTaskQueue.topic(); // "launcher-" + getKey()
log.debug("Send command {} to {}", toTaskQueue, destination);
Future<RecordMetadata> send = kafka.send(new ProducerRecord<>(destination, request));
try {
send.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Command " + toTaskQueue + " not send", e);
} catch (ExecutionException e) {
throw new RuntimeException("Command " + toTaskQueue + " not send", e);
}
}
}

View file

@ -0,0 +1,12 @@
package ru.spcex.clearing.scheduler.service;
import ru.spcex.platform.utils.enumeration.EnumMessage;
public class NewRequestResult {
private EnumMessage error;
public NewRequestResult(EnumMessage validationError) {
this.error = validationError;
}
}

View file

@ -6,6 +6,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.scheduler.Planner; import ru.clearing.classes.statics.data.scheduler.Planner;
import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.imdg.IMDGDistributedNames;
@ -15,34 +16,48 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer; 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.scheduler.IRequestValidator; import ru.spcex.clearing.scheduler.IRequestValidator;
import ru.spcex.clearing.scheduler.error.PlannerErrors;
import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.validation.IValidator;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@Service @Service
public class PlannerService extends QueueConsumer implements InitializingBean { public class PlannerService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
private final ImdgProvider imdgProvider; private final ImdgProvider imdgProvider;
private final Imdg<Planner> plannerMap; private final Imdg<Planner> plannerMap;
private final IRequestValidator<PlannerNewRequest> plannerNewRequest = IRequestValidator.PLANNER_NEW_REQUEST; private final IMessageResolver messageResolver;
private final Function<PlannerNewRequest, IValidator> validationFactory;
private final IRequestValidator<PlannerUpdateRequest> plannerUpdateRequest = IRequestValidator.PLANNER_UPDATE_REQUEST; private final IRequestValidator<PlannerUpdateRequest> plannerUpdateRequest = IRequestValidator.PLANNER_UPDATE_REQUEST;
private final IRequestValidator<CommonDeleteRequest> deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST; private final IRequestValidator<CommonDeleteRequest> deleteRequestValidator = IRequestValidator.COMMON_DELETE_REQUEST;
@Autowired @Autowired
public PlannerService(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer, public PlannerService(Consumer<String, Object> kafkaQueue,
ImdgProvider imdgProvider) { Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider,
IMessageResolver messageResolver,
@Qualifier("plannerNewRequestValidator") Function<PlannerNewRequest, IValidator> plannerNewRequestValidator) {
super(kafkaQueue, kafkaProducer); super(kafkaQueue, kafkaProducer);
this.plannerMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Planner, Planner.class); this.plannerMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Planner, Planner.class);
this.messageResolver = messageResolver;
this.validationFactory = plannerNewRequestValidator;
this.imdgProvider = imdgProvider; this.imdgProvider = imdgProvider;
} }
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
callback(PlannerNewRequest.class) callback(PlannerNewRequest.class)
.setConsumer(this::newScheduler) .setFunction(this::newScheduler)
.forDestination(Consts.DESTINATION_PLANNER_NEW, callbacks::put); .forDestination(Consts.DESTINATION_PLANNER_NEW, callbacks::put);
callback(PlannerUpdateRequest.class) callback(PlannerUpdateRequest.class)
.setConsumer(this::updateScheduler) .setConsumer(this::updateScheduler)
@ -53,11 +68,19 @@ public class PlannerService extends QueueConsumer implements InitializingBean {
init(); init();
} }
private void newScheduler(BaseRequest<PlannerNewRequest> userRequest) { public RequestInfoUpdate newScheduler(BaseRequest<PlannerNewRequest> userRequest) {
PlannerNewRequest req = userRequest.getRequestPayload(); PlannerNewRequest req = userRequest.getRequestPayload();
log.debug("PlannerNewRequest received"); log.debug("PlannerNewRequest received");
List<IRequestValidator.ValidationError> errors = plannerNewRequest.validate(req, imdgProvider); IValidator validator = validationFactory.apply(req);
if (IRequestValidator.checkErrorList(errors, log)) return; Optional<EnumMessage> validationError = validator.tillFirstError();
if (validationError.isPresent()) {
String errorMsg = messageResolver.resolve(new EnumMessage(PlannerErrors.WrongEnumValue));
log.error("cannot process PlannerNewRequest id={}: {}", userRequest.getId(), errorMsg);
return new RequestInfoUpdate()
.setId(userRequest.getId())
.setStatus(Status.Error)
.setMessage(errorMsg);
}
Planner planner = new Planner(); Planner planner = new Planner();
planner.setCreated(Instant.now()); planner.setCreated(Instant.now());
planner.setTask(req.getTask()); planner.setTask(req.getTask());
@ -69,6 +92,7 @@ public class PlannerService extends QueueConsumer implements InitializingBean {
planner.setSecurityId(req.getSecurityId()); planner.setSecurityId(req.getSecurityId());
plannerMap.insert(planner); plannerMap.insert(planner);
log.debug("successfully processed, new id {}", planner.getId()); log.debug("successfully processed, new id {}", planner.getId());
return null;
} }
private void updateScheduler(BaseRequest<PlannerUpdateRequest> userRequest) { private void updateScheduler(BaseRequest<PlannerUpdateRequest> userRequest) {

View file

@ -49,12 +49,15 @@ public class TaskManager implements EntryAddedListener<Long, PlannerAllToday>,
private Imdg<Launcher> launcherMap; private Imdg<Launcher> launcherMap;
private Imdg<PlannerAllToday> plannerAllTodayMap; private Imdg<PlannerAllToday> plannerAllTodayMap;
private ConcurrentHashMap<LocalTime, ScheduledFuture> scheduledJobs; private ConcurrentHashMap<LocalTime, ScheduledFuture> scheduledJobs;
private LauncherSender launcherSender;
@Autowired @Autowired
TaskManager(TaskScheduler taskScheduler, TaskManager(TaskScheduler taskScheduler,
ImdgProvider imdgProvider) { ImdgProvider imdgProvider,
LauncherSender launcherSender) {
this.taskScheduler = taskScheduler; this.taskScheduler = taskScheduler;
this.imdgProvider = imdgProvider; this.imdgProvider = imdgProvider;
this.launcherSender = launcherSender;
} }
private static LocalDateTime dateOldTypeConvert(@NonNull Date oldDate) { private static LocalDateTime dateOldTypeConvert(@NonNull Date oldDate) {
@ -220,8 +223,10 @@ public class TaskManager implements EntryAddedListener<Long, PlannerAllToday>,
// --- Реализация выполнения задач --- // --- Реализация выполнения задач ---
protected void doJob(PlannerAllToday task) { protected void doJob(PlannerAllToday task) {
if (getEnumByKey(Task.class, task.getTask()) != null) { Task taskE = getEnumByKey(Task.class, task.getTask());
if (taskE != null) {
log.debug("LauncherCommandRequest received"); log.debug("LauncherCommandRequest received");
// 1. cохранить команду
Instant created = Instant.now(); Instant created = Instant.now();
Launcher launcher = new Launcher(); Launcher launcher = new Launcher();
launcher.setTask(task.getTask()); launcher.setTask(task.getTask());
@ -229,6 +234,8 @@ public class TaskManager implements EntryAddedListener<Long, PlannerAllToday>,
launcher.setCreated(created); launcher.setCreated(created);
launcher.setUpdated(created); launcher.setUpdated(created);
launcherMap.insert(launcher); launcherMap.insert(launcher);
// 2. отправить сообщение
launcherSender.sendCommandToQueue(taskE, task.getParentId());
log.debug("successfully processed, new id {}", launcher.getId()); log.debug("successfully processed, new id {}", launcher.getId());
} }
} }

View file

@ -1,6 +1,6 @@
package ru.spcex.clearing.scheduler.validation.rules; package ru.spcex.clearing.scheduler.validation.rules;
import ru.spcex.clearing.scheduler.error.Errors; import ru.spcex.clearing.scheduler.error.PlannerErrors;
import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.imdg.validation.ImdgValidationContext;
@ -41,7 +41,7 @@ public class EnumPresentRule<T, D extends SpcexObjectBase> implements IValidatio
); );
D taskFromMap = dictImdg.getSingleObjectByFieldValues(Map.of("code", enumCode)); D taskFromMap = dictImdg.getSingleObjectByFieldValues(Map.of("code", enumCode));
if (taskFromMap == null) { if (taskFromMap == null) {
return of(Errors.WrongFieldValue, fieldName); return of(PlannerErrors.WrongEnumValue, fieldName);
} }
return empty(); return empty();
} }

View file

@ -7,6 +7,7 @@ import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSe
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityUpdateRequest; import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityUpdateRequest;
import ru.spcex.clearing.securities.errors.SecuritiesError; import ru.spcex.clearing.securities.errors.SecuritiesError;
import ru.spcex.clearing.securities.validation.rule.EndDtAfterStartDt; import ru.spcex.clearing.securities.validation.rule.EndDtAfterStartDt;
import ru.spcex.clearing.securities.validation.rule.MmsDeleteValidationRule;
import ru.spcex.clearing.securities.validation.rule.MmsNewValidationRule; import ru.spcex.clearing.securities.validation.rule.MmsNewValidationRule;
import ru.spcex.clearing.securities.validation.rule.MmsUpdateValidationRule; import ru.spcex.clearing.securities.validation.rule.MmsUpdateValidationRule;
import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.classes.base.SpcexObjectBase;
@ -59,7 +60,8 @@ public class ValidationProvider {
context.setValidatedObject(mmsRequest); context.setValidatedObject(mmsRequest);
context.addImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, mmsMap); context.addImdg(IMDGDistributedNames.Map_MoneyMarketSecurity, mmsMap);
return new ValidatorImpl<>(context, return new ValidatorImpl<>(context,
new PresentById(IMDGDistributedNames.Map_MoneyMarketSecurity, SecuritiesError.InstrumentNotFound, true) new PresentById(IMDGDistributedNames.Map_MoneyMarketSecurity, SecuritiesError.InstrumentNotFound, true),
MmsDeleteValidationRule.StatusIsActive
); );
}; };
} }

View file

@ -0,0 +1,32 @@
package ru.spcex.clearing.securities.validation.rule;
import ru.clearing.classes.statics.data.misc.MoneyMarketSecurity;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityUpdateRequest;
import ru.spcex.clearing.securities.errors.SecuritiesError;
import ru.spcex.platform.enumeration.Status;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.imdg.validation.Stored;
import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.validation.IValidationRule;
import java.util.Optional;
public enum MmsDeleteValidationRule implements IValidationRule<ImdgValidationContext<MoneyMarketSecurityUpdateRequest>> {
StatusIsActive() {
@Override
public Optional<EnumMessage> validate(ImdgValidationContext<MoneyMarketSecurityUpdateRequest> context) {
MoneyMarketSecurity mms = context.getStoredObject(Stored.PresentById);
//проверка только если PresentById найдет объект и сохранит его
if (mms != null && !Status.Active.getKey().equals(mms.getWorkflowStatus())) {
return of(SecuritiesError.InstrumentNotActive);
} else {
return empty();
}
}
};
@Override
public String ruleName() {
return "MmsDeleteValidationRule." + name();
}
}

View file

@ -27,6 +27,6 @@ public enum MmsUpdateValidationRule implements IValidationRule<ImdgValidationCon
@Override @Override
public String ruleName() { public String ruleName() {
return "MmsNewValidationRule." + name(); return "MmsUpdateValidationRule." + name();
} }
} }

View file

@ -0,0 +1,18 @@
package ru.spcex.platform.enumeration;
import ru.spcex.platform.utils.enumeration.IEnumKey;
public enum AccountStatus implements IEnumKey {
ACTIVE("ACTV"), BLOCKED("BLKD"), CLOSE("CLOS");
private final String key;
AccountStatus(String key) {
this.key = key;
}
@Override
public String getKey() {
return key;
}
}

View file

@ -0,0 +1,18 @@
package ru.spcex.platform.enumeration;
import ru.spcex.platform.utils.enumeration.IEnumKey;
public enum Allowed implements IEnumKey {
ALLOWED("ALWD"), DENIED("DEND");
private final String key;
Allowed(String key) {
this.key = key;
}
@Override
public String getKey() {
return key;
}
}

View file

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

View file

@ -13,10 +13,13 @@ public enum Task implements IEnumKey {
startOfPreClearing("SPRC"),// Запуск преклиринга startOfPreClearing("SPRC"),// Запуск преклиринга
startPostClearing("SPOC"),// Запуск постклиринга startPostClearing("SPOC"),// Запуск постклиринга
createOrder("CORD"), createOrder("CORD"),
dbf_GBAL("GBAL"),
dbf_ABLK("ABLK"),
dbf_GBLD("GBLD"),
dbf_ADBL("ADBL"),
createOrderConfirm("CORC"), createOrderConfirm("CORC"),
getAllBalance("GALB"), getAllBalance("GALB"),
createReport("RPRT");// Создание отчёта (report-service) createReport_GREP("GREP");// Создание отчёта (report-service) RPRT нескольких видов, этот GREP
private final String key; private final String key;

View file

@ -4,23 +4,25 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class BankAccountNewRequest { public class BankAccountNewRequest {
@JsonProperty @JsonProperty
public String bankIdentificationCode;//Банковский идентификационный код (БИК) public String bankIdentificationCode;
@JsonProperty @JsonProperty
public String bankName;//Наименование банка public String bankName;
@JsonProperty @JsonProperty
public String correspondentAccount;//Корреспондентский счет public String correspondentAccount;
@JsonProperty @JsonProperty
public String correspondentAccountName;//Наименование корреспондентского счета public String correspondentAccountName;
@JsonProperty @JsonProperty
public String currency;//Идентификатор валюты public String currency;
@JsonProperty @JsonProperty
public String destination;//Назначение public String destination;
@JsonProperty @JsonProperty
public String taxpayerIdentificationNumber;//Идентификационный номер налогоплательщика (ИНН) public String taxpayerIdentificationNumber;
@JsonProperty @JsonProperty
public String taxRegistrationReasonCode;//Код причины постановки (КПП) public String taxRegistrationReasonCode;
@JsonProperty @JsonProperty
public String account;//Номер счета public String account;
@JsonProperty
public Long companyId;
public String getBankIdentificationCode() { public String getBankIdentificationCode() {
return bankIdentificationCode; return bankIdentificationCode;

View file

@ -39,4 +39,13 @@ public class RequestInfoUpdate {
this.message = message; this.message = message;
return this; return this;
} }
@Override
public String toString() {
return "RequestInfoUpdate{" +
"id=" + id +
", status=" + status +
", message='" + message + '\'' +
'}';
}
} }