diff --git a/e-suite.Core/eSuite.Core/Miscellaneous/GeneralIdRef.cs b/e-suite.Core/eSuite.Core/Miscellaneous/GeneralIdRef.cs index a45876e..72601f4 100644 --- a/e-suite.Core/eSuite.Core/Miscellaneous/GeneralIdRef.cs +++ b/e-suite.Core/eSuite.Core/Miscellaneous/GeneralIdRef.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System.Text; +using System.Text.Json.Serialization; namespace eSuite.Core.Miscellaneous; @@ -39,5 +40,30 @@ public class GeneralIdRef : IGeneralIdRef, IEquatable public override int GetHashCode() { return HashCode.Combine(Id, Guid); + + } + + public override string ToString() + { + var needsComma = false; + var output = new StringBuilder(); + + output.Append("GeneralIdRef("); + if (Id != null) + { + output.Append("Id:"); + output.Append(Id); + needsComma = true; + } + + if (Guid != null) + { + if (needsComma) + output.Append(", "); + output.Append("Guid:"); + output.Append(Guid); + } + output.Append(")"); + return output.ToString(); } } \ No newline at end of file diff --git a/e-suite.Service.WorkflowProcessor/WorkflowProcessor.cs b/e-suite.Service.WorkflowProcessor/WorkflowProcessor.cs index 1d5de3f..f0733d5 100644 --- a/e-suite.Service.WorkflowProcessor/WorkflowProcessor.cs +++ b/e-suite.Service.WorkflowProcessor/WorkflowProcessor.cs @@ -4,6 +4,7 @@ using e_suite.Database.Core.Tables.Activity; using e_suite.Messaging.Common; using e_suite.Workflow.Core; using e_suite.Workflow.Core.Extensions; +using e_suite.Workflow.Core.Interfaces; using eSuite.Core.Clock; using eSuite.Core.Enums; using eSuite.Core.Miscellaneous; @@ -74,9 +75,15 @@ public class WorkflowProcessor : IWorkflowProcessor break; } case ActivityState.Active: - throw new NotImplementedException("don't know how to progress a running instance."); - case ActivityState.ReadyToComplete: - throw new NotImplementedException("don't know how to progress a ReadyToComplete instance."); + hasCompletableTask = await ProgressRunningActivity(auditUserDetails, cancellationToken, activityInstance, + workflowVersion); + + if (activityInstance.Tasks.All(x => x.ActivityState == ActivityState.Completed)) + { + activityInstance.ActivityState = ActivityState.Completed; + await _activityRepository.UpdateActivityInstanceAsync(auditUserDetails, activityInstance, cancellationToken); + } + break; } }); @@ -86,6 +93,23 @@ public class WorkflowProcessor : IWorkflowProcessor } } + private async Task ProgressRunningActivity(AuditUserDetails auditUserDetails, CancellationToken cancellationToken, Activity activityInstance, WorkflowVersion workflowVersion) + { + bool hasCompletableTask = false; + foreach (var task in activityInstance.Tasks) + { + var taskDefinition = workflowVersion.FindTask(task.TaskGuid)!; + if (await taskDefinition.ProgressTask(task, activityInstance.Tasks, workflowVersion, _clock)) + { + hasCompletableTask = true; + } + } + + await _activityRepository.UpdateActivityTasksAsync(auditUserDetails, activityInstance.Tasks, cancellationToken); + + return hasCompletableTask; + } + private async Task StartActivity( AuditUserDetails auditUserDetails, CancellationToken cancellationToken, diff --git a/e-suite.Workflow.Core/Extensions/TaskExtensions.cs b/e-suite.Workflow.Core/Extensions/TaskExtensions.cs index c000d7f..225757f 100644 --- a/e-suite.Workflow.Core/Extensions/TaskExtensions.cs +++ b/e-suite.Workflow.Core/Extensions/TaskExtensions.cs @@ -125,7 +125,7 @@ public static class TaskExtensions }; } - public IEnumerable GetTargetGuids() + private (Type outcomeType, IDictionary dict)? GetOutcomeDictionary() { var outcomeInterface = task.GetType() .GetInterfaces() @@ -133,12 +133,53 @@ public static class TaskExtensions i.GetGenericTypeDefinition() == typeof(IOutcome<>)); if (outcomeInterface == null) + return null; + + var outcomeType = outcomeInterface.GetGenericArguments()[0]; + var prop = outcomeInterface.GetProperty("OutcomeActions"); + var dict = (IDictionary)prop!.GetValue(task)!; + + return (outcomeType, dict); + } + + public IEnumerable GetTargetGuids() + { + var info = task.GetOutcomeDictionary(); + if (info == null) return Enumerable.Empty(); - var prop = outcomeInterface.GetProperty("OutcomeActions"); - var dict = (IDictionary)prop.GetValue(task); + return info.Value.dict.Values.Cast(); + } - return dict!.Values.Cast(); + public IEnumerable GetTargetGuids(IEnumerable outcomes) + { + var info = task.GetOutcomeDictionary(); + if (info == null) + return Enumerable.Empty(); + + var (outcomeType, dict) = info.Value; + var results = new List(); + + foreach (var outcomeString in outcomes) + { + object? typedKey; + + if (outcomeType.IsEnum) + { + typedKey = Enum.Parse(outcomeType, outcomeString); + } + else + { + typedKey = Convert.ChangeType(outcomeString, outcomeType); + } + + if (dict.Contains(typedKey)) + { + results.Add((Guid)dict[typedKey]!); + } + } + + return results; } public async Task StartTask(ActivityTask activityTask, IClock clock) @@ -149,6 +190,35 @@ public static class TaskExtensions await task.OnStartedAsync(activityTask); } + public async Task ProgressTask(ActivityTask activityTask, ICollection tasks, IStage stage, IClock clock) + { + var hasCompletableTask = false; + if (activityTask.ActivityState == ActivityState.ReadyToComplete) + { + activityTask.FinishDateTime = clock.GetNow; + activityTask.SetState(ActivityState.Completed); + + await task.OnCompleteAsync(activityTask); + + var targetGuids = task.GetTargetGuids(activityTask.Outcomes).ToList(); + + foreach (var t in tasks) + { + if (targetGuids.Contains(t.TaskGuid)) + { + var taskDefinition = stage.FindTask(t.TaskGuid)!; + await taskDefinition.StartTask(t, clock); + if (t.ActivityState == ActivityState.ReadyToComplete) + { + hasCompletableTask = true; + } + } + } + } + + return hasCompletableTask; + } + }