diff --git a/backend/Tnsu.ApprovalRoute.Application/Common/StepLabels.cs b/backend/Tnsu.ApprovalRoute.Application/Common/StepLabels.cs index 5e92a8f..8eb2b8b 100644 --- a/backend/Tnsu.ApprovalRoute.Application/Common/StepLabels.cs +++ b/backend/Tnsu.ApprovalRoute.Application/Common/StepLabels.cs @@ -20,6 +20,18 @@ public static class StepLabels _ => headType.ToString() }; + /// Название с маленькой буквы — для середины фразы («Не найден руководитель направления»). + public static string InSentence(HeadType headType) => Lower(Of(headType)); + + /// + /// Все названия мужского рода («найден руководитель проекта»), кроме «Безопасность» — + /// для неё нужна отдельная формулировка, иначе выйдет «найден безопасность». + /// + public static string InSentence(ProjectRole projectRole) => + projectRole == ProjectRole.Security ? "сотрудник службы безопасности" : Lower(Of(projectRole)); + + private static string Lower(string label) => char.ToLowerInvariant(label[0]) + label[1..]; + public static string Of(ProjectRole projectRole) => projectRole switch { ProjectRole.ProjectManager => "Руководитель проекта", diff --git a/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs b/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs index 16c686b..3b3895f 100644 --- a/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs +++ b/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs @@ -438,7 +438,7 @@ public sealed class TemplateRouteService( { resolvedEmail = projectExecutors.FirstOrDefault(e => e.ProjectRole == step.ProjectRole)?.Email; if (string.IsNullOrWhiteSpace(resolvedEmail)) - warning = $"Не найден исполнитель с ролью в проекте «{StepLabels.Of(step.ProjectRole.Value)}»."; + warning = $"В проекте не найден {StepLabels.InSentence(step.ProjectRole.Value)}."; } // DepartmentHead — единственный HeadType, который резолвится НЕ по цепочке // подчинённости инициатора, а по отделу, переданному явно в запросе (см. @@ -471,12 +471,12 @@ public sealed class TemplateRouteService( }; if (string.IsNullOrWhiteSpace(resolvedEmail)) { - var headLabel = StepLabels.Of(step.HeadType.Value); + var headLabel = StepLabels.InSentence(step.HeadType.Value); // Директор Tansu и управляющий директор берутся из настроек сервиса, а не из // справочника сотрудников — там email не «не найден», а «не проставлен». warning = step.HeadType is HeadType.DirectorTansu or HeadType.ManagingDirectorTansu - ? $"Не проставлен «{headLabel}»: email не задан в настройках сервиса." - : $"Не найден руководитель «{headLabel}»: не указан у инициатора в справочнике сотрудников."; + ? $"Не проставлен {headLabel}." + : $"Не найден {headLabel}."; } } else diff --git a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs index 8b7c2af..4ef4b38 100644 --- a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs +++ b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs @@ -1051,7 +1051,7 @@ public sealed class TemplateRouteServiceTests : IClassFixture