Added a completion rule for assignees, so that a use can choose based on the task when the assignments are completed enough to finish the task.

This commit is contained in:
Colin Dawson 2026-03-16 14:23:36 +00:00
parent 2d29c6de1c
commit 1a064848ea
10 changed files with 45 additions and 14 deletions

View File

@ -191,7 +191,7 @@ public class WorkflowProcessor : IWorkflowProcessor
.GetInterfaces() .GetInterfaces()
.FirstOrDefault(i => .FirstOrDefault(i =>
i.IsGenericType && i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof(IAssignees<>)); i.GetGenericTypeDefinition() == typeof(IAssignees<,>));
if (typedInterface == null) if (typedInterface == null)
throw new InvalidOperationException("Task does not implement IAssignees<T>."); throw new InvalidOperationException("Task does not implement IAssignees<T>.");

View File

@ -5,7 +5,6 @@ namespace e_suite.Workflow.Core.Enums;
[Description("Verdict")] [Description("Verdict")]
public enum ApprovalVerdict public enum ApprovalVerdict
{ {
None,
Approved, Approved,
Rejected Rejected
} }

View File

@ -0,0 +1,13 @@
namespace e_suite.Workflow.Core.Enums;
public enum RuleOperator
{
All,
Any,
CountAtLeast,
CountExactly,
FilterByRaci,
FilterByOutcome,
And,
Or
}

View File

@ -0,0 +1,14 @@
using e_suite.Workflow.Core.Enums;
using eSuite.Core.Workflow;
namespace e_suite.Workflow.Core.Interfaces;
public class CompletionRule<TOutcome>
{
public RuleOperator Operator { get; set; }
public List<CompletionRule<TOutcome>>? Children { get; set; }
public Raci? RaciFilter { get; set; }
public TOutcome RequiredOutcome { get; set; } = default!;
public int? Threshold { get; set; }
}

View File

@ -1,4 +1,5 @@
using e_suite.Workflow.Core.Attributes; using e_suite.Workflow.Core.Attributes;
using e_suite.Workflow.Core.Enums;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace e_suite.Workflow.Core.Interfaces; namespace e_suite.Workflow.Core.Interfaces;
@ -9,9 +10,10 @@ public interface IAssignees
} }
[TaskCapability] [TaskCapability]
public interface IAssignees<T> : IAssignees where T : ITaskAssignee public interface IAssignees<TTaskAssignee, TOutcome> : IAssignees, IOutcome<TOutcome> where TTaskAssignee : ITaskAssignee
{ {
[Required] [Required]
List<T> Assignees { get; set; } List<TTaskAssignee> Assignees { get; set; }
CompletionRule<TOutcome> AssigneesCompletionRule { get; set; }
} }

View File

@ -5,9 +5,10 @@ using e_suite.Workflow.Core.Interfaces;
namespace e_suite.Workflow.Core.Tasks; namespace e_suite.Workflow.Core.Tasks;
[GeneralTask(taskIcon: "faEyeSlash")] [GeneralTask(taskIcon: "faEyeSlash")]
public class AdhocApprovalTask : TaskBase, IAssignees<ApprovalTaskAssignee>, IOutcome<ApprovalVerdict> public class AdhocApprovalTask : TaskBase, IAssignees<ApprovalTaskAssignee, ApprovalVerdict>
{ {
public List<ApprovalTaskAssignee> Assignees { get; set; } = []; public List<ApprovalTaskAssignee> Assignees { get; set; } = [];
public CompletionRule<ApprovalVerdict> AssigneesCompletionRule { get; set; }
public ApprovalVerdict TaskOutcome { get; set; } public ApprovalVerdict TaskOutcome { get; set; }
public List<OutcomeAction<ApprovalVerdict>> OutcomeActions { get; set; } = []; public List<OutcomeAction<ApprovalVerdict>> OutcomeActions { get; set; }
} }

View File

