Files
Christoph Schwörer f045b99a25 Codebasis als Dateien ins Arbeitsrepo statt als Gitlink
QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142)
getrackt, ohne .gitmodules und ohne erreichbares Remote. Der
Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar
gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege
der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen.

Umstellung:
- Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert
  (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6)
- Gitlink aus dem Index entfernt
- Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB

Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte
bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
2026-08-26 07:43:51 +02:00

166 lines
7.7 KiB
C#

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
{
/// <summary>
/// Reproduction for Ticket #167558 (Raphael Frasch GmbH) — "Taskmanagement geht bringt Fehler".
///
/// A helpdesk task whose action has <see cref="TaskManagementHelpdeskActionDTO.SendMailToSelectedHelpdeskEmployees"/>
/// = 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 <see cref="TaskHelpdeskActionTest"/> 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.
/// </summary>
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<AppSettingsGroupWebServiceBL>().GetTaskManagementSettings();
settings.TaskManagementSenderAddress = "task-sender@example.com";
session.GetBL<AppSettingsGroupWebServiceBL>().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<AppUserBL>().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<TaskManagementActionMemberDTO>
{
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<TaskManagementTaskWebServiceBL>().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<AppUserBL>().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<TaskManagementTaskWebServiceBL>().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<AppUserBL>().GetAppUser(f => f.I3D == UserI3D);
var tickets = session.GetBL<HelpdeskSearchWebServiceBL>().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).");
}
}
}
}