Beispiel #1
0
        public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
        {
            if (!step.Collections.Has(collection))
            {
                if (step.Collections.Count == 1)
                {
                    var clone = step.Collections.Single().CloneAs(collection);
                    step.Collections[collection] = clone;
                }
            }

            var section = findSection(step);

            if (section == null)
            {
                stepValidator.AddError("Missing step collection");
                return;
            }

            stepValidator.Start(section, null);

            var i = 0;

            foreach (var child in section.Children.OfType <Step>())
            {
                i++;
                stepValidator.Start(i, child);

                child.ProcessCells(cells, stepValidator);

                stepValidator.End(child);
            }

            stepValidator.End(section);
        }
        public SwapStepsCommandValidator(
            IJourneyValidator journeyValidator,
            IStepValidator stepValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, token) => BeAnExistingStepAsync(command.JourneyId, command.StepAId, token))
            .WithMessage(_ => "Journey and/or step doesn't exist!")
            .MustAsync((command, token) => BeAnExistingStepAsync(command.JourneyId, command.StepBId, token))
            .WithMessage(_ => "Journey and/or step doesn't exist!")
            .MustAsync((command, token) => BeAdjacentStepsInAJourneyAsync(command.JourneyId, command.StepAId, command.StepBId, token))
            .WithMessage(command => $"Steps are not adjacent! Steps={command.StepAId} and {command.StepBId}")
            .Must(command => HaveAValidRowVersion(command.StepARowVersion))
            .WithMessage(command => $"Not a valid row version! Row version{command.StepARowVersion}")
            .Must(command => HaveAValidRowVersion(command.StepBRowVersion))
            .WithMessage(command => $"Not a valid row version! Row version={command.StepBRowVersion}");

            async Task <bool> BeAnExistingStepAsync(int journeyId, int stepId, CancellationToken token)
            => await journeyValidator.ExistsStepAsync(journeyId, stepId, token);

            async Task <bool> BeAdjacentStepsInAJourneyAsync(int journeyId, int stepAId, int stepBId, CancellationToken token)
            => await journeyValidator.AreAdjacentStepsInAJourneyAsync(journeyId, stepAId, stepBId, token);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
