public async Task ProductProcessChangedAsync(ProductProcessChangedArgs args)
        {
            // Clear PreExecute entries
            var emptyItems = ProductTransitionRepository.Get()
                             .Where(pt => pt.WorkflowUserId == null && pt.ProductId == args.ProcessId)
                             .Select(pt => pt.Id).ToList();

            foreach (var item in emptyItems)
            {
                await ProductTransitionRepository.DeleteAsync(item);
            }
            // Create PreExecute entries
            await Runtime.PreExecuteFromCurrentActivityAsync(args.ProcessId);

            // Find the Product assoicated with the ProcessId
            var product = await ProductRepository.Get().Where(p => p.Id == args.ProcessId).FirstOrDefaultAsync();

            if (product == null)
            {
                Log.Error($"Could find Product for ProcessId={args.ProcessId}");
                return;
            }

            await RemoveTasksByProductId(product.Id);

            // Find all users who could perform the current activity and create tasks for them
            var workflowUserIds = Runtime.GetAllActorsForDirectCommandTransitions(args.ProcessId, activityName: args.CurrentActivityName).ToList();
            var users           = UserRepository.Get().Where(u => workflowUserIds.Contains(u.WorkflowUserId.GetValueOrDefault().ToString())).ToList();
            var workflowComment = product.WorkflowComment;

            foreach (var user in users)
            {
                var task = new UserTask
                {
                    UserId       = user.Id,
                    ProductId    = product.Id,
                    ActivityName = args.CurrentActivityName,
                    Status       = args.CurrentState,
                    Comment      = workflowComment
                };
                task = await TaskRepository.CreateAsync(task);

                // TODO: SendNotification to User
                Log.Information($"Notification: user={user.Name}, command={args.ExecutingCommand}, fromActivity:{args.PreviousActivityName}, toActivity:{args.CurrentState}, comment:{product.WorkflowComment}");
            }

            // Clear the WorkflowComment
            if (!String.IsNullOrWhiteSpace(workflowComment))
            {
                // Clear the comment
                product.WorkflowComment = "";
                await ProductRepository.UpdateAsync(product);
            }
        }
        public async Task <string> ReassignUserTasksForProduct(Product product)
        {
            var instance = await ProductWorkflowRepository.GetAsync(product.Id);

            if (instance == null)
            {
                // No current running workflow for product.
                return(null);
            }

            await ClearPreExecuteEntries(product.Id);

            var comment = GetCurrentTaskComment(product);

            await RemoveTasksByProductId(product.Id);

            // Find all users who could perform the current activity and create tasks for them
            var workflowUserIds = Runtime
                                  .GetAllActorsForDirectCommandTransitions(product.Id, activityName: instance.ActivityName)
                                  .ToList();

            var workflowUserIdsForInverse = Runtime
                                            .GetAllActorsForReverseCommandTransitions(product.Id, activityName: instance.ActivityName)
                                            .ToList();

            var users = UserRepository.Get()
                        .Where(u => workflowUserIds.Contains(u.WorkflowUserId.GetValueOrDefault().ToString()) || workflowUserIdsForInverse.Contains(u.WorkflowUserId.GetValueOrDefault().ToString()))
                        .ToList();

            foreach (var user in users)
            {
                var userTask = new UserTask
                {
                    UserId       = user.Id,
                    ProductId    = product.Id,
                    ActivityName = instance.ActivityName,
                    Status       = instance.StateName,
                    Comment      = comment
                };

                await TaskRepository.CreateAsync(userTask);

                await SendNotificationForTask(userTask, user, product);
            }

            await CreatePreExecuteEntries(product.Id);

            return(comment);
        }
        public async System.Threading.Tasks.Task TaskRepository__CreateTask__WithObtainedComponents()
        {
            var options = GetDbContextOptions();

            // Arrange

            await using var context = GetDdContext(options);
            await InitDbContext(context);

            // Act
            var repository = new TaskRepository(context);
            await repository.CreateAsync(new Task { Id = 2, Description = "name", DeviceId = 1,
                                                    ObtainedDesigns = new ObtainedDesign[1]
                                                    {
                                                        new ObtainedDesign()
                                                        {
                                                            ComponentId = 1, TaskId = 2, Obtained = 10
                                                        }
                                                    },
                                                    ObtainedMontages = new ObtainedMontage[1]
                                                    {
                                                        new ObtainedMontage()
                                                        {
                                                            ComponentId = 1, TaskId = 2
                                                        }
                                                    } });

            await repository.SaveAsync();

            // Assert
            Assert.IsNotEmpty(context.Tasks);
            var task = await context.Tasks.FindAsync(2);

            Assert.NotNull(task);
            Assert.AreEqual(2, task.Id);
            Assert.AreEqual("name", task.Description);
            Assert.AreEqual(1, task.ObtainedMontages.Count());
            Assert.AreEqual(10, task.ObtainedDesigns.First().Obtained);
        }
        public async System.Threading.Tasks.Task TaskRepository__CreateTask__WithoutObtainedComponents()
        {
            var options = GetDbContextOptions();

            // Arrange

            await using var context = GetDdContext(options);
            // Act
            var repository = new TaskRepository(context);
            await repository.CreateAsync(new Task { Id = 1, Description = "name" });

            await repository.SaveAsync();

            // Assert
            Assert.IsNotEmpty(context.Tasks);
            var task = await context.Tasks.FirstOrDefaultAsync();

            Assert.NotNull(task);
            Assert.AreEqual(1, task.Id);
            Assert.AreEqual("name", task.Description);
            Assert.AreEqual(null, task.OrderId);
        }
        private async Task ReceiveTasks(CancellationToken token)
        {
            using var dbContext = CreateDbContext();
            var taskRepo = new TaskRepository(dbContext);

            try
            {
                var receivedTasks = new List <SampleTask>(100);
                dbContext.Database.BeginTransaction();
                await _consumer.Consume <CreateSampleTaskDto>(async (taskDto) =>
                {
                    var task = new SampleTask
                    {
                        Description = taskDto.Description
                    };
                    var savedTask = await taskRepo.CreateAsync(task, token);
                    receivedTasks.Add(savedTask);
                });

                dbContext.Database.CommitTransaction();
                if (receivedTasks.Count > 0)
                {
                    Console.WriteLine("----------------");
                    Console.WriteLine("Из очереди прочитаны и сохранены задачи:");
                    receivedTasks.ForEach(t =>
                    {
                        Console.WriteLine($"TaskID: {t.TaskId}, " +
                                          $"Description: {t.Description}, " +
                                          $"CreateDate: {t.CreateTime.ToLocalTime()}");
                    });
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                dbContext.Database.RollbackTransaction();
            }
        }
        public async Task ProductProcessChangedAsync(ProductProcessChangedArgs args)
        {
            // Clear PreExecute entries
            var emptyItems = ProductTransitionRepository.Get()
                             .Where(pt => pt.WorkflowUserId == null && pt.ProductId == args.ProcessId)
                             .Select(pt => pt.Id).ToList();

            foreach (var item in emptyItems)
            {
                await ProductTransitionRepository.DeleteAsync(item);
            }
            // Create PreExecute entries
            await Runtime.PreExecuteFromCurrentActivityAsync(args.ProcessId);

            // Find the Product assoicated with the ProcessId
            var product = await ProductRepository.Get()
                          .Where(p => p.Id == args.ProcessId)
                          .Include(p => p.ProductDefinition)
                          .Include(p => p.Project)
                          .ThenInclude(pr => pr.Owner)
                          .FirstOrDefaultAsync();

            if (product == null)
            {
                Log.Error($"Could find Product for ProcessId={args.ProcessId}");
                return;
            }

            await RemoveTasksByProductId(product.Id);

            // Find all users who could perform the current activity and create tasks for them
            var workflowUserIds = Runtime.GetAllActorsForDirectCommandTransitions(args.ProcessId, activityName: args.CurrentActivityName).ToList();
            var users           = UserRepository.Get().Where(u => workflowUserIds.Contains(u.WorkflowUserId.GetValueOrDefault().ToString())).ToList();
            var workflowComment = product.WorkflowComment;

            foreach (var user in users)
            {
                var task = new UserTask
                {
                    UserId       = user.Id,
                    ProductId    = product.Id,
                    ActivityName = args.CurrentActivityName,
                    Status       = args.CurrentState,
                    Comment      = workflowComment
                };
                task = await TaskRepository.CreateAsync(task);

                var messageParms = new Dictionary <string, object>()
                {
                    { "activityName", task.ActivityName },
                    { "project", product.Project.Name },
                    { "productName", product.ProductDefinition.Name },
                    { "fromActivity", args.PreviousActivityName ?? "" },
                    { "status", task.Status },
                    { "originator", user.Name },
                    { "to", product.Project.Owner.Name },
                    { "comment", task.Comment ?? "" }
                };
                await SendNotificationService.SendNotificationToUserAsync(user,
                                                                          "userTaskAdded",
                                                                          messageParms);

                Log.Information($"Notification: user={user.Name}, command={args.ExecutingCommand}, fromActivity:{args.PreviousActivityName}, toActivity:{args.CurrentState}, comment:{product.WorkflowComment}");
            }

            // Clear the WorkflowComment
            if (!String.IsNullOrWhiteSpace(workflowComment))
            {
                // Clear the comment
                product.WorkflowComment = "";
                await ProductRepository.UpdateAsync(product);
            }
        }