основной круд готов-
This commit is contained in:
+134
@@ -0,0 +1,134 @@
|
||||
using FluentResults;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Tnsu.ApprovalRoute.Application.Common.Errors;
|
||||
using Tnsu.ApprovalRoute.Domain.Entities;
|
||||
using Tnsu.ApprovalRoute.Domain.Enums;
|
||||
using Tnsu.ApprovalRoute.Infrastructure.Persistence;
|
||||
|
||||
namespace Tnsu.ApprovalRoute.Application.TemplateRouteSteps;
|
||||
|
||||
public sealed record CreateTemplateRouteStepCommand(Guid RouteId, CreateTemplateRouteStepRequest Request)
|
||||
: IRequest<Result<TemplateRouteStepDto>>;
|
||||
|
||||
public sealed record UpdateTemplateRouteStepCommand(Guid RouteId, Guid Id, UpdateTemplateRouteStepRequest Request)
|
||||
: IRequest<Result<TemplateRouteStepDto>>;
|
||||
|
||||
public sealed record DeleteTemplateRouteStepCommand(Guid RouteId, Guid Id) : IRequest<Result>;
|
||||
|
||||
public sealed class CreateTemplateRouteStepHandler(ApprovalRouteDbContext db)
|
||||
: IRequestHandler<CreateTemplateRouteStepCommand, Result<TemplateRouteStepDto>>
|
||||
{
|
||||
public async Task<Result<TemplateRouteStepDto>> Handle(CreateTemplateRouteStepCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var route = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == command.RouteId, cancellationToken);
|
||||
if (route is null)
|
||||
return Result.Fail<TemplateRouteStepDto>(new NotFoundError("Маршрут", command.RouteId));
|
||||
|
||||
var r = command.Request;
|
||||
var fieldsError = TemplateRouteStepValidation.ValidateFields(r.ExecutorEmail, r.Position, r.ProjectRole, route.ByProject);
|
||||
if (fieldsError is not null)
|
||||
return Result.Fail<TemplateRouteStepDto>(fieldsError);
|
||||
|
||||
var entity = new TemplateRouteStep
|
||||
{
|
||||
RouteId = route.Id,
|
||||
OrderNo = r.OrderNo,
|
||||
ExecutorEmail = r.ExecutorEmail,
|
||||
Position = r.Position,
|
||||
ProjectRole = r.ProjectRole,
|
||||
HeadType = r.HeadType,
|
||||
Status = r.Status,
|
||||
AllowReassignToOtherApprovers = r.AllowReassignToOtherApprovers
|
||||
};
|
||||
db.TemplateRouteSteps.Add(entity);
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var result = Result.Ok(TemplateRouteStepMapper.ToDto(entity));
|
||||
return await TemplateRouteStepValidation.AppendMissingProjectRoleWarningAsync(db, route, result, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UpdateTemplateRouteStepHandler(ApprovalRouteDbContext db)
|
||||
: IRequestHandler<UpdateTemplateRouteStepCommand, Result<TemplateRouteStepDto>>
|
||||
{
|
||||
public async Task<Result<TemplateRouteStepDto>> Handle(UpdateTemplateRouteStepCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var route = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == command.RouteId, cancellationToken);
|
||||
if (route is null)
|
||||
return Result.Fail<TemplateRouteStepDto>(new NotFoundError("Маршрут", command.RouteId));
|
||||
|
||||
var entity = await db.TemplateRouteSteps
|
||||
.FirstOrDefaultAsync(x => x.Id == command.Id && x.RouteId == command.RouteId, cancellationToken);
|
||||
if (entity is null)
|
||||
return Result.Fail<TemplateRouteStepDto>(new NotFoundError("Шаг маршрута", command.Id));
|
||||
|
||||
var r = command.Request;
|
||||
var fieldsError = TemplateRouteStepValidation.ValidateFields(r.ExecutorEmail, r.Position, r.ProjectRole, route.ByProject);
|
||||
if (fieldsError is not null)
|
||||
return Result.Fail<TemplateRouteStepDto>(fieldsError);
|
||||
|
||||
entity.OrderNo = r.OrderNo;
|
||||
entity.ExecutorEmail = r.ExecutorEmail;
|
||||
entity.Position = r.Position;
|
||||
entity.ProjectRole = r.ProjectRole;
|
||||
entity.HeadType = r.HeadType;
|
||||
entity.Status = r.Status;
|
||||
entity.AllowReassignToOtherApprovers = r.AllowReassignToOtherApprovers;
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var result = Result.Ok(TemplateRouteStepMapper.ToDto(entity));
|
||||
return await TemplateRouteStepValidation.AppendMissingProjectRoleWarningAsync(db, route, result, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DeleteTemplateRouteStepHandler(ApprovalRouteDbContext db)
|
||||
: IRequestHandler<DeleteTemplateRouteStepCommand, Result>
|
||||
{
|
||||
public async Task<Result> Handle(DeleteTemplateRouteStepCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await db.TemplateRouteSteps
|
||||
.FirstOrDefaultAsync(x => x.Id == request.Id && x.RouteId == request.RouteId, cancellationToken);
|
||||
if (entity is null)
|
||||
return Result.Fail(new NotFoundError("Шаг маршрута", request.Id));
|
||||
|
||||
db.TemplateRouteSteps.Remove(entity);
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Result.Ok();
|
||||
}
|
||||
}
|
||||
|
||||
internal static class TemplateRouteStepValidation
|
||||
{
|
||||
public static IError? ValidateFields(string executorEmail, string position, ProjectRole projectRole, bool routeByProject)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(executorEmail) && string.IsNullOrWhiteSpace(position) && projectRole == ProjectRole.None)
|
||||
return new ValidationError("Исполнитель, должность и роль в проекте не могут быть пустыми одновременно.");
|
||||
|
||||
if (!routeByProject && projectRole != ProjectRole.None)
|
||||
return new ValidationError("Роль в проекте недопустима для шага маршрута, который не учитывает проект (by_project = false).");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<Result<TemplateRouteStepDto>> AppendMissingProjectRoleWarningAsync(
|
||||
ApprovalRouteDbContext db, TemplateRoute route, Result<TemplateRouteStepDto> result, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!route.ByProject)
|
||||
return result;
|
||||
|
||||
var hasProjectRoleStep = await db.TemplateRouteSteps
|
||||
.AnyAsync(x => x.RouteId == route.Id && x.ProjectRole != ProjectRole.None, cancellationToken);
|
||||
|
||||
return hasProjectRoleStep
|
||||
? result
|
||||
: result.WithReason(new Warning("Должен быть хотя бы один шаг с ролью в проекте."));
|
||||
}
|
||||
}
|
||||
|
||||
internal static class TemplateRouteStepMapper
|
||||
{
|
||||
public static TemplateRouteStepDto ToDto(TemplateRouteStep e) => new(
|
||||
e.Id, e.OrderNo, e.ExecutorEmail, e.Position, e.ProjectRole, e.HeadType, e.Status, e.RouteId, e.AllowReassignToOtherApprovers);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Tnsu.ApprovalRoute.Domain.Enums;
|
||||
|
||||
namespace Tnsu.ApprovalRoute.Application.TemplateRouteSteps;
|
||||
|
||||
public sealed record TemplateRouteStepDto(
|
||||
Guid Id,
|
||||
int OrderNo,
|
||||
string ExecutorEmail,
|
||||
string Position,
|
||||
ProjectRole ProjectRole,
|
||||
HeadType HeadType,
|
||||
RouteStepStatus Status,
|
||||
Guid RouteId,
|
||||
bool AllowReassignToOtherApprovers);
|
||||
|
||||
public sealed record CreateTemplateRouteStepRequest(
|
||||
int OrderNo,
|
||||
string ExecutorEmail,
|
||||
string Position,
|
||||
ProjectRole ProjectRole,
|
||||
HeadType HeadType,
|
||||
RouteStepStatus Status,
|
||||
bool AllowReassignToOtherApprovers);
|
||||
|
||||
public sealed record UpdateTemplateRouteStepRequest(
|
||||
int OrderNo,
|
||||
string ExecutorEmail,
|
||||
string Position,
|
||||
ProjectRole ProjectRole,
|
||||
HeadType HeadType,
|
||||
RouteStepStatus Status,
|
||||
bool AllowReassignToOtherApprovers);
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
using FluentResults;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Tnsu.ApprovalRoute.Application.Common.Errors;
|
||||
using Tnsu.ApprovalRoute.Infrastructure.Persistence;
|
||||
|
||||
namespace Tnsu.ApprovalRoute.Application.TemplateRouteSteps;
|
||||
|
||||
public sealed record GetTemplateRouteStepQuery(Guid RouteId, Guid Id) : IRequest<Result<TemplateRouteStepDto>>;
|
||||
|
||||
public sealed record ListTemplateRouteStepsQuery(Guid RouteId) : IRequest<Result<IReadOnlyList<TemplateRouteStepDto>>>;
|
||||
|
||||
public sealed class GetTemplateRouteStepHandler(ApprovalRouteDbContext db)
|
||||
: IRequestHandler<GetTemplateRouteStepQuery, Result<TemplateRouteStepDto>>
|
||||
{
|
||||
public async Task<Result<TemplateRouteStepDto>> Handle(GetTemplateRouteStepQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await db.TemplateRouteSteps.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.Id == request.Id && x.RouteId == request.RouteId, cancellationToken);
|
||||
|
||||
return entity is null
|
||||
? Result.Fail<TemplateRouteStepDto>(new NotFoundError("Шаг маршрута", request.Id))
|
||||
: Result.Ok(TemplateRouteStepMapper.ToDto(entity));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ListTemplateRouteStepsHandler(ApprovalRouteDbContext db)
|
||||
: IRequestHandler<ListTemplateRouteStepsQuery, Result<IReadOnlyList<TemplateRouteStepDto>>>
|
||||
{
|
||||
public async Task<Result<IReadOnlyList<TemplateRouteStepDto>>> Handle(ListTemplateRouteStepsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var items = await db.TemplateRouteSteps.AsNoTracking()
|
||||
.Where(x => x.RouteId == request.RouteId)
|
||||
.OrderBy(x => x.OrderNo)
|
||||
.Select(x => new TemplateRouteStepDto(
|
||||
x.Id, x.OrderNo, x.ExecutorEmail, x.Position, x.ProjectRole, x.HeadType, x.Status, x.RouteId, x.AllowReassignToOtherApprovers))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Ok<IReadOnlyList<TemplateRouteStepDto>>(items);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user