Beispiel #3
0
        public DeleteStepCommandValidator(
            IJourneyValidator journeyValidator,
            IStepValidator stepValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, token) => BeAnExistingStepAsync(command.JourneyId, command.StepId, token))
            .WithMessage(command => "Journey and/or step doesn't exist!")
            .MustAsync((command, token) => BeAVoidedStepAsync(command.StepId, token))
            .WithMessage(command => $"Step is not voided! Step={command.StepId}")
            .MustAsync((command, token) => JourneyForStepNotBeUsedAsync(command.JourneyId, token))
            .WithMessage(command => $"No steps can be deleted from journey when preservation tags exists in journey! Journey={command.JourneyId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command => $"Not a valid row version! Row version={command.RowVersion}");

            async Task <bool> BeAnExistingStepAsync(int journeyId, int stepId, CancellationToken token)
            => await journeyValidator.ExistsStepAsync(journeyId, stepId, token);

            async Task <bool> BeAVoidedStepAsync(int stepId, CancellationToken token)
            => await stepValidator.IsVoidedAsync(stepId, token);

            async Task <bool> JourneyForStepNotBeUsedAsync(int journeyId, CancellationToken token)
            => !await journeyValidator.IsAnyStepInJourneyInUseAsync(journeyId, token);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
Beispiel #4
0
 public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
 {
     foreach (var childGrammar in children)
     {
         childGrammar.PostProcessAndValidate(stepValidator, step);
     }
 }
        public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
        {
            if (errors.Any())
            {
                stepValidator.AddError("Grammar has errors");
            }

            step.ProcessCells(cells, stepValidator);
        }
Beispiel #6
0
        public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
        {
            var section = step.Collections[collection];

            stepValidator.Start(section, fixture);

            stepValidator.ValidateStepsWithinSection(section, fixture);

            stepValidator.End(section);
        }
        public UpdateStepCommandValidator(
            IJourneyValidator journeyValidator,
            IStepValidator stepValidator,
            IModeValidator modeValidator,
            IResponsibleValidator responsibleValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, token) => BeAnExistingStepAsync(command.JourneyId, command.StepId, token))
            .WithMessage(_ => "Journey and/or step doesn't exist!")
            .MustAsync((command, token) => HaveUniqueStepTitleInJourneyAsync(command.JourneyId, command.StepId, command.Title, token))
            .WithMessage(command => $"Another step with title already exists in a journey! Step={command.Title}")
            .MustAsync((command, token) => NotBeAVoidedStepAsync(command.StepId, token))
            .WithMessage(command => $"Step is voided! Step={command.StepId}")
            .MustAsync((command, token) => BeAnExistingModeAsync(command.ModeId, token))
            .WithMessage(command => $"Mode doesn't exist! Mode={command.ModeId}")
            .MustAsync((command, token) => NotChangedToAVoidedModeAsync(command.ModeId, command.StepId, token))
            .WithMessage(command => $"Mode is voided! Mode={command.ModeId}")
            .MustAsync((command, token) => NotBeAnExistingAndVoidedResponsibleAsync(command.ResponsibleCode, token))
            .WithMessage(command => $"Responsible is voided! ResponsibleCode={command.ResponsibleCode}")
            .MustAsync((command, token) => NotHaveOtherStepsWithSameAutoTransferMethodInJourneyAsync(command.JourneyId, command.StepId, command.AutoTransferMethod, token))
            .WithMessage(command => $"Same auto transfer method can not be set on multiple steps in a journey! Method={command.AutoTransferMethod}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command => $"Not a valid row version! Row version={command.RowVersion}");

            async Task <bool> BeAnExistingStepAsync(int journeyId, int stepId, CancellationToken token)
            => await journeyValidator.ExistsStepAsync(journeyId, stepId, token);

            async Task <bool> HaveUniqueStepTitleInJourneyAsync(int journeyId, int stepId, string stepTitle, CancellationToken token) =>
            !await journeyValidator.OtherStepExistsWithSameTitleAsync(journeyId, stepId, stepTitle, token);

            async Task <bool> NotBeAVoidedStepAsync(int stepId, CancellationToken token)
            => !await stepValidator.IsVoidedAsync(stepId, token);

            async Task <bool> BeAnExistingModeAsync(int modeId, CancellationToken token)
            => await modeValidator.ExistsAsync(modeId, token);

            async Task <bool> NotChangedToAVoidedModeAsync(int modeId, int stepId, CancellationToken token)
            => await stepValidator.HasModeAsync(modeId, stepId, token) ||
            !await modeValidator.IsVoidedAsync(modeId, token);

            async Task <bool> NotBeAnExistingAndVoidedResponsibleAsync(string responsibleCode, CancellationToken token)
            => !await responsibleValidator.ExistsAndIsVoidedAsync(responsibleCode, token);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);

            async Task <bool> NotHaveOtherStepsWithSameAutoTransferMethodInJourneyAsync(int journeyId, int stepId, AutoTransferMethod autoTransferMethod, CancellationToken token)
            => autoTransferMethod == AutoTransferMethod.None || !await journeyValidator.HasOtherStepWithAutoTransferMethodAsync(journeyId, stepId, autoTransferMethod, token);
        }
