public UnCompletePunchOutCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnInvitationInCompletedStage(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is not in completed stage, and thus cannot be uncompleted!")
            .Must(command => HaveAValidRowVersion(command.InvitationRowVersion))
            .WithMessage(command =>
                         $"Invitation row version is not valid! InvitationRowVersion={command.InvitationRowVersion}")
            .Must(command => HaveAValidRowVersion(command.ParticipantRowVersion))
            .WithMessage(command =>
                         $"Participant row version is not valid! ParticipantRowVersion={command.ParticipantRowVersion}")
            .MustAsync((command, cancellationToken) => BeACompleterOnIpo(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "The IPO does not have a contractor assigned to uncomplete the IPO!")
            .MustAsync((command, cancellationToken) => BeAdminOrThePersonWhoCompleted(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Person trying to uncomplete is not an admin and not the person who completed the IPO!");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeAnInvitationInCompletedStage(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Completed, cancellationToken);

            async Task <bool> BeACompleterOnIpo(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoHasCompleterAsync(invitationId, cancellationToken);

            async Task <bool> BeAdminOrThePersonWhoCompleted(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsAdminOrValidCompletorParticipantAsync(invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
コード例 #2
0
        public SignPunchOutCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnExistingParticipant(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Participant with ID does not exist on invitation! Id={command.ParticipantId}")
            .MustAsync((command, cancellationToken) => BeANonCanceledInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is canceled, and thus cannot be signed!")
            .Must(command => HaveAValidRowVersion(command.ParticipantRowVersion))
            .WithMessage(command =>
                         $"Participant row version is not valid! ParticipantRowVersion={command.ParticipantRowVersion}")
            .MustAsync((command, cancellationToken) => BeASigningParticipantOnIpo(command.InvitationId, command.ParticipantId, cancellationToken))
            .WithMessage(command =>
                         $"Participant is not assigned to sign this IPO! ParticipantId={command.ParticipantId}")
            .MustAsync((command, cancellationToken) => BeTheAssignedPersonIfPersonParticipant(command.InvitationId, command.ParticipantId, cancellationToken))
            .WithMessage(command =>
                         "Person signing is not assigned to sign IPO, or there is not a valid functional role on the IPO!")
            .MustAsync((command, cancellationToken) => BeUnsignedParticipant(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Participant is already signed!");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeANonCanceledInvitation(int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Canceled, cancellationToken);

            async Task <bool> BeASigningParticipantOnIpo(int invitationId, int participantId, CancellationToken cancellationToken)
            => await invitationValidator.SignerExistsAsync(invitationId, participantId, cancellationToken);

            async Task <bool> BeTheAssignedPersonIfPersonParticipant(int invitationId, int participantId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsValidSigningParticipantAsync(invitationId, participantId, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            async Task <bool> BeUnsignedParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.ParticipantIsSignedAsync(participantId, invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
コード例 #3
0
        public UpdateAttendedStatusOnParticipantCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) =>
                       BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) =>
                       NotBeCancelledInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Cannot perform updates on cancelled invitation! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) =>
                       BeAnExistingParticipant(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Participant with ID does not exist on invitation! ParticipantId={command.ParticipantId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command =>
                         $"Participant doesn't have valid rowVersion! ParticipantRowVersion={command.RowVersion}")
            .MustAsync((command, cancellationToken) =>
                       HavePermissionToEdit(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage("The current user does not have sufficient privileges to edit this participant.")
            .MustAsync((command, cancellationToken) =>
                       HaveOppositeAttendedStatusIfTouched(command.ParticipantId, command.InvitationId, command.Attended, cancellationToken))
            .WithMessage("Cannot update participant to its current attendedStatus.");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> NotBeCancelledInvitation(int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Canceled, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            async Task <bool> HavePermissionToEdit(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.HasPermissionToEditParticipantAsync(participantId, invitationId, cancellationToken);

            async Task <bool> HaveOppositeAttendedStatusIfTouched(int participantId, int invitationId, bool attended, CancellationToken cancellationToken)
            => await invitationValidator.HasOppositeAttendedStatusIfTouchedAsync(participantId, invitationId, attended, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        public AcceptPunchOutCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnInvitationInCompletedStage(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is not in completed stage, and thus cannot be accepted!")
            .Must(command => HaveAValidRowVersion(command.InvitationRowVersion))
            .WithMessage(command =>
                         $"Invitation row version is not valid! InvitationRowVersion={command.InvitationRowVersion}")
            .Must(command => HaveAValidRowVersion(command.ParticipantRowVersion))
            .WithMessage(command =>
                         $"Participant row version is not valid! ParticipantRowVersion={command.ParticipantRowVersion}")
            .MustAsync((command, cancellationToken) => BeAnAccepterOnIpo(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "The IPO does not have a construction company assigned to accept the IPO!")
            .MustAsync((command, cancellationToken) => BeTheAssignedPersonIfPersonParticipant(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Person signing is not the construction company assigned to accept this IPO, or there is not a valid construction company on the IPO!");

            RuleForEach(command => command.Participants)
            .MustAsync((command, participant, _, cancellationToken) => BeAnExistingParticipant(participant.Id, command.InvitationId, cancellationToken))
            .WithMessage((command, participant) =>
                         $"Participant with ID does not exist on invitation! Participant={participant.Id}")
            .Must((command, participant) => HaveAValidRowVersion(participant.RowVersion))
            .WithMessage((command, participant) =>
                         $"Participant doesn't have valid rowVersion! Participant={participant.Id}");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeAnInvitationInCompletedStage(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Completed, cancellationToken);

            async Task <bool> BeAnAccepterOnIpo(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoHasAccepterAsync(invitationId, cancellationToken);

            async Task <bool> BeTheAssignedPersonIfPersonParticipant(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsValidAccepterParticipantAsync(invitationId, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        public UpdateAttendedStatusAndNotesOnParticipantsCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnInvitationInCompletedStage(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is not in completed stage, and thus cannot change attended statuses or notes!")
            .MustAsync((command, cancellationToken) => BeAContractorOnIpo(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "The IPO does not have a contractor assigned to the IPO!")
            .MustAsync((command, cancellationToken) => BeTheAssignedContractorIfPersonParticipant(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "User is not the contractor assigned to complete this IPO, or there is not a valid contractor on the IPO!");

            RuleForEach(command => command.Participants)
            .MustAsync((command, participant, _, cancellationToken) => BeAnExistingParticipant(participant.Id, command.InvitationId, cancellationToken))
            .WithMessage((command, participant) =>
                         $"Participant with ID does not exist on invitation! ParticipantId={participant.Id}")
            .Must((command, participant) => HaveAValidRowVersion(participant.RowVersion))
            .WithMessage((command, participant) =>
                         $"Participant doesn't have valid rowVersion! ParticipantRowVersion={participant.RowVersion}");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeAnInvitationInCompletedStage(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Completed, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            async Task <bool> BeTheAssignedContractorIfPersonParticipant(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsValidCompleterParticipantAsync(invitationId, cancellationToken);

            async Task <bool> BeAContractorOnIpo(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoHasCompleterAsync(invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        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);
        }