правки

This commit is contained in:
gorbenko.pavel
2026-07-24 17:54:34 +05:00
parent 3ae1965c29
commit 5928377465
4 changed files with 88 additions and 12 deletions
@@ -16,8 +16,8 @@ public sealed record TemplateRouteStepDto(
public sealed record CreateTemplateRouteStepRequest(
int OrderNo,
string ExecutorEmail,
string Position,
string? ExecutorEmail,
string? Position,
ProjectRole ProjectRole,
HeadType HeadType,
RouteStepStatus Status,
@@ -25,8 +25,8 @@ public sealed record CreateTemplateRouteStepRequest(
public sealed record UpdateTemplateRouteStepRequest(
int OrderNo,
string ExecutorEmail,
string Position,
string? ExecutorEmail,
string? Position,
ProjectRole ProjectRole,
HeadType HeadType,
RouteStepStatus Status,
@@ -41,12 +41,21 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
return Result.Fail<TemplateRouteStepDto>(new ValidationError(
"Роль в проекте недопустима для шага маршрута, который не учитывает проект (by_project = false)."));
var executorEmail = r.ExecutorEmail ?? string.Empty;
var position = r.Position ?? string.Empty;
var duplicate = await HasDuplicateAsync(
route.Id, executorEmail, position, r.ProjectRole, r.HeadType, r.Status, excludeId: null, cancellationToken);
if (duplicate)
return Result.Fail<TemplateRouteStepDto>(new ConflictError(
"Шаг с такими исполнителем, должностью, ролью в проекте, типом руководителя и статусом уже существует в этом маршруте."));
var entity = new TemplateRouteStep
{
RouteId = route.Id,
OrderNo = r.OrderNo,
ExecutorEmail = r.ExecutorEmail,
Position = r.Position,
ExecutorEmail = executorEmail,
Position = position,
ProjectRole = r.ProjectRole,
HeadType = r.HeadType,
Status = r.Status,
@@ -73,9 +82,18 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
return Result.Fail<TemplateRouteStepDto>(new ValidationError(
"Роль в проекте недопустима для шага маршрута, который не учитывает проект (by_project = false)."));
var executorEmail = r.ExecutorEmail ?? string.Empty;
var position = r.Position ?? string.Empty;
var duplicate = await HasDuplicateAsync(
route.Id, executorEmail, position, r.ProjectRole, r.HeadType, r.Status, excludeId: entity.Id, cancellationToken);
if (duplicate)
return Result.Fail<TemplateRouteStepDto>(new ConflictError(
"Шаг с такими исполнителем, должностью, ролью в проекте, типом руководителя и статусом уже существует в этом маршруте."));
entity.OrderNo = r.OrderNo;
entity.ExecutorEmail = r.ExecutorEmail;
entity.Position = r.Position;
entity.ExecutorEmail = executorEmail;
entity.Position = position;
entity.ProjectRole = r.ProjectRole;
entity.HeadType = r.HeadType;
entity.Status = r.Status;
@@ -97,6 +115,19 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
return Result.Ok();
}
private Task<bool> HasDuplicateAsync(
int routeId, string executorEmail, string position, ProjectRole projectRole, HeadType headType,
RouteStepStatus status, int? excludeId, CancellationToken cancellationToken) =>
db.TemplateRouteSteps.AnyAsync(x =>
x.Id != excludeId &&
x.RouteId == routeId &&
x.ExecutorEmail == executorEmail &&
x.Position == position &&
x.ProjectRole == projectRole &&
x.HeadType == headType &&
x.Status == status,
cancellationToken);
// Для маршрута «по проекту» без единого шага с ролью в проекте DTO несёт предупреждение в поле Warning.
private async Task<TemplateRouteStepDto> ToDtoWithWarningAsync(
TemplateRouteStep entity, TemplateRoute route, CancellationToken cancellationToken)
@@ -8,8 +8,12 @@ public sealed class CreateTemplateRouteStepRequestValidator : AbstractValidator<
public CreateTemplateRouteStepRequestValidator()
{
RuleFor(x => x)
.Must(x => !(string.IsNullOrWhiteSpace(x.ExecutorEmail) && string.IsNullOrWhiteSpace(x.Position) && x.ProjectRole == ProjectRole.None))
.WithMessage("Исполнитель, должность и роль в проекте не могут быть пустыми одновременно.");
.Must(x =>
!string.IsNullOrWhiteSpace(x.ExecutorEmail) ||
!string.IsNullOrWhiteSpace(x.Position) ||
x.ProjectRole != ProjectRole.None ||
x.HeadType != HeadType.None)
.WithMessage("Должно быть заполнено хотя бы одно из полей: исполнитель, должность, роль в проекте или тип руководителя.");
}
}
@@ -18,7 +22,11 @@ public sealed class UpdateTemplateRouteStepRequestValidator : AbstractValidator<
public UpdateTemplateRouteStepRequestValidator()
{
RuleFor(x => x)
.Must(x => !(string.IsNullOrWhiteSpace(x.ExecutorEmail) && string.IsNullOrWhiteSpace(x.Position) && x.ProjectRole == ProjectRole.None))
.WithMessage("Исполнитель, должность и роль в проекте не могут быть пустыми одновременно.");
.Must(x =>
!string.IsNullOrWhiteSpace(x.ExecutorEmail) ||
!string.IsNullOrWhiteSpace(x.Position) ||
x.ProjectRole != ProjectRole.None ||
x.HeadType != HeadType.None)
.WithMessage("Должно быть заполнено хотя бы одно из полей: исполнитель, должность, роль в проекте или тип руководителя.");
}
}