using System; using System.Collections.Generic; using System.Linq; using Centron.BusinessLogic; using Centron.BusinessLogic.EmployeeArea; using Centron.BusinessLogic.Mail.Factory; using Centron.BusinessLogic.Sales.Support; using Centron.BusinessLogic.WebServices.Administration.Settings.SettingGroups; using Centron.BusinessLogic.WebServices.Sales.Support; using Centron.BusinessLogic.WebServices.TaskManager; using Centron.Data.Entities.Administration.Logins; using Centron.Data.Entities.Sales.Support; using Centron.Data.Entities.TaskManager; using Centron.Data.WebServices.Administration.Employees; using Centron.Data.WebServices.Sales.CustomerAssets.Contracts; using Centron.Data.WebServices.Sales.Customers; using Centron.Data.WebServices.Sales.Support; using Centron.Data.WebServices.TaskManager; using Centron.Data.WebServices.TaskManager.Actions; using Centron.Data.WebServices.TaskManager.Recurrence; using Centron.Interfaces; using Centron.Interfaces.BL; using Centron.Tests.EndToEnd.Infrastructure; using Xunit; using Xunit.Abstractions; namespace Centron.Tests.EndToEnd.Tests.TaskHelpdeskAction { /// /// Reproduction for Ticket #167558 (Raphael Frasch GmbH) — "Taskmanagement geht bringt Fehler". /// /// A helpdesk task whose action has /// = true drives the second-save / ForwardHelpdesk path /// (TaskManagementHelpdeskActionHandler.Execute -> HelpdeskWebServiceBL.ForwardHelpdesk -> /// HelpdeskForwardBL.ForwardHelpdesk, which re-saves the just-created helpdesk). /// /// Before the fix the customer saw: /// "Batch update returned unexpected row count from update; actual row count: 0; expected: 1" /// on UPDATE dbo.hlpdsk_requests ... WHERE ID = @p /// and no ticket was created. Root cause: HelpdeskReportBL.GetReportForHelpdesk (reached via the /// forward step) ran a throw-away transaction and rolled it back even when nested inside the task's /// ambient transaction, dropping the just-created ticket. /// /// The existing never sets SendMailToSelectedHelpdeskEmployees, /// so it does not exercise this path. This test does, and asserts the task creates a ticket and /// reports success. It is a regression guard for that fix. /// public class TaskHelpdeskForwardActionTest : EndToEndTest { public const int CustomerI3D = 10022; public const int ContractI3D = 35; public const int ResponsibleEmployeeI3D = 22; public const int UserI3D = 11; public TaskHelpdeskForwardActionTest(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } public override void Execute() { this.PrepareDatabase(); var taskI3D = this.CreateForwardingTask(); this.ExecuteAndAssertTicketCreated(taskI3D); } private void PrepareDatabase() { // The handler aborts/logs when the Task-Management sender address is empty, so set it. using (var session = new BLSession()) { var settings = session.GetBL().GetTaskManagementSettings(); settings.TaskManagementSenderAddress = "task-sender@example.com"; session.GetBL().UpdateTaskManagementSettings(settings); } // Make sure the employee we forward to has an e-mail address (used to build the internal mail). this.Sql($"UPDATE dbo.Personal SET Email = 'editor@example.com' WHERE I3D = {ResponsibleEmployeeI3D} AND (Email IS NULL OR Email = '')"); } private int CreateForwardingTask() { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == UserI3D); var task = new TaskManagementTaskDTO { Name = "Forwarding task (#167558 repro)", Description = "Ticket should be created and forwarded to the selected employees.", Status = ProjectStatus.Started, Action = new TaskManagementHelpdeskActionDTO { Customer = new CustomerPreviewDTO { I3D = CustomerI3D }, Category = new HelpdeskCategoryDTO { I3D = 6 }, Contract = new ContractDTO { I3D = ContractI3D }, Priority = new HelpdeskPrioritiesDTO { I3D = 1 }, Type = new HelpdeskTypeDTO { I3D = 6 }, State = new HelpdeskStatusDTO { I3D = 1 }, ResponsiblePerson = new EmployeePreviewDTO { I3D = ResponsibleEmployeeI3D }, // This is the flag that triggers the ForwardHelpdesk second-save path. SendMailToSelectedHelpdeskEmployees = true, Members = new List { new TaskManagementActionMemberDTO { Employee = new EmployeePreviewDTO { I3D = ResponsibleEmployeeI3D } } } }, Recurrence = new TaskManagementDailyRecurrenceDTO { AppointmentStart = new DateTime(2020, 2, 2, 13, 0, 0), StartTime = new DateTime(2020, 2, 2, 13, 0, 0), DayInterval = 14, NumberOfRecurrence = 53 } }; var saved = session.GetBL().SaveOrUpdateTask(task, user).ThrowIfError(); return saved.I3D; } } private void ExecuteAndAssertTicketCreated(int taskI3D) { Result executeResult = null; // Route the forward mail through the in-memory test transport so the test does not depend // on a configured SMTP host. TestMails.Start(() => { using var session = new BLSession(); var user = session.GetBL().GetAppUser(f => f.I3D == UserI3D); // Manual execution (single recurrence date), matching the Frasch case where even a // manual run fails. Isolates a single create+forward cycle. executeResult = session.GetBL().ExecuteTaskNow(taskI3D, user); }); Assert.True(executeResult.Status == ResultStatus.Success, $"ExecuteTask did not succeed (this reproduces #167558). Status={executeResult.Status}, Message={executeResult.Message}"); using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == UserI3D); var tickets = session.GetBL().GetHelpdesksThroughPaging( new HelpdeskFilter { CreatedByTasks = true, CreatedFromObjectKind = CentronObjectKindNumeric.TaskManagementClass, CreatedFromObjectI3D = taskI3D }, HelpdeskSort.Number, true, 1, int.MaxValue, new LoggedInUser(user)).ThrowIfError(); Assert.True(tickets.Result.Any(), "No ticket was created for the forwarding task (this reproduces #167558: task runs but no ticket exists)."); } } } }