diff --git a/clearing-parent/imdg/pom.xml b/clearing-parent/imdg/pom.xml index 5a35a391a..cb06f2437 100644 --- a/clearing-parent/imdg/pom.xml +++ b/clearing-parent/imdg/pom.xml @@ -71,6 +71,10 @@ ru.spcex.platform platform-imdg-api-hazelcast-impl + + ru.spcex.platform + platform-enum + diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java index 53a6dd15a..8b9ea7df8 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractHazelcastLifecycleSupport.java @@ -19,17 +19,17 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; -import static ru.spcex.clearing.imdg.util.Util.makeSchedulerAllTodayMap; - //todo почистить класс public abstract class AbstractHazelcastLifecycleSupport implements InitializingBean, DisposableBean { private final Logger log = LoggerFactory.getLogger(this.getClass()); private final HazelcastInstance hazelcastServerInstance; private final JdbcTemplate jdbcTemplate; + private final PlannerAllTodayMaker plannerAllTodayMaker; - public AbstractHazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate) { + public AbstractHazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate, PlannerAllTodayMaker plannerAllTodayMaker) { this.hazelcastServerInstance = hazelcastServerInstance; this.jdbcTemplate = jdbcTemplate; + this.plannerAllTodayMaker = plannerAllTodayMaker; } /** @@ -103,7 +103,7 @@ public abstract class AbstractHazelcastLifecycleSupport implements InitializingB boolean generatorResult = generator.init(maxKey); if (generatorResult) { log.info("IDGenerator {} success init by {}", IMDGDistributedNames.MAP_SEQUENCE_NAME, maxKey); - makeSchedulerAllTodayMap(hazelcastServerInstance); + plannerAllTodayMaker.makeSchedulerAllTodayMap(); } else { log.info("IDGenerator {} already initialized in other node", IMDGDistributedNames.MAP_SEQUENCE_NAME); } diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java index e248a2054..bf249777b 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/HazelcastLifecycleSupport.java @@ -19,8 +19,8 @@ public class HazelcastLifecycleSupport extends AbstractHazelcastLifecycleSupport private final Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired - public HazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate) { - super(hazelcastServerInstance, jdbcTemplate); + public HazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate, PlannerAllTodayMaker plannerAllTodayMaker) { + super(hazelcastServerInstance, jdbcTemplate, plannerAllTodayMaker); } @Override diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/PlannerAllTodayMaker.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/PlannerAllTodayMaker.java new file mode 100644 index 000000000..81e9c8dc8 --- /dev/null +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/PlannerAllTodayMaker.java @@ -0,0 +1,117 @@ +package ru.spcex.clearing.imdg.services; + +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.core.IMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.scheduler.ClearingCalendar; +import ru.clearing.classes.statics.data.scheduler.Planner; +import ru.clearing.classes.statics.data.scheduler.PlannerAllToday; +import ru.clearing.classes.statics.data.scheduler.PlannerTemplate; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.Parent; +import ru.spcex.platform.enumeration.Status; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static ru.spcex.clearing.imdg.IMDGDistributedNames.*; + +@Service +public class PlannerAllTodayMaker { + private final HazelcastInstance hazelcastInstance; + private final IMap plannerMap; + private final IMap clearingCalendarMap; + private final IMap plannerTemplateMap; + private final IMap plannerAllTodayMap; + + @Autowired + public PlannerAllTodayMaker(HazelcastInstance hazelcastInstance) { + this.hazelcastInstance = hazelcastInstance; + plannerMap = hazelcastInstance.getMap(Map_Planner); + clearingCalendarMap = hazelcastInstance.getMap(Map_ClearingCalendar); + plannerTemplateMap = hazelcastInstance.getMap(Map_PlannerTemplate); + plannerAllTodayMap = hazelcastInstance.getMap(Map_PlannerAllToday); + } + + public void makeSchedulerAllTodayMap() { + LocalDate currentDate = LocalDate.now(); + List listOfPlannerAllToday = new ArrayList<>(); + + if (!plannerMap.isEmpty()) listOfPlannerAllToday.addAll(getPlannersAllTodayToDate(currentDate)); + + plannerMap.values().stream() + .filter(x -> x.getTaskStatus() != null) + .filter((x) -> x.getClearingDate() == null || x.getClearingDate().isEqual(currentDate)).forEach((x) -> { + if (x.getTaskStatus().equalsIgnoreCase(Status.Active.getKey())) { + listOfPlannerAllToday.add(createPlannerAllTodayFromPlanner(x)); + } + + if (x.getTaskStatus().equalsIgnoreCase(Status.Cancel.getKey()) || x.getTaskStatus().equalsIgnoreCase(Status.Blocked.getKey())) { + listOfPlannerAllToday.removeIf((allToday) -> x.getTaskTime().equals(allToday.getTaskTime()) && + x.getTask().equalsIgnoreCase(allToday.getTask())); + } + }); + for (PlannerAllToday plannerAllToday : listOfPlannerAllToday) { + plannerAllToday.setId(hazelcastInstance.getIdGenerator(MAP_SEQUENCE_NAME).newId()); + plannerAllTodayMap.put(plannerAllToday.getId(), plannerAllToday); + } + } + + private List getPlannersAllTodayToDate(LocalDate currentDate) { + boolean weekend = Arrays.asList(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY).contains(currentDate.getDayOfWeek()); + List res = new ArrayList<>(); + if (clearingCalendarMap == null || clearingCalendarMap.isEmpty()) { + if (!weekend) { + for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { + res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); + } + } + } else { + Optional clearingCalendarOptional = clearingCalendarMap.values().stream() + .filter((calendar) -> calendar.getClearingDate().isEqual(currentDate)) + .findFirst(); + if (clearingCalendarOptional.isPresent()) { + ClearingCalendar calendar = clearingCalendarOptional.get(); + if (calendar.getDayStatus().equalsIgnoreCase(DayStatus.Workday.getKey())) { + if (calendar.getCompanyId() != null && calendar.getCompanyId() != 0) { + for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { + res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); + } + } + } + } + } + + return res; + } + + private PlannerAllToday createPlannerAllTodayFromPlanner(Planner planner) { + PlannerAllToday res = new PlannerAllToday(); + res.setTask(planner.getTask()); + res.setTaskTime(planner.getTaskTime()); + res.setClearingDate(planner.getClearingDate()); + res.setMarket(planner.getMarket()); + res.setTaskStatus(planner.getTaskStatus()); + res.setCompanyId(planner.getCompanyId()); + res.setSecurityId(planner.getSecurityId()); + res.setParent(Parent.Planner.getKey()); + res.setParentId(planner.getId()); + return res; + } + + private PlannerAllToday createPlannerAllTodayFromPlannerTemplate(PlannerTemplate plannerTemplate) { + PlannerAllToday res = new PlannerAllToday(); + res.setTask(plannerTemplate.getTask()); + res.setTaskTime(plannerTemplate.getTaskTime()); + res.setTaskStatus(plannerTemplate.getTaskStatus()); + res.setParent(Parent.Template.getKey()); + res.setParentId(plannerTemplate.getId()); + return res; + } + +} diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/util/Util.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/util/Util.java deleted file mode 100644 index 8ed0e6696..000000000 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/util/Util.java +++ /dev/null @@ -1,115 +0,0 @@ -package ru.spcex.clearing.imdg.util; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; -import ru.clearing.classes.statics.data.scheduler.ClearingCalendar; -import ru.clearing.classes.statics.data.scheduler.Planner; -import ru.clearing.classes.statics.data.scheduler.PlannerAllToday; -import ru.clearing.classes.statics.data.scheduler.PlannerTemplate; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static ru.spcex.clearing.imdg.IMDGDistributedNames.*; - -public class Util { - - public static void makeSchedulerAllTodayMap(HazelcastInstance hazelcastInstance) { - IMap plannerMap = hazelcastInstance.getMap(Map_Planner); - IMap clearingCalendarMap = hazelcastInstance.getMap(Map_ClearingCalendar); - IMap plannerTemplateMap = hazelcastInstance.getMap(Map_PlannerTemplate); - IMap plannerAllTodayMap = hazelcastInstance.getMap(Map_PlannerAllToday); - LocalDate currentDate = LocalDate.now(); - List listOfPlannerAllToday = new ArrayList<>(); - - - if (!plannerMap.isEmpty()) { - switch (currentDate.getDayOfWeek()) { - case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> listOfPlannerAllToday.addAll(getPlannersOnMonday2Friday(currentDate, clearingCalendarMap, plannerTemplateMap)); - case SUNDAY, SATURDAY -> listOfPlannerAllToday.addAll(getPlannersOnSunday2Saturday(currentDate, clearingCalendarMap, plannerTemplateMap)); - } - } - - plannerMap.values().stream() - .filter(x -> x.getTaskStatus() != null) - .filter((x) -> x.getClearingDate() == null || x.getClearingDate().isEqual(currentDate)).forEach((x) -> { - if (x.getTaskStatus().equalsIgnoreCase("ACTV")) { - listOfPlannerAllToday.add(createPlannerAllTodayFromPlanner(x)); - } - - if (x.getTaskStatus().equalsIgnoreCase("CNCL") || x.getTaskStatus().equalsIgnoreCase("BLKD")) { - listOfPlannerAllToday.removeIf((allToday) -> !x.getTaskTime().equals(allToday.getTaskTime()) || - !x.getTask().equalsIgnoreCase(allToday.getTask())); - } - }); - for (PlannerAllToday plannerAllToday : listOfPlannerAllToday) { - plannerAllToday.setId(hazelcastInstance.getIdGenerator(MAP_SEQUENCE_NAME).newId()); - plannerAllTodayMap.put(plannerAllToday.getId(), plannerAllToday); - } - } - - private static List getPlannersOnMonday2Friday(LocalDate currentDate, IMap clearingCalendarMap, IMap plannerTemplateMap) { - List res = new ArrayList<>(); - if (clearingCalendarMap == null || clearingCalendarMap.isEmpty()) { - for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { - res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); - } - } else { - Optional clearingCalendarOptional = clearingCalendarMap.values().stream().filter((calendar) -> calendar.getClearingDate().isEqual(currentDate)).findFirst(); - if (clearingCalendarOptional.isPresent()) { - ClearingCalendar calendar = clearingCalendarOptional.get(); - if (calendar.getDayStatus().equalsIgnoreCase("BDAY")) { - if (calendar.getCompanyId() != null && calendar.getCompanyId() != 0) { - for (PlannerTemplate plannerTemplate : - plannerTemplateMap.values()) { - res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); - } - } - } - } - } - - return res; - } - - private static List getPlannersOnSunday2Saturday(LocalDate currentDate, IMap clearingCalendarMap, IMap plannerTemplateMap) { - List res = new ArrayList<>(); - Optional clearingCalendarOptional = clearingCalendarMap.values().stream().filter((calendar) -> calendar.getClearingDate().isEqual(currentDate)).findFirst(); - if (clearingCalendarOptional.isPresent()) { - ClearingCalendar clearingCalendar = clearingCalendarOptional.get(); - if (clearingCalendar.getDayStatus().equalsIgnoreCase("BDAY")) { - for (PlannerTemplate plannerTemplate : plannerTemplateMap.values()) { - res.add(createPlannerAllTodayFromPlannerTemplate(plannerTemplate)); - } - } - } - return res; - } - - private static PlannerAllToday createPlannerAllTodayFromPlanner(Planner planner) { - PlannerAllToday res = new PlannerAllToday(); - res.setTask(planner.getTask()); - res.setTaskTime(planner.getTaskTime()); - res.setClearingDate(planner.getClearingDate()); - res.setMarket(planner.getMarket()); - res.setTaskStatus(planner.getTaskStatus()); - res.setCompanyId(planner.getCompanyId()); - res.setSecurityId(planner.getSecurityId()); - res.setParent("PLNR"); - res.setParentId(planner.getId()); - return res; - } - - private static PlannerAllToday createPlannerAllTodayFromPlannerTemplate(PlannerTemplate plannerTemplate) { - PlannerAllToday res = new PlannerAllToday(); - res.setTask(plannerTemplate.getTask()); - res.setTaskTime(plannerTemplate.getTaskTime()); - res.setTaskStatus(plannerTemplate.getTaskStatus()); - res.setParent("TMPL"); - res.setParentId(plannerTemplate.getId()); - return res; - } - -} diff --git a/clearing-parent/scheduler-service/pom.xml b/clearing-parent/scheduler-service/pom.xml index 04774fd14..cb13c4eef 100644 --- a/clearing-parent/scheduler-service/pom.xml +++ b/clearing-parent/scheduler-service/pom.xml @@ -28,6 +28,10 @@ ru.spcex.platform platform-imdg-api-hazelcast-impl + + ru.spcex.clearing + dictionary + ru.spcex.clearing classes diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ErrorResolverConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ErrorResolverConfig.java new file mode 100644 index 000000000..c64e7c10e --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/ErrorResolverConfig.java @@ -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(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ClearingCalendarValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ClearingCalendarValidationConfig.java new file mode 100644 index 000000000..c16595d10 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ClearingCalendarValidationConfig.java @@ -0,0 +1,100 @@ +package ru.spcex.clearing.scheduler.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.scheduler.ClearingCalendar; +import ru.clearing.platform.dictionary.DayStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.DateNotBeforeRule; +import ru.spcex.clearing.scheduler.validation.rules.common.DictionaryPresentRule; +import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.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 ClearingCalendarValidationConfig { + + @Bean("clearingCalendarNewRequestValidator") + public Function clearingCalendarNewRequestValidator(Map> imdgForValidation) { + return clearingCalendarNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clearingCalendarNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_DayStatusDictionary); + return new ValidatorImpl<>(context, + DateNotBeforeRule.instance("clearingDate", + ClearingCalendarNewRequest::getClearingDate), + IdPresentRule.instance("companyId", + ClearingCalendarNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + DictionaryPresentRule.instance("dayStatus", + ClearingCalendarNewRequest::getDayStatus, + IMDGDistributedNames.Map_DayStatusDictionary, + DayStatusDictionary.class) + ); + }; + } + + @Bean("clearingCalendarUpdateRequestValidator") + public Function clearingCalendarUpdateRequestValidator(Map> imdgForValidation) { + return clearingCalendarUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clearingCalendarUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_DayStatusDictionary); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + ClearingCalendarUpdateRequest::getId, + IMDGDistributedNames.Map_ClearingCalendar, + ClearingCalendar.class, + ValidationError.RecordNotFound), + DateNotBeforeRule.instance("clearingDate", + ClearingCalendarUpdateRequest::getClearingDate), + IdPresentRule.instance("companyId", + ClearingCalendarUpdateRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + DictionaryPresentRule.instance("dayStatus", + ClearingCalendarUpdateRequest::getDayStatus, + IMDGDistributedNames.Map_DayStatusDictionary, + DayStatusDictionary.class) + ); + }; + } + + @Bean("clearingCalendarDeleteRequestValidator") + public Function clearingCalendarDeleteRequestValidator() { + return clearingCalendarDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(clearingCalendarDeleteRequest); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_ClearingCalendar, + ClearingCalendar.class, + ValidationError.RecordNotFound) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java new file mode 100644 index 000000000..56c9f706f --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerTemplateValidationConfig.java @@ -0,0 +1,132 @@ +package ru.spcex.clearing.scheduler.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.scheduler.PlannerTemplate; +import ru.clearing.classes.statics.data.security.Security; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.DictionaryPresentRule; +import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; +import ru.spcex.clearing.scheduler.validation.rules.common.TimeNotBeforeRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.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 PlannerTemplateValidationConfig { + + @Bean("plannerTemplateNewRequestValidator") + public Function plannerNewRequestValidator(Map> imdgForValidation) { + return plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + DictionaryPresentRule.instance("task", + PlannerTemplateNewRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class), + TimeNotBeforeRule.instance("taskTime", + PlannerTemplateNewRequest::getTaskTime), + DictionaryPresentRule.instance("taskStatus", + PlannerTemplateNewRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class), + IdPresentRule.instance("companyId", + PlannerTemplateNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerTemplateNewRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + + @Bean("plannerTemplateUpdateRequestValidator") + public Function plannerUpdateRequestValidator(Map> imdgForValidation) { + return plannerUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + PlannerTemplateUpdateRequest::getId, + IMDGDistributedNames.Map_PlannerTemplate, + PlannerTemplate.class, + ValidationError.RecordNotFound), + DictionaryPresentRule.instance("task", + PlannerTemplateNewRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class, + false), + TimeNotBeforeRule.instance("taskTime", + PlannerTemplateNewRequest::getTaskTime, + false), + DictionaryPresentRule.instance("taskStatus", + PlannerTemplateNewRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class, + false), + IdPresentRule.instance("companyId", + PlannerTemplateNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + false, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerTemplateNewRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + false, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + + + @Bean("plannerTemplateDeleteRequestValidator") + public Function plannerTemplateDeleteRequestValidator() { + return plannerTemplateDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerTemplateDeleteRequest); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_PlannerTemplate, + PlannerTemplate.class, + ValidationError.RecordNotFound) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java new file mode 100644 index 000000000..16a4e8501 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/PlannerValidationConfig.java @@ -0,0 +1,143 @@ +package ru.spcex.clearing.scheduler.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.scheduler.Planner; +import ru.clearing.classes.statics.data.security.Security; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerUpdateRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.*; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.Market; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.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 PlannerValidationConfig { + + @Bean("plannerNewRequestValidator") + public Function plannerNewRequestValidator(Map> imdgForValidation) { + return plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + DictionaryPresentRule.instance("task", + PlannerNewRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class), + TimeNotBeforeRule.instance("taskTime", + PlannerNewRequest::getTaskTime), + DateNotBeforeRule.instance("clearingDate", + PlannerNewRequest::getClearingDate), + EnumPresentRule.instance("market", + PlannerNewRequest::getMarket, + Market.values(), + false), + DictionaryPresentRule.instance("taskStatus", + PlannerNewRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class), + IdPresentRule.instance("companyId", + PlannerNewRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerNewRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + + @Bean("plannerUpdateRequestValidator") + public Function plannerUpdateRequestValidator(Map> imdgForValidation) { + return plannerUpdateRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerUpdateRequest); + Consumer addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary); + addImdg.accept(IMDGDistributedNames.Map_Company); + addImdg.accept(IMDGDistributedNames.Map_Security); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + PlannerUpdateRequest::getId, + IMDGDistributedNames.Map_Planner, + Planner.class, + ValidationError.RecordNotFound), + DictionaryPresentRule.instance("task", + PlannerUpdateRequest::getTask, + IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class, + false), + TimeNotBeforeRule.instance("taskTime", + PlannerUpdateRequest::getTaskTime, + false), + DateNotBeforeRule.instance("clearingDate", + PlannerUpdateRequest::getClearingDate, + false), + EnumPresentRule.instance("market", + PlannerUpdateRequest::getMarket, + Market.values(), + false), + DictionaryPresentRule.instance("taskStatus", + PlannerUpdateRequest::getTaskStatus, + IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class, + false), + IdPresentRule.instance("companyId", + PlannerUpdateRequest::getCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + ValidationError.CompanyNotFound, + false, + company -> WorkflowStatus.Active.getKey().equals(company.getWorkflowStatus()) ? null : ValidationError.CompanyNotActive), + IdPresentRule.instance("securityId", + PlannerUpdateRequest::getSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + ValidationError.SecurityNotFound, + false, + security -> WorkflowStatus.Active.getKey().equals(security.getWorkflowStatus()) ? null : ValidationError.SecurityNotActive) + ); + }; + } + + @Bean("plannerDeleteRequestValidator") + public Function plannerDeleteRequestValidator() { + return plannerDeleteRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerDeleteRequest); + return new ValidatorImpl<>(context, + IdPresentRule.instance("id", + CommonDeleteRequest::getId, + IMDGDistributedNames.Map_Planner, + Planner.class, + ValidationError.RecordNotFound) + ); + }; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java new file mode 100644 index 000000000..d12745c9e --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/config/validation/ValidationConfig.java @@ -0,0 +1,34 @@ +package ru.spcex.clearing.scheduler.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.security.Security; +import ru.clearing.platform.dictionary.DayStatusDictionary; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +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.api.ImdgProvider; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; + +@Configuration +public class ValidationConfig { + + @Bean("imdgForValidation") + public Map> imdgForValidation(ImdgProvider imdgProvider) { + final Map> imdg = new HashMap<>(); + BiConsumer> addImdg = (s, aClass) -> imdg.put(s, imdgProvider.getImdg(s, aClass)); + addImdg.accept(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class); + addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); + addImdg.accept(IMDGDistributedNames.Map_Security, Security.class); + addImdg.accept(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class); + return imdg; + } + +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java new file mode 100644 index 000000000..ea04bfa3a --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/error/ValidationError.java @@ -0,0 +1,29 @@ +package ru.spcex.clearing.scheduler.error; + +import ru.spcex.platform.utils.enumeration.IEnumId; + +public enum ValidationError implements IEnumId { + WrongDictionaryValue(10003L), + EmptyRequiredValue(10002L), + WrongEnumValue(777L), //todo set code + RecordNotFound(7006L), + TaskForPastDate(7010L), + TaskForPastTime(7011L), + CompanyNotFound(7014L), + SecurityNotFound(7012L), + CompanyNotActive(7015L), + SecurityNotActive(7013L) + ; + + private final Long id; + + ValidationError(Long id) { + this.id = id; + } + + + @Override + public Long getId() { + return id; + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java index 3a86684b7..adbf15094 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/ClearingCalendarService.java @@ -6,6 +6,7 @@ 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.scheduler.ClearingCalendar; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -15,40 +16,58 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; +import java.util.function.Function; @Service public class ClearingCalendarService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg clearingCalendarMap; + private final IMessageResolver messageResolver; + private final Function clearingCalendarDeleteRequestValidation; + private final Function clearingCalendarNewRequestValidation; + private final Function clearingCalendarUpdateRequestValidation; @Autowired public ClearingCalendarService(Consumer kafkaQueue, Producer kafkaProducer, - ImdgProvider imdgProvider) { + ImdgProvider imdgProvider, + IMessageResolver messageResolver, + @Qualifier("clearingCalendarDeleteRequestValidator") Function clearingCalendarDeleteRequestValidator, + @Qualifier("clearingCalendarNewRequestValidator") Function clearingCalendarNewRequestValidator, + @Qualifier("clearingCalendarUpdateRequestValidator") Function clearingCalendarUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.clearingCalendarMap = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingCalendar, ClearingCalendar.class); + this.clearingCalendarDeleteRequestValidation = clearingCalendarDeleteRequestValidator; + this.clearingCalendarNewRequestValidation = clearingCalendarNewRequestValidator; + this.clearingCalendarUpdateRequestValidation = clearingCalendarUpdateRequestValidator; + this.messageResolver = messageResolver; } @Override public void afterPropertiesSet() { callback(ClearingCalendarNewRequest.class) - .setConsumer(this::newClearingCalendar) + .setFunction(this::newClearingCalendar) .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_NEW, callbacks::put); callback(ClearingCalendarUpdateRequest.class) - .setConsumer(this::updateClearingCalendar) + .setFunction(this::updateClearingCalendar) .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_UPDATE, callbacks::put); callback(CommonDeleteRequest.class) - .setConsumer(this::deleteClearingCalendar) + .setFunction(this::deleteClearingCalendar) .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_DELETE, callbacks::put); init(); } - private void newClearingCalendar(BaseRequest userRequest) { + private RequestInfoUpdate newClearingCalendar(BaseRequest userRequest) { ClearingCalendarNewRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarNewRequest received"); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, clearingCalendarNewRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); clearingCalendar.setCreated(created); @@ -57,11 +76,14 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi clearingCalendar.setDayStatus(req.getDayStatus()); clearingCalendarMap.insert(clearingCalendar); log.debug("successfully processed, new id {}", clearingCalendar.getId()); + return null; } - private void updateClearingCalendar(BaseRequest userRequest) { + private RequestInfoUpdate updateClearingCalendar(BaseRequest userRequest) { ClearingCalendarUpdateRequest req = userRequest.getRequestPayload(); log.debug("ClearingCalendarUpdateRequest received"); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, clearingCalendarUpdateRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Instant updated = Instant.now(); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendar.setClearingDate(req.getClearingDate()); @@ -70,12 +92,16 @@ public class ClearingCalendarService extends QueueConsumer implements Initializi clearingCalendar.setUpdated(updated); clearingCalendarMap.update(clearingCalendar); log.debug("successfully processed, new id {}", clearingCalendar.getId()); + return null; } - private void deleteClearingCalendar(BaseRequest userRequest) { + private RequestInfoUpdate deleteClearingCalendar(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, clearingCalendarDeleteRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; log.debug("CommonDeleteRequest received id = {}", req.getId()); ClearingCalendar clearingCalendar = clearingCalendarMap.getSingleObjectByID(req.getId()); clearingCalendarMap.delete(clearingCalendar); + return null; } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java index 199c12ab4..4f0870dbc 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerService.java @@ -6,6 +6,7 @@ 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.scheduler.Planner; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -15,40 +16,59 @@ 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.PlannerUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; +import java.util.function.Function; @Service public class PlannerService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg plannerMap; + private final IMessageResolver messageResolver; + private final Function plannerDeleteRequestValidation; + private final Function plannerNewRequestValidation; + private final Function plannerUpdateRequestValidation; @Autowired - public PlannerService(Consumer kafkaQueue, Producer kafkaProducer, - ImdgProvider imdgProvider) { + public PlannerService(Consumer kafkaQueue, + Producer kafkaProducer, + ImdgProvider imdgProvider, + IMessageResolver messageResolver, + @Qualifier("plannerDeleteRequestValidator") Function plannerDeleteRequestValidator, + @Qualifier("plannerNewRequestValidator") Function plannerNewRequestValidator, + @Qualifier("plannerUpdateRequestValidator") Function plannerUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.plannerMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Planner, Planner.class); + this.messageResolver = messageResolver; + this.plannerDeleteRequestValidation = plannerDeleteRequestValidator; + this.plannerNewRequestValidation = plannerNewRequestValidator; + this.plannerUpdateRequestValidation = plannerUpdateRequestValidator; } @Override public void afterPropertiesSet() { callback(PlannerNewRequest.class) - .setConsumer(this::newScheduler) + .setFunction(this::newScheduler) .forDestination(Consts.DESTINATION_PLANNER_NEW, callbacks::put); callback(PlannerUpdateRequest.class) - .setConsumer(this::updateScheduler) + .setFunction(this::updateScheduler) .forDestination(Consts.DESTINATION_PLANNER_UPDATE, callbacks::put); callback(CommonDeleteRequest.class) - .setConsumer(this::deleteScheduler) + .setFunction(this::deleteScheduler) .forDestination(Consts.DESTINATION_PLANNER_DELETE, callbacks::put); init(); } - private void newScheduler(BaseRequest userRequest) { + private RequestInfoUpdate newScheduler(BaseRequest userRequest) { PlannerNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerNewRequest received"); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerNewRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Planner planner = new Planner(); planner.setCreated(Instant.now()); planner.setTask(req.getTask()); @@ -60,11 +80,14 @@ public class PlannerService extends QueueConsumer implements InitializingBean { planner.setSecurityId(req.getSecurityId()); plannerMap.insert(planner); log.debug("successfully processed, new id {}", planner.getId()); + return null; } - private void updateScheduler(BaseRequest userRequest) { + private RequestInfoUpdate updateScheduler(BaseRequest userRequest) { PlannerUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerUpdateRequest received id = {}", req.getId()); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerUpdateRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Planner planner = plannerMap.getSingleObjectByID(req.getId()); planner.setUpdated(Instant.now()); planner.setTask(req.getTask()); @@ -75,13 +98,17 @@ public class PlannerService extends QueueConsumer implements InitializingBean { planner.setCompanyId(req.getCompanyId()); planner.setSecurityId(req.getSecurityId()); plannerMap.update(planner); + return null; } - private void deleteScheduler(BaseRequest userRequest) { + private RequestInfoUpdate deleteScheduler(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerDeleteRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; Planner planner = plannerMap.getSingleObjectByID(req.getId()); plannerMap.delete(planner); + return null; } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java index 77a1466a0..2b7c7c76a 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/PlannerTemplateService.java @@ -6,6 +6,7 @@ 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.scheduler.PlannerTemplate; import ru.spcex.clearing.imdg.IMDGDistributedNames; @@ -15,40 +16,58 @@ import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteReques import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Instant; +import java.util.function.Function; @Service public class PlannerTemplateService extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Imdg plannerTemplateMap; + private final IMessageResolver messageResolver; + private final Function plannerTemplateDeleteRequestValidation; + private final Function plannerTemplateNewRequestValidation; + private final Function plannerTemplateUpdateRequestValidation; @Autowired public PlannerTemplateService(Consumer kafkaQueue, Producer kafkaProducer, - ImdgProvider imdgProvider) { + ImdgProvider imdgProvider, + IMessageResolver messageResolver, + @Qualifier("plannerTemplateDeleteRequestValidator") Function plannerTemplateDeleteRequestValidator, + @Qualifier("plannerTemplateNewRequestValidator") Function plannerTemplateNewRequestValidator, + @Qualifier("plannerTemplateUpdateRequestValidator") Function plannerTemplateUpdateRequestValidator) { super(kafkaQueue, kafkaProducer); this.plannerTemplateMap = imdgProvider.getImdg(IMDGDistributedNames.Map_PlannerTemplate, PlannerTemplate.class); + this.plannerTemplateDeleteRequestValidation = plannerTemplateDeleteRequestValidator; + this.plannerTemplateNewRequestValidation = plannerTemplateNewRequestValidator; + this.plannerTemplateUpdateRequestValidation = plannerTemplateUpdateRequestValidator; + this.messageResolver = messageResolver; } @Override public void afterPropertiesSet() { callback(PlannerTemplateNewRequest.class) - .setConsumer(this::newTimetable) + .setFunction(this::newTimetable) .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_NEW, callbacks::put); callback(PlannerTemplateUpdateRequest.class) - .setConsumer(this::updateTimetable) + .setFunction(this::updateTimetable) .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_UPDATE, callbacks::put); callback(CommonDeleteRequest.class) - .setConsumer(this::deleteTimetable) + .setFunction(this::deleteTimetable) .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_DELETE, callbacks::put); init(); } - private void newTimetable(BaseRequest userRequest) { + private RequestInfoUpdate newTimetable(BaseRequest userRequest) { PlannerTemplateNewRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateNewRequest received"); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerTemplateNewRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; PlannerTemplate plannerTemplate = new PlannerTemplate(); Instant created = Instant.now(); plannerTemplate.setCreated(created); @@ -59,11 +78,14 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin plannerTemplate.setSecurityId(req.getSecurityId()); plannerTemplateMap.insert(plannerTemplate); log.debug("successfully processed, new id {}", plannerTemplate.getId()); + return null; } - private void updateTimetable(BaseRequest userRequest) { + private RequestInfoUpdate updateTimetable(BaseRequest userRequest) { PlannerTemplateUpdateRequest req = userRequest.getRequestPayload(); log.debug("PlannerTemplateUpdateRequest received"); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerTemplateUpdateRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); Instant updated = Instant.now(); plannerTemplate.setUpdated(updated); @@ -74,12 +96,16 @@ public class PlannerTemplateService extends QueueConsumer implements Initializin plannerTemplate.setSecurityId(req.getSecurityId()); plannerTemplateMap.update(plannerTemplate); log.debug("successfully processed, new id {}", plannerTemplate.getId()); + return null; } - private void deleteTimetable(BaseRequest userRequest) { + private RequestInfoUpdate deleteTimetable(BaseRequest userRequest) { CommonDeleteRequest req = userRequest.getRequestPayload(); log.debug("CommonDeleteRequest received id = {}", req.getId()); + RequestInfoUpdate requestInfoUpdate = validate(userRequest, plannerTemplateDeleteRequestValidation, messageResolver); + if (requestInfoUpdate != null) return requestInfoUpdate; PlannerTemplate plannerTemplate = plannerTemplateMap.getSingleObjectByID(req.getId()); plannerTemplateMap.delete(plannerTemplate); + return null; } } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java index b0a8708d5..bcc7fbc07 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java @@ -18,6 +18,7 @@ import ru.spcex.platform.enumeration.Status; import ru.spcex.platform.enumeration.Task; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgHazelcast; import java.time.*; import java.util.ArrayList; @@ -75,6 +76,9 @@ public class TaskManager implements EntryAddedListener, public void afterPropertiesSet() { this.launcherMap = imdgProvider.getImdg(Map_Launcher, Launcher.class); this.plannerAllTodayMap = imdgProvider.getImdg(Map_PlannerAllToday, PlannerAllToday.class); + if (plannerAllTodayMap instanceof ImdgHazelcast plannerAllTodayImdgHazelcast) { + plannerAllTodayImdgHazelcast.getMap().addEntryListener(this, true); + } scheduledJobs = new ConcurrentHashMap<>(); updateScheduler(); } diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java new file mode 100644 index 000000000..b1df393c6 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DateNotBeforeRule.java @@ -0,0 +1,45 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.time.LocalDate; +import java.util.Optional; +import java.util.function.Function; + +/** + * Проверка поля с LocalDate. Условие проверки: поверяемая дата >= текущая дата + * @param Класс проверяемого объекта + */ +public record DateNotBeforeRule(String fieldName, Function getter, boolean required) implements IValidationRule> { + + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемой даты + * @param required Флаг обязательности поля + * @param Класс проверяемого объекта + */ + public static DateNotBeforeRule instance(String fieldName, Function getter, boolean required) { + return new DateNotBeforeRule<>(fieldName, getter, required); + } + + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемой даты + * @param Класс проверяемого объекта + */ + public static DateNotBeforeRule instance(String fieldName, Function getter) { + return new DateNotBeforeRule<>(fieldName, getter, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + LocalDate date = getter.apply(validatedObject); + if (date == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : Optional.empty(); + if (date.isBefore(LocalDate.now())) return of(ValidationError.TaskForPastDate, fieldName); + return Optional.empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java new file mode 100644 index 000000000..999f484bb --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/DictionaryPresentRule.java @@ -0,0 +1,81 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Collection; +import java.util.Optional; +import java.util.function.Function; + +/** + * Проверка поля с кодом из словаря (таблицы *_dictionary) + * @param Класс проверяемого объекта + * @param Класс словаря + */ +public record DictionaryPresentRule(String fieldName, + Function getter, + String dictionaryName, + Class dictionaryClass, + boolean required) implements IValidationRule> { + + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param dictionaryName Название словаря (см. IMDGDistributedNames) + * @param dictionaryClass Класс словаря (классы *Dictionary.class) + * @param required Флаг обязательности + * @param Класс проверяемого объекта + * @param Класс словаря + */ + public static DictionaryPresentRule instance(String fieldName, + Function getter, + String dictionaryName, + Class dictionaryClass, + boolean required) { + return new DictionaryPresentRule<>(fieldName, getter, dictionaryName, dictionaryClass, required); + } + + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param dictionaryName Название словаря (см. IMDGDistributedNames) + * @param dictionaryClass Класс словаря (классы *Dictionary.class) + * @param Класс проверяемого объекта + * @param Класс словаря + */ + public static DictionaryPresentRule instance(String fieldName, + Function getter, + String dictionaryName, + Class dictionaryClass) { + return new DictionaryPresentRule<>(fieldName, getter, dictionaryName, dictionaryClass, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + String enumCode = getter.apply(validatedObject); + if (enumCode == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : empty(); + Imdg dictImdg = context.obtainMap( + dictionaryName, + dictionaryClass + ); + ImdgPredicateBuilder imdgPredicateBuilder = dictImdg.predicateBuilder(); + ImdgPredicate imdgPredicate = imdgPredicateBuilder.equals("code", enumCode); + Collection fromMap = dictImdg.getCollectionObjectsByPredicate(imdgPredicate); + if (fromMap.isEmpty()) { + return of(ValidationError.WrongDictionaryValue, fieldName); + } + assert fromMap.size() == 1; + D dictionaryFromMap = fromMap.iterator().next(); + if (dictionaryFromMap == null) { + return of(ValidationError.WrongDictionaryValue, fieldName); + } + return empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java new file mode 100644 index 000000000..a8ab3cd4f --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/EnumPresentRule.java @@ -0,0 +1,60 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Optional; +import java.util.function.Function; + +/** + * Проверка поля со значением из множества (enum) + * @param Класс проверяемого объекта + * @param Enum + */ +public record EnumPresentRule(String fieldName, + Function getter, + E[] enumValues, + boolean required) implements IValidationRule> { + + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param enumValues Значения из проверяемого множества (Enum.values()) + * @param required Флаг обязательности + * @param Класс проверяемого объекта + * @param Enum + */ + public static EnumPresentRule instance(String fieldName, + Function getter, + E[] enumValues, + boolean required) { + return new EnumPresentRule<>(fieldName, getter, enumValues, required); + } + + /** + * @param fieldName Название поля + * @param getter Метод получения проверяемого значения + * @param enumValues Значения из проверяемого множества (Enum.values()) + * @param Класс проверяемого объекта + * @param Enum + */ + public static EnumPresentRule instance(String fieldName, + Function getter, + E[] enumValues) { + return new EnumPresentRule<>(fieldName, getter, enumValues, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + String enumCode = getter.apply(validatedObject); + if (enumCode == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : empty(); + for (E enumValue : enumValues) { + if (enumValue.getKey().equals(enumCode)) return empty(); + } + return of(ValidationError.WrongEnumValue, fieldName); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java new file mode 100644 index 000000000..4abc90b45 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/FieldRequiredRule.java @@ -0,0 +1,35 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Optional; +import java.util.function.Function; + +/** + * Проверка обязательности поля (not null) + * @param Класс проверяемого объекта + * @param Класс проверяемого значения + */ +public record FieldRequiredRule(String fieldName, Function getter) implements IValidationRule> { + + /** + * @param fieldName Название поля + * @param getter Метод получения значения + * @param Класс проверяемого объекта + * @param Класс проверяемого значения + */ + public static FieldRequiredRule instance(String fieldName, Function getter) { + return new FieldRequiredRule<>(fieldName, getter); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + V value = getter.apply(validatedObject); + if (value == null) return of(ValidationError.EmptyRequiredValue, fieldName); + return empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java new file mode 100644 index 000000000..e87377b56 --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/IdPresentRule.java @@ -0,0 +1,77 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.util.Optional; +import java.util.function.Function; + +/** + * Проверка наличия связанного по Id объекта в базе + * @param Класс проверяемого объекта + * @param Класс связанного объекта + */ +public record IdPresentRule( + String fieldName, + Function idGetter, + Function[] additionalChecks, + String mapName, + Class mapClass, + ValidationError idNotPresentError, + boolean required +) implements IValidationRule> { + + /** + * @param fieldName Название поля, содержащего Id + * @param idGetter Метод получения Id + * @param mapName Название мапы связанного объекта (см. IMDGDistributedNames) + * @param mapClass Класс связанного объекта + * @param idNotPresentError Ошибка, которая будет возвращена, если Id не найден + * @param required Флаг обязательности + * @param additionalChecks Дополнительные проверки, которые можно провести со связанным объектом + * @param Класс проверяемого объекта + * @param Класс связанного объекта + */ + @SafeVarargs + public static IdPresentRule instance(String fieldName, + Function idGetter, + String mapName, + Class mapClass, + ValidationError idNotPresentError, + boolean required, + Function ... additionalChecks) { + return new IdPresentRule<>(fieldName, idGetter, additionalChecks, mapName, mapClass, idNotPresentError, required); + } + + @SafeVarargs + public static IdPresentRule instance(String fieldName, + Function idGetter, + String mapName, + Class mapClass, + ValidationError idNotPresentError, + Function ... additionalChecks) { + return new IdPresentRule<>(fieldName, idGetter, additionalChecks, mapName, mapClass, idNotPresentError, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + Long id = idGetter.apply(validatedObject); + if (id == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : empty(); + Imdg imdg = context.obtainMap(mapName, mapClass); + V fromMap = imdg.getSingleObjectByID(id); + if (fromMap == null) { + return of(idNotPresentError, fieldName); + } + for (Function additionalCheck : additionalChecks) { + ValidationError validationError = additionalCheck.apply(fromMap); + if (validationError != null) + return of(validationError, fieldName); + } + return empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java new file mode 100644 index 000000000..90287864e --- /dev/null +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/validation/rules/common/TimeNotBeforeRule.java @@ -0,0 +1,45 @@ +package ru.spcex.clearing.scheduler.validation.rules.common; + +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +import java.time.LocalTime; +import java.util.Optional; +import java.util.function.Function; + +/** + * Проверка поля с LocalTime. Условие проверки: проверяемое время >= текущее время + * @param Класс проверяемого объекта + */ +public record TimeNotBeforeRule(String fieldName, Function getter, boolean required) implements IValidationRule> { + + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемого времени + * @param required Флаг обязательности поля + * @param Класс проверяемого объекта + */ + public static TimeNotBeforeRule instance(String fieldName, Function getter, boolean required) { + return new TimeNotBeforeRule<>(fieldName, getter, required); + } + + /** + * @param fieldName Название поля класса, используется для передачи ошибки + * @param getter Метод получения проверяемого времени + * @param Класс проверяемого объекта + */ + public static TimeNotBeforeRule instance(String fieldName, Function getter) { + return new TimeNotBeforeRule<>(fieldName, getter, true); + } + + @Override + public Optional validate(ImdgValidationContext context) { + R validatedObject = context.getValidatedObject(); + LocalTime date = getter.apply(validatedObject); + if (date == null) return required ? of(ValidationError.EmptyRequiredValue, fieldName) : Optional.empty(); + if (date.isBefore(LocalTime.now())) return of(ValidationError.TaskForPastTime, fieldName); + return Optional.empty(); + } +} diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java index af55150d0..48b9644d4 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/config/HazelcastServiceTestConfiguration.java @@ -10,6 +10,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.enumeration.SimpleMessageResolver; import java.util.List; import java.util.Random; @@ -65,4 +67,9 @@ public class HazelcastServiceTestConfiguration { params.setNearCacheConfig(new NearCacheConfig()); return params; } + + @Bean + public IMessageResolver messageResolver() { + return new SimpleMessageResolver(); + } } diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java index 7307966f9..258f6e1a3 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/ClearingCalendarServiceTest.java @@ -17,25 +17,40 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; 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.profile.Contact; import ru.clearing.classes.statics.data.scheduler.ClearingCalendar; +import ru.clearing.platform.dictionary.DayStatusDictionary; 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.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarUpdateRequest; +import ru.spcex.clearing.scheduler.config.validation.ClearingCalendarValidationConfig; +import ru.spcex.clearing.scheduler.config.validation.ValidationConfig; import ru.spcex.clearing.scheduler.service.ClearingCalendarService; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; import java.time.Instant; import java.time.LocalDate; import java.util.Collections; import java.util.HashMap; +import java.util.function.Function; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { - HazelcastServiceTestConfiguration.class}) + HazelcastServiceTestConfiguration.class, + ValidationConfig.class, + ClearingCalendarValidationConfig.class +}) class ClearingCalendarServiceTest { private static final int PARTITION = 0; @@ -48,6 +63,18 @@ class ClearingCalendarServiceTest { private MockConsumer mockConsumer; private MockProducer mockProducer; + @Autowired + private IMessageResolver messageResolver; + + @Autowired + private Function clearingCalendarDeleteRequestValidation; + + @Autowired + private Function clearingCalendarNewRequestValidation; + + @Autowired + private Function clearingCalendarUpdateRequestValidation; + @BeforeEach void setUp() { mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST); @@ -61,14 +88,28 @@ class ClearingCalendarServiceTest { */ @Test public void newClearingCalendarInQueue() throws InterruptedException { - //ARRANGE + // Prepare test objects + hazelcastServiceTest.waitAvailable(); + Company company = new Company(); + company.setId(0L); + company.setWorkflowStatus(WorkflowStatus.Active.getKey()); + Imdg companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + companyImdg.insert(company); + DayStatus dayStatus = DayStatus.Workday; + DayStatusDictionary dayStatusDictionary = new DayStatusDictionary(); + dayStatusDictionary.setId(0L); + dayStatusDictionary.setCode(dayStatus.getKey()); + Imdg dayStatusDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_DayStatusDictionary, DayStatusDictionary.class); + dayStatusDictionaryImdg.insert(dayStatusDictionary); + + //ARRANGE ClearingCalendar clearingCalendar = new ClearingCalendar(); Instant created = Instant.now(); clearingCalendar.setCreated(created); - clearingCalendar.setClearingDate(LocalDate.now()); + clearingCalendar.setClearingDate(LocalDate.now().plusDays(1)); clearingCalendar.setCompanyId(0L); - clearingCalendar.setDayStatus("STATUS"); + clearingCalendar.setDayStatus(DayStatus.Workday.getKey()); ClearingCalendarNewRequest clearingCalendarNewRequest = new ClearingCalendarNewRequest(); clearingCalendarNewRequest.setClearingDate(clearingCalendar.getClearingDate()); @@ -89,10 +130,23 @@ class ClearingCalendarServiceTest { //ACT //service set up - ClearingCalendarService clearingCalendarService = new ClearingCalendarService(mockConsumer, mockProducer, hazelcastServiceTest); + ClearingCalendarService clearingCalendarService = new ClearingCalendarService(mockConsumer, + mockProducer, + hazelcastServiceTest, + messageResolver, + clearingCalendarDeleteRequestValidation, + clearingCalendarNewRequestValidation, + clearingCalendarUpdateRequestValidation); //callbacks set up clearingCalendarService.afterPropertiesSet(); + + BaseRequest baseRequest = new BaseRequest<>(); + baseRequest.setId(1L); + baseRequest.setActionType(ActionType.NEW); + ClearingCalendarNewRequest newRequest = new ClearingCalendarNewRequest(); + baseRequest.setRequestPayload(newRequest); + IMap iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_ClearingCalendar); //KAFKA HashMap startOffsetsUpdating = new HashMap<>(); diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java index ff5ac8109..7fd0b0d66 100644 --- a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/service/PlannerTemplateServiceTest.java @@ -17,25 +17,44 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; 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.profile.Contact; import ru.clearing.classes.statics.data.scheduler.PlannerTemplate; +import ru.clearing.classes.statics.data.security.Security; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; 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.common.CommonDeleteRequest; import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerTemplateUpdateRequest; +import ru.spcex.clearing.scheduler.config.validation.PlannerTemplateValidationConfig; +import ru.spcex.clearing.scheduler.config.validation.ValidationConfig; import ru.spcex.clearing.scheduler.service.PlannerTemplateService; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.enumeration.WorkflowStatus; +import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.utils.enumeration.IMessageResolver; +import ru.spcex.platform.utils.validation.IValidator; import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; import java.time.Instant; import java.time.LocalTime; +import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.HashMap; +import java.util.function.Function; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { - HazelcastServiceTestConfiguration.class}) + HazelcastServiceTestConfiguration.class, + ValidationConfig.class, + PlannerTemplateValidationConfig.class +}) class PlannerTemplateServiceTest { private static final int PARTITION = 0; @@ -48,6 +67,18 @@ class PlannerTemplateServiceTest { private MockConsumer mockConsumer; private MockProducer mockProducer; + @Autowired + private IMessageResolver messageResolver; + + @Autowired + private Function plannerTemplateDeleteRequestValidation; + + @Autowired + private Function plannerTemplateNewRequestValidation; + + @Autowired + private Function plannerTemplateUpdateRequestValidation; + @BeforeEach void setUp() { mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST); @@ -61,14 +92,42 @@ class PlannerTemplateServiceTest { */ @Test public void newPlannerTemplateInQueue() throws InterruptedException { + Task testTask = Task.accountBlock; + TaskDictionary taskDictionary = new TaskDictionary(); + taskDictionary.setId(0L); + taskDictionary.setCode(testTask.getKey()); + Imdg taskDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_TaskDictionary, TaskDictionary.class); + taskDictionaryImdg.insert(taskDictionary); + + Status testTaskStatus = Status.Active; + TaskStatusDictionary taskStatusDictionary = new TaskStatusDictionary(); + taskStatusDictionary.setId(0L); + taskStatusDictionary.setCode(testTaskStatus.getKey()); + Imdg taskStatusDictionaryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_TaskStatusDictionary, TaskStatusDictionary.class); + taskStatusDictionaryImdg.insert(taskStatusDictionary); + + long testCompanyId = 0L; + Company company = new Company(); + company.setId(testCompanyId); + company.setWorkflowStatus(WorkflowStatus.Active.getKey()); + Imdg companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + companyImdg.insert(company); + + long testSecurityId = 0L; + Security security = new Security(); + security.setId(testSecurityId); + security.setWorkflowStatus(WorkflowStatus.Active.getKey()); + Imdg securityImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Security, Security.class); + securityImdg.insert(security); + //ARRANGE Instant created = Instant.now(); PlannerTemplate plannerTemplate = new PlannerTemplate(); - plannerTemplate.setTask("TASK"); - plannerTemplate.setTaskTime(LocalTime.MIDNIGHT); - plannerTemplate.setTaskStatus("TASK_STATUS"); - plannerTemplate.setCompanyId(0L); - plannerTemplate.setSecurityId(10L); + plannerTemplate.setTask(testTask.getKey()); + plannerTemplate.setTaskTime(LocalTime.now().plusHours(1)); + plannerTemplate.setTaskStatus(testTaskStatus.getKey()); + plannerTemplate.setCompanyId(testCompanyId); + plannerTemplate.setSecurityId(testSecurityId); PlannerTemplateNewRequest plannerTemplateNewRequest = new PlannerTemplateNewRequest(); plannerTemplateNewRequest.setTask(plannerTemplate.getTask()); @@ -91,7 +150,13 @@ class PlannerTemplateServiceTest { //ACT //service set up - PlannerTemplateService plannerTemplateService = new PlannerTemplateService(mockConsumer, mockProducer, hazelcastServiceTest); + PlannerTemplateService plannerTemplateService = new PlannerTemplateService(mockConsumer, + mockProducer, + hazelcastServiceTest, + messageResolver, + plannerTemplateDeleteRequestValidation, + plannerTemplateNewRequestValidation, + plannerTemplateUpdateRequestValidation); //callbacks set up plannerTemplateService.afterPropertiesSet(); @@ -131,7 +196,7 @@ class PlannerTemplateServiceTest { Assertions.assertNotNull(plannerTemplateRes.getCreated()); Assertions.assertEquals(plannerTemplate.getTask(), plannerTemplateRes.getTask()); - Assertions.assertEquals(plannerTemplate.getTaskTime(), plannerTemplateRes.getTaskTime()); + Assertions.assertEquals(plannerTemplate.getTaskTime().truncatedTo(ChronoUnit.SECONDS), plannerTemplateRes.getTaskTime().truncatedTo(ChronoUnit.SECONDS)); Assertions.assertEquals(plannerTemplate.getTaskStatus(), plannerTemplateRes.getTaskStatus()); Assertions.assertEquals(plannerTemplate.getCompanyId(), plannerTemplateRes.getCompanyId()); Assertions.assertEquals(plannerTemplate.getSecurityId(), plannerTemplateRes.getSecurityId()); diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DateNotBeforeRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DateNotBeforeRuleTest.java new file mode 100644 index 000000000..311bf050c --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DateNotBeforeRuleTest.java @@ -0,0 +1,49 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.validation.rules.common.DateNotBeforeRule; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +class DateNotBeforeRuleTest { + + @Test + public void dateNotBeforeRuleTest() { + Function validatorBuilder = plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + return new ValidatorImpl<>(context, + DateNotBeforeRule.instance("clearingDate", PlannerNewRequest::getClearingDate)); + }; + PlannerNewRequest plannerNewRequest = new PlannerNewRequest(); + + plannerNewRequest.setClearingDate(LocalDate.now().plusDays(1)); + IValidator validator = validatorBuilder.apply(plannerNewRequest); + Collection enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setClearingDate(LocalDate.now()); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setClearingDate(LocalDate.now().minusDays(1)); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java new file mode 100644 index 000000000..3cbcf6698 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/DictionaryPresentRuleTest.java @@ -0,0 +1,115 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.clearing.platform.dictionary.DayStatusDictionary; +import ru.clearing.platform.dictionary.TaskDictionary; +import ru.clearing.platform.dictionary.TaskStatusDictionary; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.DictionaryPresentRule; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; +import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + HazelcastServiceTestConfiguration.class}) +class DictionaryPresentRuleTest { + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + @Test + public void dictionaryPresentRuleTest() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + testDictionary(IMDGDistributedNames.Map_TaskDictionary, + TaskDictionary.class, + PlannerNewRequest.class, + "task", + Task.values(), + PlannerNewRequest::getTask, + PlannerNewRequest::setTask); + testDictionary(IMDGDistributedNames.Map_TaskStatusDictionary, + TaskStatusDictionary.class, + PlannerNewRequest.class, + "taskStatus", + Status.values(), + PlannerNewRequest::getTaskStatus, + PlannerNewRequest::setTaskStatus); + testDictionary(IMDGDistributedNames.Map_DayStatusDictionary, + DayStatusDictionary.class, + ClearingCalendarNewRequest.class, + "dayStatus", + DayStatus.values(), + ClearingCalendarNewRequest::getDayStatus, + ClearingCalendarNewRequest::setDayStatus); + + } + + private void testDictionary(String dictionaryKey, + Class dictionaryClass, + Class recordClass, + String fieldName, + E[] enumValues, + Function getter, + BiConsumer setter) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Imdg dictionaryImdg = hazelcastServiceTest.getImdg(dictionaryKey, dictionaryClass); + long idIdx = 0; + for (E enumValue : enumValues) { + D td = dictionaryClass.getConstructor().newInstance(); + td.setId(idIdx++); + td.setCode(enumValue.getKey()); + dictionaryImdg.insert(td); + } + + Function validatorBuilder = request -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(request); + context.addImdg(dictionaryKey, dictionaryImdg); + return new ValidatorImpl<>(context, + DictionaryPresentRule.instance(fieldName, + getter, + dictionaryKey, + dictionaryClass) + ); + }; + R record = recordClass.getConstructor().newInstance(); + IValidator validator = validatorBuilder.apply(record); + + Collection enumMessages; + for (E enumValue : enumValues) { + setter.accept(record, enumValue.getKey()); + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + } + + setter.accept(record, "BAD_VALUE"); + enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(ValidationError.WrongDictionaryValue, enumMessages.iterator().next().getSubject()); + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/EnumPresentRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/EnumPresentRuleTest.java new file mode 100644 index 000000000..8303e0872 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/EnumPresentRuleTest.java @@ -0,0 +1,97 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.ClearingCalendarNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.EnumPresentRule; +import ru.spcex.platform.enumeration.DayStatus; +import ru.spcex.platform.enumeration.Status; +import ru.spcex.platform.enumeration.Task; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumKey; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; +import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + HazelcastServiceTestConfiguration.class}) +class EnumPresentRuleTest { + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + @Test + public void enumPresentRuleTest() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + testEnum( + PlannerNewRequest.class, + "task", + Task.values(), + PlannerNewRequest::getTask, + PlannerNewRequest::setTask); + testEnum( + PlannerNewRequest.class, + "taskStatus", + Status.values(), + PlannerNewRequest::getTaskStatus, + PlannerNewRequest::setTaskStatus); + testEnum( + ClearingCalendarNewRequest.class, + "dayStatus", + DayStatus.values(), + ClearingCalendarNewRequest::getDayStatus, + ClearingCalendarNewRequest::setDayStatus); + + } + + private void testEnum(Class recordClass, + String fieldName, + E[] enumValues, + Function getter, + BiConsumer setter) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + + BiFunction validatorBuilder = (request, required) -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(request); + return new ValidatorImpl<>(context, + EnumPresentRule.instance(fieldName, + getter, + enumValues, + required) + ); + }; + R record = recordClass.getConstructor().newInstance(); + IValidator strictValidator = validatorBuilder.apply(record, true); + + Collection enumMessages; + for (E enumValue : enumValues) { + setter.accept(record, enumValue.getKey()); + enumMessages = strictValidator.validateAll(); + assertTrue(enumMessages.isEmpty()); + } + + setter.accept(record, "BAD_VALUE"); + enumMessages = strictValidator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(ValidationError.WrongEnumValue, enumMessages.iterator().next().getSubject()); + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java new file mode 100644 index 000000000..78cbec5d0 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/FieldRequiredRuleTest.java @@ -0,0 +1,44 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.validation.rules.common.FieldRequiredRule; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.util.Collection; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +class FieldRequiredRuleTest { + + @Test + public void fieldRequiredRuleTest() { + Function validatorBuilder = plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + return new ValidatorImpl<>(context, + new FieldRequiredRule<>("task", PlannerNewRequest::getTask) + ); + }; + PlannerNewRequest plannerNewRequest = new PlannerNewRequest(); + + plannerNewRequest.setTask("test"); + IValidator validator = validatorBuilder.apply(plannerNewRequest); + Collection enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setTask(null); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/IdPresentRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/IdPresentRuleTest.java new file mode 100644 index 000000000..9bc738c22 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/IdPresentRuleTest.java @@ -0,0 +1,105 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.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.security.Security; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.error.ValidationError; +import ru.spcex.clearing.scheduler.validation.rules.common.IdPresentRule; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; +import ru.specx.clearing.scheduler.config.HazelcastServiceTestConfiguration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + HazelcastServiceTestConfiguration.class}) +class IdPresentRuleTest { + private final static Long TEST_ID = 777L; + + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + @Test + public void idPresentRuleTest() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + testIdPresentRule( + "companyId", + PlannerNewRequest::getCompanyId, + PlannerNewRequest::setCompanyId, + IMDGDistributedNames.Map_Company, + Company.class, + PlannerNewRequest.class, + ValidationError.CompanyNotFound, + ValidationError.CompanyNotActive + ); + testIdPresentRule( + "securityId", + PlannerNewRequest::getSecurityId, + PlannerNewRequest::setSecurityId, + IMDGDistributedNames.Map_Security, + Security.class, + PlannerNewRequest.class, + ValidationError.SecurityNotFound, + ValidationError.SecurityNotActive + ); + } + + private void testIdPresentRule(String fieldName, + Function getter, + BiConsumer setter, + String mapName, + Class mapClass, + Class objClass, + ValidationError notFoundExpectedError, + ValidationError notActiveExpectedError) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Imdg imdg = hazelcastServiceTest.getImdg(mapName, mapClass); + Function validatorBuilder = request -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(request); + context.addImdg(mapName, imdg); + return new ValidatorImpl<>(context, IdPresentRule.instance(fieldName, + getter, + mapName, + mapClass, + notFoundExpectedError, + true, + company -> company.getId().equals(TEST_ID) ? null : notActiveExpectedError + )); + }; + + R obj = objClass.getConstructor().newInstance(); + setter.accept(obj, TEST_ID); + IValidator validator = validatorBuilder.apply(obj); + Collection enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + assertEquals(notFoundExpectedError, enumMessages.iterator().next().getSubject()); + + D map = mapClass.getConstructor().newInstance(); + map.setId(TEST_ID); + imdg.insert(map); + + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + } + +} \ No newline at end of file diff --git a/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/TimeNotBeforeRuleTest.java b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/TimeNotBeforeRuleTest.java new file mode 100644 index 000000000..32206cda7 --- /dev/null +++ b/clearing-parent/scheduler-service/src/test/java/ru/specx/clearing/scheduler/validation/TimeNotBeforeRuleTest.java @@ -0,0 +1,49 @@ +package ru.specx.clearing.scheduler.validation; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.PlannerNewRequest; +import ru.spcex.clearing.scheduler.validation.rules.common.TimeNotBeforeRule; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidator; +import ru.spcex.platform.utils.validation.ValidatorImpl; + +import java.time.LocalTime; +import java.util.Collection; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(SpringExtension.class) +class TimeNotBeforeRuleTest { + + @Test + public void timeNotBeforeRuleTest() { + Function validatorBuilder = plannerNewRequest -> { + ImdgValidationContext context = new ImdgValidationContext<>(); + context.setValidatedObject(plannerNewRequest); + return new ValidatorImpl<>(context, + TimeNotBeforeRule.instance("taskTime", PlannerNewRequest::getTaskTime)); + }; + PlannerNewRequest plannerNewRequest = new PlannerNewRequest(); + + plannerNewRequest.setTaskTime(LocalTime.now().plusMinutes(1)); + IValidator validator = validatorBuilder.apply(plannerNewRequest); + Collection enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setTaskTime(LocalTime.now().plusSeconds(1)); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertTrue(enumMessages.isEmpty()); + + plannerNewRequest.setTaskTime(LocalTime.now().minusMinutes(1)); + validator = validatorBuilder.apply(plannerNewRequest); + enumMessages = validator.validateAll(); + assertEquals(1, enumMessages.size()); + } + +} \ No newline at end of file diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/DayStatus.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/DayStatus.java new file mode 100644 index 000000000..2028f093c --- /dev/null +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/DayStatus.java @@ -0,0 +1,18 @@ +package ru.spcex.platform.enumeration; + +import ru.spcex.platform.utils.enumeration.IEnumKey; + +public enum DayStatus implements IEnumKey { + Workday("BDAY"), DayOff("DOFF"); + + private final String key; + + DayStatus(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/Parent.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/Parent.java new file mode 100644 index 000000000..523bba0bf --- /dev/null +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/Parent.java @@ -0,0 +1,18 @@ +package ru.spcex.platform.enumeration; + +import ru.spcex.platform.utils.enumeration.IEnumKey; + +public enum Parent implements IEnumKey { + Template("TMPL"), Planner("PLNR"), Calendar("CLND"); + + private final String key; + + Parent(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/WorkflowStatus.java b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/WorkflowStatus.java new file mode 100644 index 000000000..0e1ccdd49 --- /dev/null +++ b/platform-parent/platform-enum/src/main/java/ru/spcex/platform/enumeration/WorkflowStatus.java @@ -0,0 +1,19 @@ +package ru.spcex.platform.enumeration; + +import ru.spcex.platform.utils.enumeration.IEnumKey; + +public enum WorkflowStatus implements IEnumKey { + Active("ACTV"), + Blocked("BLKD"); + + private final String key; + + WorkflowStatus(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java index 2730b70a5..8fffd91e8 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/QueueConsumer.java @@ -16,16 +16,21 @@ import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.logic.functional.BuilderConsumerStep; import ru.spcex.clearing.platform.messaging.logic.functional.ConsumerSpecificClass; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.log.ExceptionUtils; +import ru.spcex.platform.utils.validation.IValidator; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; /** * утилитный класс для обработки сообщений из очереди @@ -155,6 +160,31 @@ public class QueueConsumer implements AutoCloseable { return ConsumerSpecificClass.build(clazz); } + + /** + * Валидация запроса + * @param Класс проверяемого запроса + * @return null если ошибок нет + */ + public RequestInfoUpdate validate(BaseRequest userRequest, + Function validatorBuilder, + IMessageResolver messageResolver) { + if (validatorBuilder != null) { + R req = userRequest.getRequestPayload(); + IValidator validator = validatorBuilder.apply(req); + Optional validationError = validator.tillFirstError(); + if (validationError.isPresent()) { + String errorMsg = messageResolver.resolve(validationError.get()); + log.error("validation error for {} error={}, id={}: {}", req.getClass().getSimpleName(), validationError.get().getSubject(), userRequest.getId(), errorMsg); + return new RequestInfoUpdate() + .setId(userRequest.getId()) + .setStatus(Status.Error) + .setMessage(errorMsg); + } + } + return null; + } + @Override public void close() { log.debug("Closing queue consumer {}", getClass().getSimpleName()); diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/RequestInfoUpdate.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/RequestInfoUpdate.java index 24e8a1562..fd0610311 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/RequestInfoUpdate.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/service/RequestInfoUpdate.java @@ -39,4 +39,13 @@ public class RequestInfoUpdate { this.message = message; return this; } + + @Override + public String toString() { + return "RequestInfoUpdate{" + + "id=" + id + + ", status=" + status + + ", message='" + message + '\'' + + '}'; + } }