using System; using System.Linq; using Centron.BusinessLogic; using Centron.BusinessLogic.Sales.Support; using Centron.BusinessLogic.TaskManager; using Centron.BusinessLogic.WebServices.TaskManager; using Centron.Data.Entities.TaskManager; using Centron.Data.Entities.TaskManager.Actions; using Centron.Data.Entities.TaskManager.Recurrences; using Centron.Interfaces.BL; using Centron.Tests.EndToEnd.Infrastructure; using Xunit; using Xunit.Abstractions; namespace Centron.Tests.EndToEnd.Tests.TaskManagement { /// /// Ticket 168438: the orphan inspector must re-create and re-link the missing ticket for a helpdesk-task /// execution that was marked as done but whose ticket was rolled back ("transaction has already ended"). /// This drives the full backend path: create an active helpdesk task, execute it, strip the ticket link, /// then detect + repair. /// public class TaskManagementOrphanRepairTests : EndToEndTest { // An existing helpdesk in the seed data; we reuse its customer/state/priority/type/category so the // task's action passes validation regardless of which "field required" settings are active. private const int ReferenceHelpdeskI3D = 10491; public TaskManagementOrphanRepairTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } public override void Execute() { var user = this.GetLoggedInUser(); // Require a clean baseline: the repair is global, so a nonzero baseline would be fixed too and // make the post-repair assertions ambiguous. using (var session = new BLSession()) Assert.Equal(0, session.GetBL().CountOrphanedHelpdeskExecutions(user.User).ThrowIfError()); int taskI3D; int actionI3D; using (var session = new BLSession()) { // Load the reference helpdesk in this same session, so its customer/state/... entities stay // attached and can be reused on the task's action. var refHelpdesk = session.GetBL().GetHelpdesk(ReferenceHelpdeskI3D); Assert.NotNull(refHelpdesk); var yesterday = DateTime.Today.AddDays(-1); var task = new TaskManagementTask { Status = ProjectStatus.Started, Name = "Repair E2E Test", Description = "Repair E2E Test", Action = new TaskManagementHelpdeskAction { Customer = refHelpdesk.Customer, State = refHelpdesk.HelpdeskState, Priority = refHelpdesk.HelpdeskPriority, Type = refHelpdesk.HelpdeskType, Category = refHelpdesk.MainCategory, ResponsiblePerson = user.User.Employee, }, Recurrence = new TaskManagementDailyRecurrence { DayInterval = 1, StartTime = yesterday, AppointmentStart = yesterday, ExecuteDaysBefore = 0, }, }; var saved = session.GetBL().SaveOrUpdateTask(task, user.User).ThrowIfError(); taskI3D = saved.I3D; actionI3D = saved.Action.I3D; } // Manual execution creates the ticket and records the execution (linked to the ticket). using (var session = new BLSession()) session.GetBL().ExecuteTaskNow(taskI3D, user.User).ThrowIfError(); int executedAtI3D; using (var session = new BLSession()) { var exec = session.GetBL().GetTaskExecutedAtByI3D(actionI3D, onlyLatestEntry: true) .ThrowIfError().FirstOrDefault(); Assert.NotNull(exec); Assert.NotNull(exec.TicketI3D); executedAtI3D = exec.I3D; } // Simulate the rollback orphan: execution stays "done" but the ticket link is gone. this.Sql($"UPDATE TaskManagementActionExecutedAt SET TicketI3D = NULL WHERE I3D = {executedAtI3D}"); using (var session = new BLSession()) { var count = session.GetBL().CountOrphanedHelpdeskExecutions(user.User).ThrowIfError(); Assert.Equal(1, count); } using (var session = new BLSession()) { var repaired = session.GetBL().RepairMissingHelpdeskTickets(user.User).ThrowIfError(); Assert.True(repaired >= 1, "Expected at least the seeded orphan to be repaired."); } using (var session = new BLSession()) { var exec = session.GetBL().GetTaskExecutedAtByI3D(actionI3D, onlyLatestEntry: true) .ThrowIfError().FirstOrDefault(); Assert.NotNull(exec); Assert.NotNull(exec.TicketI3D); var ticket = session.GetBL().GetHelpdesk(exec.TicketI3D.Value); Assert.NotNull(ticket); var count = session.GetBL().CountOrphanedHelpdeskExecutions(user.User).ThrowIfError(); Assert.Equal(0, count); } } } }