diff --git a/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs b/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs index aae5af9..e1122c3 100644 --- a/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs +++ b/backend/Tnsu.ApprovalRoute.Application/TemplateRoutes/TemplateRouteService.cs @@ -261,9 +261,12 @@ public sealed class TemplateRouteService( } else if (!string.IsNullOrWhiteSpace(step.Position)) { - resolvedEmail = await portalClient.GetEmployeeByPositionAsync(step.Position, initiatorCompany, cancellationToken); - if (string.IsNullOrWhiteSpace(resolvedEmail)) + var employeeByPosition = await portalClient.GetEmployeeByPositionAsync(step.Position, initiatorCompany, cancellationToken); + resolvedEmail = employeeByPosition.Email; + if (!employeeByPosition.Found) warning = $"Не найден сотрудник на должности «{step.Position}» в компании «{initiatorCompany}»."; + else if (string.IsNullOrWhiteSpace(resolvedEmail)) + warning = $"Сотрудник {employeeByPosition.Fio} на должности «{step.Position}» найден, но email не указан в системе портала."; } else if (step.ProjectRole is not (null or ProjectRole.None)) { diff --git a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/CachingTnsuPortalClient.cs b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/CachingTnsuPortalClient.cs index 6ddab54..785e246 100644 --- a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/CachingTnsuPortalClient.cs +++ b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/CachingTnsuPortalClient.cs @@ -22,7 +22,7 @@ public sealed class CachingTnsuPortalClient(HttpTnsuPortalClient inner, IMemoryC $"emp:email:{email.ToLowerInvariant()}", () => inner.GetEmployeeByEmailAsync(email, cancellationToken)); - public Task GetEmployeeByPositionAsync(string position, string company, CancellationToken cancellationToken) => + public Task GetEmployeeByPositionAsync(string position, string company, CancellationToken cancellationToken) => GetOrAddAsync( $"emp:position:{position.ToLowerInvariant()}|{company.ToLowerInvariant()}", () => inner.GetEmployeeByPositionAsync(position, company, cancellationToken)); diff --git a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/HttpTnsuPortalClient.cs b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/HttpTnsuPortalClient.cs index 24bd5e7..9c050ac 100644 --- a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/HttpTnsuPortalClient.cs +++ b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/HttpTnsuPortalClient.cs @@ -25,12 +25,12 @@ public sealed class HttpTnsuPortalClient( return new EmployeeDirectoryInfo(employee.CompanyId ?? Guid.Empty, employee.DepartmentId, employee.Company ?? string.Empty, employee.Position); } - public async Task GetEmployeeByPositionAsync(string position, string company, CancellationToken cancellationToken) + public async Task GetEmployeeByPositionAsync(string position, string company, CancellationToken cancellationToken) { var employee = await GetAsync( $"/Employee/ByPosition?position={Uri.EscapeDataString(position)}&company={Uri.EscapeDataString(company)}", cancellationToken); - return employee?.Email; + return new EmployeeLookupResult(employee is not null, employee?.Email, employee?.Fio); } public async Task GetManagerAsync(string email, string managerType, CancellationToken cancellationToken) @@ -107,7 +107,8 @@ public sealed class HttpTnsuPortalClient( [property: JsonPropertyName("company")] string? Company, [property: JsonPropertyName("companyId")] Guid? CompanyId, [property: JsonPropertyName("departmentId")] Guid? DepartmentId, - [property: JsonPropertyName("position")] string? Position); + [property: JsonPropertyName("position")] string? Position, + [property: JsonPropertyName("fio")] string? Fio); private sealed record ManagerResponse( [property: JsonPropertyName("managerEmail")] string? ManagerEmail); diff --git a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/ITnsuPortalClient.cs b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/ITnsuPortalClient.cs index 502affa..2821d9d 100644 --- a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/ITnsuPortalClient.cs +++ b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/ITnsuPortalClient.cs @@ -4,7 +4,7 @@ public interface ITnsuPortalClient { Task GetEmployeeByEmailAsync(string email, CancellationToken cancellationToken); - Task GetEmployeeByPositionAsync(string position, string company, CancellationToken cancellationToken); + Task GetEmployeeByPositionAsync(string position, string company, CancellationToken cancellationToken); Task GetManagerAsync(string email, string managerType, CancellationToken cancellationToken); diff --git a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/TnsuPortalDtos.cs b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/TnsuPortalDtos.cs index 29fe375..9a0636b 100644 --- a/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/TnsuPortalDtos.cs +++ b/backend/Tnsu.ApprovalRoute.Infrastructure/TnsuPortal/TnsuPortalDtos.cs @@ -5,3 +5,6 @@ namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal; public sealed record EmployeeDirectoryInfo(Guid CompanyId, Guid? DepartmentId, string Company, string? Position); public sealed record ProjectExecutorInfo(ProjectRole ProjectRole, string Email); + +/// Найден ли сотрудник вообще — отдельно от того, заполнен ли у него email в портале (это разные проблемы). +public sealed record EmployeeLookupResult(bool Found, string? Email, string? Fio); diff --git a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs index cc77636..ad5e0e7 100644 --- a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs +++ b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/TemplateRouteServiceTests.cs @@ -560,7 +560,7 @@ public sealed class TemplateRouteServiceTests : IClassFixture x.GetEmployeeByPositionAsync("Lead", "ТОО TANSU Construction", It.IsAny())) - .ReturnsAsync("lead@tnsu.kz"); + .ReturnsAsync(new EmployeeLookupResult(true, "lead@tnsu.kz", "Иванов Иван Иванович")); var services = TestServiceProviderFactory.Build(_connectionString, portalClient: portalClient.Object); var routeService = services.GetRequiredService();