Feature/routes export #29
@@ -24,7 +24,6 @@ public sealed class RouteExportService(
|
||||
{
|
||||
private const string Empty = "—";
|
||||
private const string Always = "Всегда";
|
||||
private const string AnyOrganization = "Любая";
|
||||
private const string AnyCompany = "любая компания";
|
||||
private const string AnyDepartment = "любой отдел";
|
||||
private const string ByRequest = "Определяется по заявке";
|
||||
@@ -112,12 +111,9 @@ public sealed class RouteExportService(
|
||||
var sections = routes
|
||||
.Select(route =>
|
||||
{
|
||||
var organization = route.CompanyId is { } companyId
|
||||
? directory.CompanyName(companyId)
|
||||
: AnyOrganization;
|
||||
return new RouteExportSection(
|
||||
routes.Count < 2 ? null : RouteTitle(route, directory),
|
||||
BuildGroups(route.Steps, organization, directory));
|
||||
BuildGroups(route.Steps, directory));
|
||||
})
|
||||
.ToList();
|
||||
|
||||
@@ -131,7 +127,7 @@ public sealed class RouteExportService(
|
||||
return $"Маршрут: {company} · {department}{(route.ByProject ? " · по проекту" : string.Empty)}";
|
||||
}
|
||||
|
||||
private List<RouteExportGroup> BuildGroups(IEnumerable<TemplateRouteStep> steps, string organization, PortalDirectory directory)
|
||||
private List<RouteExportGroup> BuildGroups(IEnumerable<TemplateRouteStep> steps, PortalDirectory directory)
|
||||
{
|
||||
var ordered = steps.OrderBy(s => s.OrderNo).ToList();
|
||||
var approvers = ordered.Where(s => s.Status != RouteStepStatus.Execution).ToList();
|
||||
@@ -139,22 +135,22 @@ public sealed class RouteExportService(
|
||||
|
||||
return new[]
|
||||
{
|
||||
new RouteExportGroup("Согласующие", BuildRows(approvers, organization, directory)),
|
||||
new RouteExportGroup("Исполнители", BuildRows(executors, organization, directory))
|
||||
new RouteExportGroup("Согласующие", BuildRows(approvers, directory)),
|
||||
new RouteExportGroup("Исполнители", BuildRows(executors, directory))
|
||||
}
|
||||
.Where(g => g.Rows.Count > 0)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// Параллельные шаги (равный OrderNo) получают один и тот же номер.
|
||||
private List<RouteExportRow> BuildRows(IReadOnlyList<TemplateRouteStep> steps, string organization, PortalDirectory directory)
|
||||
private List<RouteExportRow> BuildRows(IReadOnlyList<TemplateRouteStep> steps, PortalDirectory directory)
|
||||
{
|
||||
var orderNos = steps.Select(s => s.OrderNo).Distinct().OrderBy(n => n).ToList();
|
||||
|
||||
return steps
|
||||
.Select(step =>
|
||||
{
|
||||
var (role, executor) = DescribeRoleAndExecutor(step, directory);
|
||||
var (role, executor, organization) = DescribeRoleAndExecutor(step, directory);
|
||||
return new RouteExportRow(
|
||||
orderNos.IndexOf(step.OrderNo) + 1,
|
||||
role,
|
||||
@@ -169,19 +165,22 @@ public sealed class RouteExportService(
|
||||
// «Роль» — должность или тип руководителя, «исполнитель» — конкретный человек,
|
||||
// если он известен уже при настройке маршрута. Директор Tansu и Управляющий
|
||||
// директор Tansu — тоже конкретные люди (их email лежит в настройках).
|
||||
private (string Role, string Executor) DescribeRoleAndExecutor(TemplateRouteStep step, PortalDirectory directory)
|
||||
private (string Role, string Executor, string Organization) DescribeRoleAndExecutor(TemplateRouteStep step, PortalDirectory directory)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(step.ExecutorEmail))
|
||||
{
|
||||
var employee = directory.FindByEmail(step.ExecutorEmail);
|
||||
return (EmptyIfBlank(employee?.Position), employee?.Fio ?? step.ExecutorEmail);
|
||||
return (EmptyIfBlank(employee?.Position), employee?.Fio ?? step.ExecutorEmail, directory.CompaniesOf(step.ExecutorEmail));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(step.Position))
|
||||
return (step.Position, directory.FindByPosition(step.Position)?.Fio ?? Empty);
|
||||
{
|
||||
var holder = directory.FindByPosition(step.Position);
|
||||
return (step.Position, holder?.Fio ?? Empty, directory.CompaniesOf(holder?.Email));
|
||||
}
|
||||
|
||||
if (step.ProjectRole is { } projectRole && projectRole != ProjectRole.None)
|
||||
return (ProjectRoleLabels[projectRole], ByRequest);
|
||||
return (ProjectRoleLabels[projectRole], ByRequest, Empty);
|
||||
|
||||
if (step.HeadType is { } headType && headType != HeadType.None)
|
||||
{
|
||||
@@ -193,12 +192,12 @@ public sealed class RouteExportService(
|
||||
};
|
||||
if (fixedEmail is not null)
|
||||
// Нет в справочнике — лучше показать email, чем пустую ячейку.
|
||||
return (HeadTypeLabels[headType], directory.FindByEmail(fixedEmail)?.Fio ?? fixedEmail);
|
||||
return (HeadTypeLabels[headType], directory.FindByEmail(fixedEmail)?.Fio ?? fixedEmail, directory.CompaniesOf(fixedEmail));
|
||||
|
||||
return (HeadTypeLabels[headType], ByRequest);
|
||||
return (HeadTypeLabels[headType], ByRequest, Empty);
|
||||
}
|
||||
|
||||
return (Empty, Empty);
|
||||
return (Empty, Empty, Empty);
|
||||
}
|
||||
|
||||
private static string DescribeCondition(TemplateRouteStep step)
|
||||
@@ -239,6 +238,22 @@ public sealed class RouteExportService(
|
||||
public EmployeeContactInfo? FindByPosition(string position) =>
|
||||
employees.FirstOrDefault(e => string.Equals(e.Position?.Trim(), position.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// Организация — компания СОТРУДНИКА, а не маршрута. Справочник даёт строку на
|
||||
// каждую компанию, где он числится (совместители), поэтому выводим все.
|
||||
public string CompaniesOf(string? email)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(email))
|
||||
return Empty;
|
||||
|
||||
var names = employees
|
||||
.Where(e => string.Equals(e.Email, email, StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.IsNullOrWhiteSpace(e.Company))
|
||||
.Select(e => e.Company)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
return names.Count == 0 ? Empty : string.Join(", ", names);
|
||||
}
|
||||
|
||||
// Пока справочник не отдал имя (или запись удалена) — усечённый Guid, как в админке.
|
||||
public string CompanyName(Guid id) => companies.GetValueOrDefault(id) ?? ShortGuid(id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user