@ -5,10 +5,10 @@ using e_suite.Workflow.Core.Interfaces;
namespace e_suite.Workflow.Core.Tasks; namespace e_suite.Workflow.Core.Tasks;
[ApprovalTask] [ApprovalTask]
public class ApprovalStep : TaskBase, IAssignees<ApprovalTaskAssignee>, IOutcome<DefaultOutcome> public class ApprovalStep : TaskBase, IAssignees<ApprovalTaskAssignee, ApprovalVerdict>
{ {
public List<ApprovalTaskAssignee> Assignees { get; set; } = []; public List<ApprovalTaskAssignee> Assignees { get; set; } = [];
public CompletionRule<ApprovalVerdict> AssigneesCompletionRule { get; set; }
public List<OutcomeAction<ApprovalVerdict>> OutcomeActions { get; set; }
public List<OutcomeAction<DefaultOutcome>> OutcomeActions { get; set; } = [];
} }

View File

@ -1,5 +1,4 @@
using System.ComponentModel; using e_suite.Workflow.Core.Attributes;
using e_suite.Workflow.Core.Attributes;
using e_suite.Workflow.Core.Enums; using e_suite.Workflow.Core.Enums;
using e_suite.Workflow.Core.Interfaces; using e_suite.Workflow.Core.Interfaces;
@ -9,9 +8,10 @@ namespace e_suite.Workflow.Core.Tasks;
/// A user has to open this task, manually set it to ready to complete /// A user has to open this task, manually set it to ready to complete
/// </summary> /// </summary>
[GeneralTask(taskIcon: "faSquareCheck")] [GeneralTask(taskIcon: "faSquareCheck")]
public class BasicTask : TaskBase, IAssignees<TaskAssignee>, IOutcome<DefaultOutcome> public class BasicTask : TaskBase, IAssignees<TaskAssignee, DefaultOutcome>
{ {
public List<TaskAssignee> Assignees { get; set; } = []; public List<TaskAssignee> Assignees { get; set; } = [];
public CompletionRule<DefaultOutcome> AssigneesCompletionRule { get; set; }
public List<OutcomeAction<DefaultOutcome>> OutcomeActions { get; set; } = []; public List<OutcomeAction<DefaultOutcome>> OutcomeActions { get; set; } = [];
} }

View File

@ -8,9 +8,10 @@ namespace e_suite.Workflow.Core.Tasks;
/// Create a table of field data for output to PDF or AdobeIllustrator /// Create a table of field data for output to PDF or AdobeIllustrator
/// </summary> /// </summary>
[GeneralTask] [GeneralTask]
public class ContentCollationTask : TaskBase, IAssignees<TaskAssignee>, IOutcome<DefaultOutcome> public class ContentCollationTask : TaskBase, IAssignees<TaskAssignee, DefaultOutcome>
{ {
public List<TaskAssignee> Assignees { get; set; } = []; public List<TaskAssignee> Assignees { get; set; } = [];
public CompletionRule<DefaultOutcome> AssigneesCompletionRule { get; set; }
public List<OutcomeAction<DefaultOutcome>> OutcomeActions { get; set; } = []; public List<OutcomeAction<DefaultOutcome>> OutcomeActions { get; set; } = [];
} }

View File

@ -6,9 +6,10 @@ using eSuite.Core.Miscellaneous;
namespace e_suite.Workflow.Core.Tasks; namespace e_suite.Workflow.Core.Tasks;
[GeneralTask(taskIcon: "faFileLines")] [GeneralTask(taskIcon: "faFileLines")]
public class FormDataInputTask : TaskBase, IAssignees<TaskAssignee>, IFormTemplate, IOutcome<DefaultOutcome> public class FormDataInputTask : TaskBase, IAssignees<TaskAssignee, DefaultOutcome>, IFormTemplate
{ {
public List<TaskAssignee> Assignees { get; set; } = []; public List<TaskAssignee> Assignees { get; set; } = [];
public CompletionRule<DefaultOutcome> AssigneesCompletionRule { get; set; }
public bool IsMultiple { get; set; } public bool IsMultiple { get; set; }
public required IGeneralIdRef FormIdRef { get; set; } public required IGeneralIdRef FormIdRef { get; set; }