переработана логика
This commit is contained in:
@@ -23,10 +23,18 @@ public sealed record ResolvedRouteStepDto(
|
||||
int? SlaHours = null,
|
||||
bool? AskOverdueReason = null);
|
||||
|
||||
/// <param name="Warning">
|
||||
/// Предупреждение уровня всего резолва (не привязано к конкретному шагу) — например,
|
||||
/// в маршруте есть шаг с условием по полю IsManager, а в заявке не передано значение
|
||||
/// поля Position, из которого IsManager вычисляется. Это не ошибка (резолв всё равно
|
||||
/// отработал, IsManager просто посчитался как «false»), но может означать, что
|
||||
/// вызывающая сторона забыла передать поле, и шаг из-за этого не появился, хотя должен был.
|
||||
/// </param>
|
||||
public sealed record ResolveTemplateRouteResultDto(
|
||||
int RouteId,
|
||||
bool RequiresControl,
|
||||
IReadOnlyList<ResolvedRouteStepDto> Steps);
|
||||
IReadOnlyList<ResolvedRouteStepDto> Steps,
|
||||
string? Warning = null);
|
||||
|
||||
/// <summary>Значение поля списка SharePoint (field_name шага) для проверки условий шагов при resolve.</summary>
|
||||
public sealed record ResolveFieldValueDto(string FieldName, string Value);
|
||||
|
||||
@@ -163,10 +163,29 @@ public sealed class TemplateRouteService(
|
||||
.GroupBy(f => f.FieldName, StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(g => g.Key, g => g.First().Value, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Синтетическое поле условия (не пришедшее из request.FieldValues, а вычисленное
|
||||
// здесь): должность в справочнике — свободный текст, поэтому «руководитель или
|
||||
// нет» определяем по ключевым словам в её названии, а не по отдельному флагу.
|
||||
fieldValues["IsManager"] = IsManagerPosition(employee.Position) ? "true" : "false";
|
||||
// Синтетическое поле условия — переопределяет то, что мог прислать вызывающий
|
||||
// код под тем же именем. Считаем НЕ по должности инициатора из справочника
|
||||
// api.tnsu.kz (employee.Position — она у самого сотрудника чаще всего не
|
||||
// «руководитель»), а по полю Position, заполненному В САМОЙ АНКЕТЕ (например,
|
||||
// «Должность» в Обходном листе — там указывают должность увольняемого, а не
|
||||
// того, кто отправил заявку). Это свободный текст, поэтому определяем
|
||||
// «руководитель или нет» по ключевым словам в нём. Нет такого поля в заявке —
|
||||
// считаем «нет» (а не подставляем должность инициатора как фолбэк).
|
||||
fieldValues.TryGetValue("Position", out var formPosition);
|
||||
fieldValues["IsManager"] = IsManagerPosition(formPosition) ? "true" : "false";
|
||||
|
||||
// Предупреждение уровня резолва, а не шага: условие по IsManager есть в маршруте
|
||||
// (хотя бы на одном шаге, независимо от статуса — фильтр по s.Status ниже сузил бы
|
||||
// проверку до конкретной фазы, а «забыли передать Position» это не про фазу), но
|
||||
// Position в заявке не пришёл вовсе. Если поле пришло, но пустой строкой или не
|
||||
// похоже на руководящую должность — это осознанный «false», предупреждать не о чем.
|
||||
string? generalWarning = null;
|
||||
if (string.IsNullOrWhiteSpace(formPosition) &&
|
||||
route.Steps.Any(s => string.Equals(s.FieldName, "IsManager", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
generalWarning = "В маршруте есть шаг с условием по полю «IsManager», но в заявке не передано значение " +
|
||||
"поля «Position» (должность) — условие считается невыполненным.";
|
||||
}
|
||||
|
||||
var matchingSteps = route.Steps
|
||||
.Where(s => s.Status == request.Status)
|
||||
@@ -181,7 +200,7 @@ public sealed class TemplateRouteService(
|
||||
|
||||
var collapsedSteps = CollapseByExecutorEmail(steps);
|
||||
|
||||
return Result.Ok(new ResolveTemplateRouteResultDto(route.Id, route.RequiresControl, collapsedSteps));
|
||||
return Result.Ok(new ResolveTemplateRouteResultDto(route.Id, route.RequiresControl, collapsedSteps, generalWarning));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user