Beispiel #8
0
        public AutoScopeTagsCommandValidator(
            ITagValidator tagValidator,
            IStepValidator stepValidator,
            IProjectValidator projectValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command.TagNos)
            .Must(r => r.Any())
            .WithMessage("At least 1 tag must be given!")
            .Must(BeUniqueTagNos)
            .WithMessage("Tags must be unique!");

            RuleForEach(command => command.TagNos)
            .MustAsync((command, tagNo, _, token) => NotBeAnExistingTagWithinProjectAsync(tagNo, command.ProjectName, token))
            .WithMessage((command, tagNo) => $"Tag already exists in scope for project! Tag={tagNo}");

            RuleFor(command => command)
            .MustAsync((command, token) => NotBeAnExistingAndClosedProjectAsync(command.ProjectName, token))
            .WithMessage(command => $"Project is closed! Project={command.ProjectName}")
            .MustAsync((command, token) => BeAnExistingStepAsync(command.StepId, token))
            .WithMessage(command => $"Step doesn't exist! Step={command.StepId}")
            .MustAsync((command, token) => NotBeAVoidedStepAsync(command.StepId, token))
            .WithMessage(command => $"Step is voided! Step={command.StepId}");

            bool BeUniqueTagNos(IEnumerable <string> tagNos)
            {
                var lowerTagNos = tagNos.Select(t => t.ToLower()).ToList();

                return(lowerTagNos.Distinct().Count() == lowerTagNos.Count);
            }

            async Task <bool> NotBeAnExistingTagWithinProjectAsync(string tagNo, string projectName, CancellationToken token) =>
            !await tagValidator.ExistsAsync(tagNo, projectName, token);

            async Task <bool> NotBeAnExistingAndClosedProjectAsync(string projectName, CancellationToken token)
            => !await projectValidator.IsExistingAndClosedAsync(projectName, token);

            async Task <bool> BeAnExistingStepAsync(int stepId, CancellationToken token)
            => await stepValidator.ExistsAsync(stepId, token);

            async Task <bool> NotBeAVoidedStepAsync(int stepId, CancellationToken token)
            => !await stepValidator.IsVoidedAsync(stepId, token);
        }
        public UnvoidStepCommandValidator(
            IJourneyValidator journeyValidator,
            IStepValidator stepValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, token) => BeAnExistingStepAsync(command.JourneyId, command.StepId, token))
            .WithMessage(command => "Journey and/or step doesn't exist!")
            .MustAsync((command, token) => BeAVoidedStepAsync(command.StepId, token))
            .WithMessage(command => $"Step is not voided! Step={command.StepId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command => $"Not a valid row version! Row version={command.RowVersion}");

            async Task <bool> BeAnExistingStepAsync(int journeyId, int stepId, CancellationToken token)
            => await journeyValidator.ExistsStepAsync(journeyId, stepId, token);
            async Task <bool> BeAVoidedStepAsync(int stepId, CancellationToken token)
            => await stepValidator.IsVoidedAsync(stepId, token);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
Beispiel #10
0
        public void ProcessCells(Cell[] cells, IStepValidator stepValidator)
        {
            if (cells == null || cells.Length == 0)
            {
                return;
            }

            if (StagedValues != null)
            {
                for (int i = 0; i < StagedValues.Length; i++)
                {
                    if (cells.Length <= i)
                    {
                        break;
                    }

                    Values[cells[i].Key] = StagedValues[i];
                }
            }

            foreach (var cell in cells)
            {
                if (Values.ContainsKey(cell.Key))
                {
                    continue;
                }

                if (cell.DefaultValue.IsNotEmpty())
                {
                    Values[cell.Key] = cell.DefaultValue;
                }
                else
                {
                    stepValidator.AddError($"Missing value for '{cell.Key}'");
                }
            }
        }
Beispiel #11
0
        public void ProcessCells(Cell[] cells, IStepValidator stepValidator)
        {
            if (cells == null || cells.Length == 0) return;

            if (StagedValues != null)
            {
                for (int i = 0; i < StagedValues.Length; i++)
                {
                    if (cells.Length <= i) break;

                    Values[cells[i].Key] = StagedValues[i];
                }
            }

            foreach (var cell in cells)
            {
                if (Values.ContainsKey(cell.Key)) continue;

                if (cell.DefaultValue.IsNotEmpty())
                {
                    Values[cell.Key] = cell.DefaultValue;
                }
                else
                {
                    stepValidator.AddError($"Missing value for '{cell.Key}'");
                }
            }
        }
Beispiel #12
0
 public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
 {
     foreach (var childGrammar in children)
     {
         childGrammar.PostProcessAndValidate(stepValidator, step);
     }
 }
Beispiel #13
0
 public virtual void PostProcessAndValidate(IStepValidator stepValidator, Step step)
 {
     // Nothing
 }
 public virtual void PostProcessAndValidate(IStepValidator stepValidator, Step step)
 {
     // Nothing
 }
Beispiel #15
0
        public CreateAreaTagCommandValidator(
            ITagValidator tagValidator,
            IStepValidator stepValidator,
            IProjectValidator projectValidator,
            IRequirementDefinitionValidator requirementDefinitionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            WhenAsync((command, token) => BeASupplierStepAsync(command.StepId, token), () =>
            {
                RuleFor(command => command)
                .MustAsync((command, token) => RequirementUsageIsForAllJourneysAsync(command.Requirements, token))
                .WithMessage(_ => "Requirements must include requirements to be used both for supplier and other than suppliers!")
                .When(command => command.TagType != TagType.PoArea, ApplyConditionTo.CurrentValidator)
                .MustAsync((command, token) => RequirementUsageIsForSupplierAsync(command.Requirements, token))
                .WithMessage(_ => "Requirements must include requirements to be used for supplier!")
                .When(command => command.TagType == TagType.PoArea, ApplyConditionTo.CurrentValidator)
                .MustAsync((command, token) => RequirementUsageIsNotForOtherThanSupplierAsync(command.Requirements, token))
                .WithMessage(_ => "Requirements can not include requirements for other than suppliers!")
                .When(command => command.TagType == TagType.PoArea, ApplyConditionTo.CurrentValidator);
            }).Otherwise(() =>
            {
                RuleFor(command => command)
                .Must(command => command.TagType != TagType.PoArea)
                .WithMessage(_ => $"Step for a {TagType.PoArea.GetTagNoPrefix()} tag needs to be for supplier!")
                .MustAsync((command, token) => RequirementUsageIsForJourneysWithoutSupplierAsync(command.Requirements, token))
                .WithMessage(_ => "Requirements must include requirements to be used for other than suppliers!")
                .MustAsync((command, token) => RequirementUsageIsNotForSupplierOnlyAsync(command.Requirements, token))
                .WithMessage(_ => "Requirements can not include requirements just for suppliers!");
            });

            RuleFor(command => command)
            .Must(command => BeUniqueRequirements(command.Requirements))
            .WithMessage(_ => "Requirement definitions must be unique!")
            .MustAsync((command, token) => NotBeAnExistingAndClosedProjectAsync(command.ProjectName, token))
            .WithMessage(command => $"Project is closed! Project={command.ProjectName}")
            .MustAsync((command, token) => NotBeAnExistingTagWithinProjectAsync(command.GetTagNo(), command.ProjectName, token))
            .WithMessage(command => $"Tag already exists in scope for project! Tag={command.GetTagNo()}")
            .MustAsync((command, token) => BeAnExistingStepAsync(command.StepId, token))
            .WithMessage(command => $"Step doesn't exist! Step={command.StepId}")
            .MustAsync((command, token) => NotBeAVoidedStepAsync(command.StepId, token))
            .WithMessage(command => $"Step is voided! Step={command.StepId}");

            RuleForEach(command => command.Requirements)
            .MustAsync((_, req, _, token) => BeAnExistingRequirementDefinitionAsync(req, token))
            .WithMessage((_, req) => $"Requirement definition doesn't exist! Requirement definition={req.RequirementDefinitionId}")
            .MustAsync((_, req, _, token) => NotBeAVoidedRequirementDefinitionAsync(req, token))
            .WithMessage((_, req) => $"Requirement definition is voided! Requirement definition={req.RequirementDefinitionId}");

            bool BeUniqueRequirements(IEnumerable <RequirementForCommand> requirements)
            {
                var reqIds = requirements.Select(dto => dto.RequirementDefinitionId).ToList();

                return(reqIds.Distinct().Count() == reqIds.Count);
            }

            async Task <bool> RequirementUsageIsForAllJourneysAsync(IEnumerable <RequirementForCommand> requirements, CancellationToken token)
            {
                var reqIds = requirements.Select(dto => dto.RequirementDefinitionId).ToList();

                return(await requirementDefinitionValidator.UsageCoversBothForSupplierAndOtherAsync(reqIds, token));
            }

            async Task <bool> RequirementUsageIsForSupplierAsync(IEnumerable <RequirementForCommand> requirements, CancellationToken token)
            {
                var reqIds = requirements.Select(dto => dto.RequirementDefinitionId).ToList();

                return(await requirementDefinitionValidator.UsageCoversForSuppliersAsync(reqIds, token));
            }

            async Task <bool> RequirementUsageIsForJourneysWithoutSupplierAsync(IEnumerable <RequirementForCommand> requirements, CancellationToken token)
            {
                var reqIds = requirements.Select(dto => dto.RequirementDefinitionId).ToList();

                return(await requirementDefinitionValidator.UsageCoversForOtherThanSuppliersAsync(reqIds, token));
            }

            async Task <bool> RequirementUsageIsNotForOtherThanSupplierAsync(IEnumerable <RequirementForCommand> requirements, CancellationToken token)
            {
                var reqIds = requirements.Select(dto => dto.RequirementDefinitionId).ToList();

                return(!await requirementDefinitionValidator.HasAnyForForOtherThanSuppliersUsageAsync(reqIds, token));
            }

            async Task <bool> RequirementUsageIsNotForSupplierOnlyAsync(IEnumerable <RequirementForCommand> requirements, CancellationToken token)
            {
                var reqIds = requirements.Select(dto => dto.RequirementDefinitionId).ToList();

                return(!await requirementDefinitionValidator.HasAnyForSupplierOnlyUsageAsync(reqIds, token));
            }

            async Task <bool> NotBeAnExistingAndClosedProjectAsync(string projectName, CancellationToken token)
            => !await projectValidator.IsExistingAndClosedAsync(projectName, token);

            async Task <bool> NotBeAnExistingTagWithinProjectAsync(string tagNo, string projectName, CancellationToken token)
            => !await tagValidator.ExistsAsync(tagNo, projectName, token);

            async Task <bool> BeAnExistingStepAsync(int stepId, CancellationToken token)
            => await stepValidator.ExistsAsync(stepId, token);

            async Task <bool> NotBeAVoidedStepAsync(int stepId, CancellationToken token)
            => !await stepValidator.IsVoidedAsync(stepId, token);

            async Task <bool> BeASupplierStepAsync(int stepId, CancellationToken token)
            => await stepValidator.IsForSupplierAsync(stepId, token);

            async Task <bool> BeAnExistingRequirementDefinitionAsync(RequirementForCommand requirement, CancellationToken token)
            => await requirementDefinitionValidator.ExistsAsync(requirement.RequirementDefinitionId, token);

            async Task <bool> NotBeAVoidedRequirementDefinitionAsync(RequirementForCommand requirement, CancellationToken token)
            => !await requirementDefinitionValidator.IsVoidedAsync(requirement.RequirementDefinitionId, token);
        }
Beispiel #16
0
        public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
        {
            if (errors.Any())
            {
                stepValidator.AddError("Grammar has errors");
            }

            step.ProcessCells(cells, stepValidator);
        }
        public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
        {
            var section = step.Collections[collection];

            stepValidator.Start(section, fixture);

            stepValidator.ValidateStepsWithinSection(section, fixture);

            stepValidator.End(section);
        }
Beispiel #18
0
        public override void PostProcessAndValidate(IStepValidator stepValidator, Step step)
        {
            if (!step.Collections.Has(collection))
            {
                if (step.Collections.Count == 1)
                {
                    var clone = step.Collections.Single().CloneAs(collection);
                    step.Collections[collection] = clone;
                }
            }

            var section = findSection(step);
            if (section == null)
            {
                stepValidator.AddError("Missing step collection");
                return;
            }

            stepValidator.Start(section, null);

            var i = 0;
            foreach (var child in section.Children.OfType<Step>())
            {
                i++;
                stepValidator.Start(i, child);

                child.ProcessCells(cells, stepValidator);

                stepValidator.End(child);
            }

            stepValidator.End(section);
        }
        public UpdateTagStepAndRequirementsCommandValidator(
            IProjectValidator projectValidator,
            ITagValidator tagValidator,
            IStepValidator stepValidator,
            IRequirementDefinitionValidator requirementDefinitionValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            WhenAsync((command, token) => IsASupplierStepAsync(command.StepId, token), () =>
            {
                WhenAsync((command, token) => NotBeAPoAreaTagAsync(command.TagId, token), () =>
                {
                    RuleFor(command => command)
                    .MustAsync((_, command, token) =>
                               RequirementUsageIsForAllJourneysAsync(
                                   command.TagId,
                                   command.UpdatedRequirements.Where(u => !u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                                   command.UpdatedRequirements.Where(u => u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                                   command.NewRequirements.Select(r => r.RequirementDefinitionId).ToList(),
                                   token))
                    .WithMessage(_ => "Requirements must include requirements to be used both for supplier and other than suppliers!");
                }).Otherwise(() =>
                {
                    RuleFor(command => command)
                    .MustAsync((_, command, token) =>
                               RequirementUsageIsForSupplierAsync(
                                   command.TagId,
                                   command.UpdatedRequirements.Where(u => !u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                                   command.UpdatedRequirements.Where(u => u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                                   command.NewRequirements.Select(r => r.RequirementDefinitionId).ToList(),
                                   token))
                    .WithMessage(_ => "Requirements must include requirements to be used for supplier!")
                    .MustAsync((command, token) => RequirementUsageIsNotForOtherThanSupplierAsync(
                                   command.TagId,
                                   command.UpdatedRequirements.Where(u => !u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                                   command.UpdatedRequirements.Where(u => u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                                   command.NewRequirements.Select(r => r.RequirementDefinitionId).ToList(),
                                   token))
                    .WithMessage(_ => "Requirements can not include requirements for other than suppliers!");
                });
            }).Otherwise(() =>
            {
                RuleFor(command => command)
                .MustAsync((command, token) => NotBeAPoAreaTagAsync(command.TagId, token))
                .WithMessage(_ => $"Step for a {TagType.PoArea.GetTagNoPrefix()} tag needs to be for supplier!")
                .MustAsync((_, command, token) =>
                           RequirementUsageIsForJourneysWithoutSupplierAsync(
                               command.TagId,
                               command.UpdatedRequirements.Where(u => !u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                               command.UpdatedRequirements.Where(u => u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                               command.NewRequirements.Select(r => r.RequirementDefinitionId).ToList(),
                               token))
                .WithMessage(_ => "Requirements must include requirements to be used for other than suppliers!");
            });

            WhenAsync((command, token) => IsAnAreaTagAsync(command.TagId, token), () =>
            {
                RuleFor(command => command)
                .Must(command => !string.IsNullOrEmpty(command.Description))
                .WithMessage(_ => "Description can not be blank!");
            }).Otherwise(() =>
            {
                RuleFor(command => command)
                .MustAsync((command, token)
                           => NotChangeDescriptionAsync(command.TagId, command.Description, token))
                .WithMessage(_ => "Tag must be an area tag to update description!");
            });

            RuleFor(command => command)
            .MustAsync((_, command, token) =>
                       RequirementsMustBeUniqueAfterUpdateAsync(
                           command.TagId,
                           command.NewRequirements.Select(r => r.RequirementDefinitionId).ToList(),
                           token))
            .WithMessage(_ => "Requirements must be unique!")
            .MustAsync((command, token) => NotBeAClosedProjectForTagAsync(command.TagId, token))
            .WithMessage(command => $"Project for tag is closed! Tag={command.TagId}")
            .MustAsync((command, token) => BeAnExistingTagAsync(command.TagId, token))
            .WithMessage(command => $"Tag doesn't exist! Tag={command.TagId}")
            .MustAsync((command, token) => NotBeAVoidedTagAsync(command.TagId, token))
            .WithMessage(command => $"Tag is voided! Tag={command.TagId}")
            .MustAsync((command, token) => NotChangedToAVoidedStepAsync(command.TagId, command.StepId, token))
            .WithMessage(command => $"Step is voided! Step={command.StepId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command => $"Not a valid row version! Row version={command.RowVersion}");

            RuleForEach(command => command.UpdatedRequirements)
            .MustAsync((command, req, _, token) => BeAnExistingTagRequirementAsync(command.TagId, req.TagRequirementId, token))
            .WithMessage((_, req) => $"Requirement doesn't exist! Requirement={req.TagRequirementId}");

            RuleForEach(command => command.DeletedRequirements)
            .MustAsync((command, req, _, token) => BeAnExistingTagRequirementAsync(command.TagId, req.TagRequirementId, token))
            .WithMessage((_, req) => $"Requirement doesn't exist! Requirement={req.TagRequirementId}")
            .MustAsync((command, req, _, token) => BeAVoidedTagRequirementAsync(
                           command.TagId,
                           req.TagRequirementId,
                           command.UpdatedRequirements.Where(u => u.IsVoided).Select(u => u.TagRequirementId).ToList(),
                           token))
            .WithMessage((_, req) => $"Requirement is not voided! Requirement={req.TagRequirementId}");

            RuleForEach(command => command.NewRequirements)
            .MustAsync((_, req, _, token) => BeAnExistingRequirementDefinitionAsync(req.RequirementDefinitionId, token))
            .WithMessage((_, req) =>
                         $"Requirement definition doesn't exist! Requirement definition={req.RequirementDefinitionId}")
            .MustAsync((_, req, _, token) => NotBeAVoidedRequirementDefinitionAsync(req.RequirementDefinitionId, token))
            .WithMessage((_, req) =>
                         $"Requirement definition is voided! Requirement definition={req.RequirementDefinitionId}");

            async Task <bool> RequirementsMustBeUniqueAfterUpdateAsync(
                int tagId,
                List <int> requirementDefinitionIdsToBeAdded,
                CancellationToken token)
            => requirementDefinitionIdsToBeAdded.Count == 0 ||
            await tagValidator.AllRequirementsWillBeUniqueAsync(tagId, requirementDefinitionIdsToBeAdded, token);

            async Task <bool> RequirementUsageIsNotForOtherThanSupplierAsync(
                int tagId,
                List <int> tagRequirementIdsToBeUnvoided,
                List <int> tagRequirementIdsToBeVoided,
                List <int> requirementDefinitionIdsToBeAdded,
                CancellationToken token)
            => !await tagValidator.RequirementHasAnyForOtherThanSuppliersUsageAsync(
                tagId,
                tagRequirementIdsToBeUnvoided,
                tagRequirementIdsToBeVoided,
                requirementDefinitionIdsToBeAdded,
                token);

            async Task <bool> RequirementUsageIsForSupplierAsync(
                int tagId,
                List <int> tagRequirementIdsToBeUnvoided,
                List <int> tagRequirementIdsToBeVoided,
                List <int> requirementDefinitionIdsToBeAdded,
                CancellationToken token)
            => await tagValidator.RequirementUsageWillCoverForSuppliersAsync(
                tagId,
                tagRequirementIdsToBeUnvoided,
                tagRequirementIdsToBeVoided,
                requirementDefinitionIdsToBeAdded,
                token);

            async Task <bool> RequirementUsageIsForAllJourneysAsync(
                int tagId,
                List <int> tagRequirementIdsToBeUnvoided,
                List <int> tagRequirementIdsToBeVoided,
                List <int> requirementDefinitionIdsToBeAdded,
                CancellationToken token)
            => await tagValidator.RequirementUsageWillCoverBothForSupplierAndOtherAsync(
                tagId,
                tagRequirementIdsToBeUnvoided,
                tagRequirementIdsToBeVoided,
                requirementDefinitionIdsToBeAdded,
                token);

            async Task <bool> RequirementUsageIsForJourneysWithoutSupplierAsync(
                int tagId,
                List <int> tagRequirementIdsToBeUnvoided,
                List <int> tagRequirementIdsToBeVoided,
                List <int> requirementDefinitionIdsToBeAdded,
                CancellationToken token)
            => await tagValidator.RequirementUsageWillCoverForOtherThanSuppliersAsync(
                tagId,
                tagRequirementIdsToBeUnvoided,
                tagRequirementIdsToBeVoided,
                requirementDefinitionIdsToBeAdded,
                token);

            async Task <bool> IsASupplierStepAsync(int stepId, CancellationToken token)
            => await stepValidator.IsForSupplierAsync(stepId, token);

            async Task <bool> NotBeAClosedProjectForTagAsync(int tagId, CancellationToken token)
            => !await projectValidator.IsClosedForTagAsync(tagId, token);

            async Task <bool> IsAnAreaTagAsync(int tagId, CancellationToken token)
            => await tagValidator.VerifyTagIsAreaTagAsync(tagId, token);

            async Task <bool> BeAnExistingTagAsync(int tagId, CancellationToken token)
            => await tagValidator.ExistsAsync(tagId, token);

            async Task <bool> NotBeAVoidedTagAsync(int tagId, CancellationToken token)
            => !await tagValidator.IsVoidedAsync(tagId, token);

            async Task <bool> NotBeAPoAreaTagAsync(int tagId, CancellationToken token)
            => !await tagValidator.VerifyTagTypeAsync(tagId, TagType.PoArea, token);

            async Task <bool> NotChangedToAVoidedStepAsync(int tagId, int stepId, CancellationToken token)
            => await tagValidator.HasStepAsync(tagId, stepId, token) ||
            !await stepValidator.IsVoidedAsync(stepId, token);

            async Task <bool> BeAnExistingRequirementDefinitionAsync(int requirementDefinitionId, CancellationToken token)
            => await requirementDefinitionValidator.ExistsAsync(requirementDefinitionId, token);

            async Task <bool> NotBeAVoidedRequirementDefinitionAsync(int requirementDefinitionId, CancellationToken token)
            => !await requirementDefinitionValidator.IsVoidedAsync(requirementDefinitionId, token);

            async Task <bool> BeAnExistingTagRequirementAsync(int tagId, int tagRequirementId, CancellationToken token)
            => await tagValidator.HasRequirementAsync(tagId, tagRequirementId, token);

            async Task <bool> BeAVoidedTagRequirementAsync(
                int tagId,
                int tagRequirementId,
                List <int> tagRequirementIdsToBeVoided,
                CancellationToken token)
            {
                if (tagRequirementIdsToBeVoided.Contains(tagRequirementId))
                {
                    return(true);
                }

                return(await tagValidator.IsRequirementVoidedAsync(tagId, tagRequirementId, token));
            }

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);

            async Task <bool> NotChangeDescriptionAsync(int tagId, string description, CancellationToken token)
            => description == null || await tagValidator.VerifyTagDescriptionAsync(tagId, description, token);
        }