using System; using Centron.BusinessLogic; using Centron.BusinessLogic.EmployeeArea; using Centron.BusinessLogic.WebServices.TaskManager; using Centron.Data.Entities.TaskManager; using Centron.Data.WebServices.Administration.Employees; 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 { /// /// Ticket 168833: duplicating a task template onto another customer used to carry the source customer's /// contact person over, so every generated ticket got a foreign contact. Covers both branches of the /// customer check in TaskManagementHelpdeskActionHandler. /// public class TaskHelpdeskActionContactPersonTest : EndToEndTest { private const int CustomerI3D = 10022; private const int UserI3D = 11; public TaskHelpdeskActionContactPersonTest(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } public override void Execute() { this.ContactOfTheOwnCustomerIsUsedForTheTicket(); this.ContactOfAnotherCustomerIsNotUsedForTheTicket(); } private void ContactOfTheOwnCustomerIsUsedForTheTicket() { // Needs a customer with two contacts, so the configured contact differs from the default contact - // otherwise the assertion could not tell the configured contact and the fallback apart. var customerI3D = this.GetCustomerWithTwoContactsOnDefaultAddress(); var defaultTicketContactI3D = this.MakeSingleDefaultTicketContact(customerI3D); var ownContactI3D = this.GetActiveContactOfCustomer(customerI3D, exceptContactI3D: defaultTicketContactI3D); var taskI3D = this.CreateStartedTask("Task mit eigenem Ansprechpartner", customerI3D, ownContactI3D); this.ExecuteTask(taskI3D); this.AssertEveryTicketOfTaskUsesContact(taskI3D, ownContactI3D); } private void ContactOfAnotherCustomerIsNotUsedForTheTicket() { var defaultTicketContactI3D = this.MakeSingleDefaultTicketContact(CustomerI3D); var foreignContactI3D = this.GetActiveContactOfAnotherCustomer(CustomerI3D); var taskI3D = this.CreateStartedTask("Task mit fremdem Ansprechpartner", CustomerI3D, foreignContactI3D); // The task itself must keep what was stored - the handler corrects the ticket, not the task data. var storedContactI3D = this.Sql( $"SELECT ISNULL(ContactI3D, 0) FROM TaskManagementAction WHERE I3D = (SELECT TaskManagementActionI3D FROM TaskManagementTask WHERE I3D = {taskI3D})"); Assert.True(storedContactI3D == foreignContactI3D, $"Expected the task to keep the stored contact {foreignContactI3D}, but it was changed to {storedContactI3D}."); this.ExecuteTask(taskI3D); this.AssertEveryTicketOfTaskUsesContact(taskI3D, defaultTicketContactI3D); } /// /// Asserts that the task created at least one ticket and that every single one of them uses the expected /// contact - checking only one ticket would miss a second one that kept the foreign contact. /// private void AssertEveryTicketOfTaskUsesContact(int taskI3D, int expectedContactI3D) { var ticketFilter = $@" FROM hlpdsk_requests WHERE CreatedFromObjectI3D = {taskI3D} AND CreatedFromObjectKind = {(int)CentronObjectKindNumeric.TaskManagementClass}"; var ticketCount = this.Sql($"SELECT COUNT(*) {ticketFilter}"); Assert.True(ticketCount > 0, $"No ticket was created for task {taskI3D}."); var wrongContactCount = this.Sql( $"SELECT COUNT(*) {ticketFilter} AND ISNULL(AnsprechpartnerI3D, 0) <> {expectedContactI3D}"); Assert.True(wrongContactCount == 0, $"{wrongContactCount} of {ticketCount} tickets of task {taskI3D} do not use the expected contact {expectedContactI3D}."); } /// /// Marks one active contact of the customer's default address as the only ticket default contact and /// returns it. This is the contact HelpdeskBL falls back to when a task carries no usable contact. /// private int MakeSingleDefaultTicketContact(int customerI3D) { var contactI3D = this.Sql($@" SELECT ISNULL(MIN(p.I3D), 0) FROM Personen p INNER JOIN Anschrif a ON a.I3D = p.AnschriftID WHERE p.Status = 1 AND a.Status = 1 AND a.Kunde = {customerI3D} AND a.KundeDefault = 1"); Assert.True(contactI3D > 0, $"The test database has no active contact on the default address of customer {customerI3D}."); this.Sql($@" UPDATE c SET c.DefaultTicket = 0 FROM AccountAddressContacts c INNER JOIN Personen p ON p.I3D = c.OldReferenceI3D INNER JOIN Anschrif a ON a.I3D = p.AnschriftID WHERE a.Kunde = {customerI3D}"); this.Sql($"UPDATE AccountAddressContacts SET DefaultTicket = 1 WHERE OldReferenceI3D = {contactI3D}"); return contactI3D; } private int GetCustomerWithTwoContactsOnDefaultAddress() { var customerI3D = this.Sql(@" SELECT ISNULL(MIN(candidates.Kunde), 0) FROM ( SELECT a.Kunde FROM Personen p INNER JOIN Anschrif a ON a.I3D = p.AnschriftID WHERE p.Status = 1 AND a.Status = 1 AND a.Kunde IS NOT NULL AND a.KundeDefault = 1 GROUP BY a.Kunde HAVING COUNT(*) >= 2 ) candidates"); Assert.True(customerI3D > 0, "The test database has no customer with two active contacts on its default address."); return customerI3D; } private int CreateStartedTask(string name, int customerI3D, int contactPersonI3D) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == UserI3D); var task = new TaskManagementTaskDTO { Name = name, Description = name, Status = ProjectStatus.Started, Action = new TaskManagementHelpdeskActionDTO { Customer = new CustomerPreviewDTO { I3D = customerI3D }, ContactPersonOldReferenceI3D = contactPersonI3D, Category = new HelpdeskCategoryDTO { I3D = 6 }, Priority = new HelpdeskPrioritiesDTO { I3D = 1 }, Type = new HelpdeskTypeDTO { I3D = 6 }, State = new HelpdeskStatusDTO { I3D = 1 }, ResponsiblePerson = new EmployeePreviewDTO { I3D = 22 } }, Recurrence = new TaskManagementDailyRecurrenceDTO { AppointmentStart = new DateTime(2020, 2, 2, 13, 0, 0), StartTime = new DateTime(2020, 2, 2, 13, 0, 0), DayInterval = 14, NumberOfRecurrence = 1 } }; var savedTask = session.GetBL().SaveOrUpdateTask(task, user); Assert.True(savedTask.Status == ResultStatus.Success, savedTask.Message); return savedTask.Data.I3D; } } private void ExecuteTask(int taskI3D) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == UserI3D); var result = session.GetBL().ExecuteTask(taskI3D, user); Assert.True(result.Status != ResultStatus.Error, result.Message); } } private int GetActiveContactOfCustomer(int customerI3D, int exceptContactI3D) { var contactI3D = this.Sql($@" SELECT ISNULL(MIN(p.I3D), 0) FROM Personen p INNER JOIN Anschrif a ON a.I3D = p.AnschriftID WHERE p.Status = 1 AND a.Status = 1 AND a.Kunde = {customerI3D} AND p.I3D <> {exceptContactI3D}"); Assert.True(contactI3D > 0, $"The test database has no second active contact for customer {customerI3D}."); return contactI3D; } private int GetActiveContactOfAnotherCustomer(int customerI3D) { var contactI3D = this.Sql($@" SELECT ISNULL(MIN(p.I3D), 0) FROM Personen p INNER JOIN Anschrif a ON a.I3D = p.AnschriftID WHERE p.Status = 1 AND a.Status = 1 AND a.Kunde IS NOT NULL AND a.Kunde <> {customerI3D}"); Assert.True(contactI3D > 0, "The test database has no active contact of another customer."); return contactI3D; } } }