основное сделано

This commit is contained in:
gorbenko.pavel
2026-08-12 15:12:11 +05:00
parent 4b83d666f1
commit 9fc089c37a
47 changed files with 2481 additions and 52 deletions
@@ -129,8 +129,11 @@ public sealed class TemplateRouteService(
return Result.Fail<ResolveTemplateRouteResultDto>(
new ValidationError("Не удалось определить email инициатора: не передан явно и отсутствует в токене."));
var requestTypeExists = await db.RequestTypes.AnyAsync(x => x.Id == request.RequestTypeId, cancellationToken);
if (!requestTypeExists)
// Сам тип заявки, а не только факт его существования: из него берутся
// значения SLA по умолчанию для шагов (см. ResolveStepAsync).
var requestType = await db.RequestTypes.AsNoTracking()
.FirstOrDefaultAsync(x => x.Id == request.RequestTypeId, cancellationToken);
if (requestType is null)
return Result.Fail<ResolveTemplateRouteResultDto>(new NotFoundError("Тип заявки", request.RequestTypeId));
var employee = await portalClient.GetEmployeeByEmailAsync(email, cancellationToken);
@@ -168,7 +171,8 @@ public sealed class TemplateRouteService(
var steps = new List<ResolvedRouteStepDto>();
foreach (var step in matchingSteps)
steps.Add(await ResolveStepAsync(step, email, employee.Company, projectExecutors, request.DepartmentId, cancellationToken));
steps.Add(await ResolveStepAsync(
step, email, employee.Company, projectExecutors, request.DepartmentId, requestType, cancellationToken));
var collapsedSteps = CollapseByExecutorEmail(steps);
@@ -212,7 +216,8 @@ public sealed class TemplateRouteService(
private async Task<ResolvedRouteStepDto> ResolveStepAsync(
TemplateRouteStep step, string initiatorEmail, string initiatorCompany,
IReadOnlyList<ProjectExecutorInfo> projectExecutors, Guid? departmentId, CancellationToken cancellationToken)
IReadOnlyList<ProjectExecutorInfo> projectExecutors, Guid? departmentId, RequestType requestType,
CancellationToken cancellationToken)
{
string? resolvedEmail;
string? warning = null;
@@ -277,7 +282,19 @@ public sealed class TemplateRouteService(
resolvedPosition = resolvedEmployee?.Position;
}
return new ResolvedRouteStepDto(step.Id, step.OrderNo, resolvedEmail, resolvedPosition, step.AllowReassignToOtherApprovers, warning);
// Наследование SLA применяется ЗДЕСЬ, а не у вызывающей стороны: `??`
// работает именно так, как задумано — значение шага перекрывает типовое,
// и при этом заданный на шаге 0 остаётся нулём, а не подменяется типовым
// (0 — осознанное «напоминать сразу», см. TemplateRouteStep.SlaHours).
return new ResolvedRouteStepDto(
step.Id,
step.OrderNo,
resolvedEmail,
resolvedPosition,
step.AllowReassignToOtherApprovers,
warning,
step.SlaHours ?? requestType.SlaHours,
step.AskOverdueReason ?? requestType.AskOverdueReason);
}
/// <summary>