using e_suite.API.Common.repository; using e_suite.Database.Audit; using e_suite.Database.Core.Tables.Activity; using e_suite.Workflow.Core; using e_suite.Workflow.Core.Interfaces; using eSuite.Core.Clock; using eSuite.Core.Enums; using eSuite.Core.Miscellaneous; using Microsoft.Extensions.Logging; namespace e_suite.Service.WorkflowProcessor; public class WorkflowProcessor : IWorkflowProcessor { private readonly ILogger _logger; private readonly IClock _clock; private readonly IWorkflowTemplateRepository _workflowTemplateRepository; private readonly IWorkflowConverter _workflowConverter; private readonly IActivityRepository _activityRepository; public WorkflowProcessor(ILogger logger, IClock clock, IWorkflowTemplateRepository workflowTemplateRepository, IActivityRepository activityRepository, IWorkflowConverter workflowConverter) { _logger = logger; _clock = clock; _workflowTemplateRepository = workflowTemplateRepository; _activityRepository = activityRepository; _workflowConverter = workflowConverter; } public async Task ProgressActivity( AuditUserDetails auditUserDetails, GeneralIdRef activityId, CancellationToken cancellationToken ) { _logger.LogInformation("{DateTime}: Progressing Activity {messageId}", _clock.GetNow, activityId); var activityInstance = await _activityRepository.GetActivityInstanceAsync(activityId, cancellationToken); if (activityInstance == null) { _logger.LogInformation("{DateTime}: Unable to find activity {messageId}", _clock.GetNow, activityId); throw new InvalidDataException("activityInstance not found"); } if (activityInstance.ActivityState == ActivityState.Cancelled) { _logger.LogInformation("{DateTime}: Activity {messageId} is cancelled, skipping", _clock.GetNow, activityId); return; } if (activityInstance.ActivityState == ActivityState.Completed) { _logger.LogInformation("{DateTime}: Activity {messageId} is already completed, skipping", _clock.GetNow, activityId); return; } var workflowVersion = _workflowConverter.DeserialiseFromDatabase(activityInstance.WorkflowVersion); await _activityRepository.TransactionAsync(async () => { ICollection tasks; if (activityInstance.ActivityState == ActivityState.Pending) { activityInstance.ActivityState = ActivityState.Active; await _activityRepository.UpdateActivityInstanceAsync(auditUserDetails, activityInstance, cancellationToken); tasks = await PlanTaskExecution(auditUserDetails, activityInstance, workflowVersion, cancellationToken); } else { tasks = activityInstance.Tasks; } //Invoke startable tasks. }); } private async Task> PlanTaskExecution(AuditUserDetails auditUserDetails, Activity activityInstance, WorkflowVersion workflowVersion, CancellationToken cancellationToken) { var activityOrdinalCounter = 1; //Create task instances for the activity var activityTasks = new List(); foreach (var task in workflowVersion.Tasks) { var activityTask = new ActivityTask { Guid = Guid.NewGuid(), Activity = activityInstance, ActivityState = ActivityState.Pending, TaskGuid = task.Guid, ActivityOrdinal = activityOrdinalCounter++, TaskName = task.Name, }; activityTasks.Add(activityTask); } await _activityRepository.AddActivityTasksAsync(auditUserDetails, activityTasks, cancellationToken); return activityTasks; } }