апи для работы с маршрутами согласования #2
@@ -1,5 +1,5 @@
|
|||||||
namespace Tnsu.ApprovalRoute.Api.Common;
|
namespace Tnsu.ApprovalRoute.Api.Common;
|
||||||
|
|
||||||
public sealed record ApiResponse<T>(T Data, IReadOnlyList<string> Warnings);
|
public sealed record ApiResponse<T>(T Data);
|
||||||
|
|
||||||
public sealed record ApiError(string Message);
|
public sealed record ApiError(string Message);
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ public static class ResultExtensions
|
|||||||
if (result.IsFailed)
|
if (result.IsFailed)
|
||||||
return result.Errors[0].ToActionResult();
|
return result.Errors[0].ToActionResult();
|
||||||
|
|
||||||
var warnings = result.Reasons.OfType<Warning>().Select(w => w.Message).ToList();
|
return new OkObjectResult(new ApiResponse<T>(result.Value));
|
||||||
return new OkObjectResult(new ApiResponse<T>(result.Value, warnings));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IActionResult ToActionResult(this Result result)
|
public static IActionResult ToActionResult(this Result result)
|
||||||
|
|||||||
@@ -8,5 +8,3 @@ public sealed class NotFoundError(string entity, object id)
|
|||||||
public sealed class ValidationError(string message) : Error(message);
|
public sealed class ValidationError(string message) : Error(message);
|
||||||
|
|
||||||
public sealed class ConflictError(string message) : Error(message);
|
public sealed class ConflictError(string message) : Error(message);
|
||||||
|
|
||||||
public sealed class Warning(string message) : Success(message);
|
|
||||||
|
|||||||
+2
-1
@@ -11,7 +11,8 @@ public sealed record TemplateRouteStepDto(
|
|||||||
HeadType HeadType,
|
HeadType HeadType,
|
||||||
RouteStepStatus Status,
|
RouteStepStatus Status,
|
||||||
int RouteId,
|
int RouteId,
|
||||||
bool AllowReassignToOtherApprovers);
|
bool AllowReassignToOtherApprovers,
|
||||||
|
string? Warning = null);
|
||||||
|
|
||||||
public sealed record CreateTemplateRouteStepRequest(
|
public sealed record CreateTemplateRouteStepRequest(
|
||||||
int OrderNo,
|
int OrderNo,
|
||||||
|
|||||||
+12
-12
@@ -55,8 +55,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
|
|||||||
db.TemplateRouteSteps.Add(entity);
|
db.TemplateRouteSteps.Add(entity);
|
||||||
await db.SaveChangesAsync(cancellationToken);
|
await db.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
var result = Result.Ok(ToDto(entity));
|
return Result.Ok(await ToDtoWithWarningAsync(entity, route, cancellationToken));
|
||||||
return await AppendMissingProjectRoleWarningAsync(route, result, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Result<TemplateRouteStepDto>> UpdateAsync(
|
public async Task<Result<TemplateRouteStepDto>> UpdateAsync(
|
||||||
@@ -83,8 +82,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
|
|||||||
entity.AllowReassignToOtherApprovers = r.AllowReassignToOtherApprovers;
|
entity.AllowReassignToOtherApprovers = r.AllowReassignToOtherApprovers;
|
||||||
await db.SaveChangesAsync(cancellationToken);
|
await db.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
var result = Result.Ok(ToDto(entity));
|
return Result.Ok(await ToDtoWithWarningAsync(entity, route, cancellationToken));
|
||||||
return await AppendMissingProjectRoleWarningAsync(route, result, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Result> DeleteAsync(int routeId, int id, CancellationToken cancellationToken)
|
public async Task<Result> DeleteAsync(int routeId, int id, CancellationToken cancellationToken)
|
||||||
@@ -99,18 +97,20 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
|
|||||||
return Result.Ok();
|
return Result.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Result<TemplateRouteStepDto>> AppendMissingProjectRoleWarningAsync(
|
// Для маршрута «по проекту» без единого шага с ролью в проекте DTO несёт предупреждение в поле Warning.
|
||||||
TemplateRoute route, Result<TemplateRouteStepDto> result, CancellationToken cancellationToken)
|
private async Task<TemplateRouteStepDto> ToDtoWithWarningAsync(
|
||||||
|
TemplateRouteStep entity, TemplateRoute route, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
string? warning = null;
|
||||||
|
if (route.ByProject)
|
||||||
{
|
{
|
||||||
if (!route.ByProject)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
var hasProjectRoleStep = await db.TemplateRouteSteps
|
var hasProjectRoleStep = await db.TemplateRouteSteps
|
||||||
.AnyAsync(x => x.RouteId == route.Id && x.ProjectRole != ProjectRole.None, cancellationToken);
|
.AnyAsync(x => x.RouteId == route.Id && x.ProjectRole != ProjectRole.None, cancellationToken);
|
||||||
|
if (!hasProjectRoleStep)
|
||||||
|
warning = "Должен быть хотя бы один шаг с ролью в проекте.";
|
||||||
|
}
|
||||||
|
|
||||||
return hasProjectRoleStep
|
return ToDto(entity) with { Warning = warning };
|
||||||
? result
|
|
||||||
: result.WithReason(new Warning("Должен быть хотя бы один шаг с ролью в проекте."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TemplateRouteStepDto ToDto(TemplateRouteStep e) => new(
|
private static TemplateRouteStepDto ToDto(TemplateRouteStep e) => new(
|
||||||
|
|||||||
+3
-2
@@ -99,7 +99,8 @@ public sealed class TemplateRouteStepServiceTests : IClassFixture<PostgresDataba
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
created.IsSuccess.ShouldBeTrue();
|
created.IsSuccess.ShouldBeTrue();
|
||||||
created.Reasons.ShouldContain(r => r.Message.Contains("ролью в проекте"));
|
created.Value.Warning.ShouldNotBeNull();
|
||||||
|
created.Value.Warning.ShouldContain("ролью в проекте");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(DisplayName = "Создание шага с ролью в проекте на маршруте «по проекту» не возвращает предупреждение")]
|
[Fact(DisplayName = "Создание шага с ролью в проекте на маршруте «по проекту» не возвращает предупреждение")]
|
||||||
@@ -116,7 +117,7 @@ public sealed class TemplateRouteStepServiceTests : IClassFixture<PostgresDataba
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
created.IsSuccess.ShouldBeTrue();
|
created.IsSuccess.ShouldBeTrue();
|
||||||
created.Reasons.ShouldBeEmpty();
|
created.Value.Warning.ShouldBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(DisplayName = "Обновление шага маршрута изменяет исполнителя, статус и разрешение на переназначение")]
|
[Fact(DisplayName = "Обновление шага маршрута изменяет исполнителя, статус и разрешение на переназначение")]
|
||||||
|
|||||||
Reference in New Issue
Block a user