diff --git a/PARR.API/Contracts/V1/Requests/SubprocessRequest.cs b/PARR.API/Contracts/V1/Requests/SubprocessRequest.cs
new file mode 100644
index 00000000..6b91387f
--- /dev/null
+++ b/PARR.API/Contracts/V1/Requests/SubprocessRequest.cs
@@ -0,0 +1,9 @@
+namespace PARR.API.Contracts.V1.Requests
+{
+ public class SubprocessRequest
+ {
+ public required string Name { get; set; }
+ public int EsppId { get; set; }
+ public Guid ProcessId { get; set; }
+ }
+}
diff --git a/PARR.API/Controllers/V1/SubprocessController.cs b/PARR.API/Controllers/V1/SubprocessController.cs
new file mode 100644
index 00000000..af6df569
--- /dev/null
+++ b/PARR.API/Controllers/V1/SubprocessController.cs
@@ -0,0 +1,203 @@
+using AutoMapper;
+using FluentValidation;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using PARR.API.Contracts.V1;
+using PARR.API.Contracts.V1.Requests;
+using PARR.API.Contracts.V1.Requests.Queries;
+using PARR.API.Contracts.V1.Responses;
+using PARR.API.Contracts.V1.Responses.Base;
+using PARR.API.Controllers.V1.Base;
+using PARR.API.Extensions;
+using PARR.API.Services.Interfaces;
+using PARR.Constants;
+using PARR.DAL.DomainModels;
+using PARR.DAL.Models;
+using PARR.DAL.Services.Interfaces;
+
+namespace PARR.API.Controllers.V1
+{
+ ///
+ /// Управление Подпроцессами
+ ///
+ [Authorize(Roles = ParrRoles.Administrator.Role)]
+ public class SubprocessController : BaseApiController
+ {
+ private readonly ILogger logger;
+ private readonly IMapper mapper;
+ private readonly ISubprocessService subprocessService;
+ private readonly IValidator validator;
+ private readonly IUriService uriService;
+
+ public SubprocessController(
+ ILogger logger,
+ IMapper mapper,
+ ISubprocessService subprocessService,
+ IValidator validator,
+ IUriService uriService
+ )
+ {
+ this.logger = logger;
+ this.mapper = mapper;
+ this.subprocessService = subprocessService;
+ this.validator = validator;
+ this.uriService = uriService;
+ }
+
+
+ ///
+ /// Создать подпроцесс
+ ///
+ ///
+ ///
+ [HttpPost(ApiRoutes.Subprocess.Create)]
+ public async Task Create([FromBody] SubprocessRequest request)
+ {
+ var resultValidate = await validator.ValidateAsync(request);
+ if (!resultValidate.IsValid)
+ return BadRequest(new Response(resultValidate.Errors));
+
+ var existName = await subprocessService.Get().FirstOrDefaultAsync(t => t.Name == request.Name);
+ if (existName != null)
+ return BadRequest(new Response(false, new List { new ErrorModel { FieldName = nameof(request.Name), Message = $"Подпроцесс с именем \"{request.Name}\" уже существует." } }));
+
+ var subprocess = new Subprocess
+ {
+ Id = Guid.NewGuid(),
+ Name = request.Name,
+ EsppId = request.EsppId,
+ ProcessId = request.ProcessId,
+ };
+
+ if (!await subprocessService.CreateAsync(subprocess) || !await subprocessService.CommitAsync())
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при записи нового подпроцесса в базу данных" } }));
+
+ logger.LogInformation($"Пользователь {User.Identity?.Name} добавил подпроцесс: {subprocess.Name}, {subprocess.EsppId}, {subprocess.ProcessId}");
+
+ var locationUri = uriService.GetUri(ApiRoutes.Subprocess.Get, ApiRoutes.Subprocess.getParam, subprocess.Id);
+
+ return Created(locationUri, new Response(mapper.Map(subprocess), true));
+ }
+
+
+ ///
+ /// Список подпроцессов постранично
+ ///
+ ///
+ ///
+ [HttpGet(ApiRoutes.Subprocess.GetAll)]
+ public async Task GetAll([FromQuery] PaginationQuery paginationQuery)
+ {
+ var paginationFilter = mapper.Map(paginationQuery);
+
+ IQueryable query = subprocessService.Get()
+ .OrderBy(t => t.Name);
+
+ var subprocesses = await subprocessService.GetPage(query, paginationFilter).ToListAsync();
+
+ if (!subprocesses.Any())
+ return NoContent();
+
+ var subprocessesResponse = mapper.Map>(subprocesses);
+ var paginationResponse = new PagedResponse(subprocessesResponse, true).GetPaginatedProps(paginationFilter, query);
+
+ return Ok(paginationResponse);
+ }
+
+
+ ///
+ /// Получить подпроцесс по id
+ ///
+ ///
+ ///
+ [HttpGet(ApiRoutes.Subprocess.Get)]
+ public async Task GetById([FromRoute] Guid id)
+ {
+ var subprocess = await subprocessService.Get()
+ .FirstOrDefaultAsync(t => t.Id == id);
+
+ if (subprocess == null)
+ return NotFound();
+
+ var response = mapper.Map(subprocess);
+
+ return Ok(new Response(response, true));
+ }
+
+
+ ///
+ /// Получить связанные с подпроцессом ТНК
+ ///
+ ///
+ ///
+ [HttpGet(ApiRoutes.Subprocess.GetTnks)]
+ public async Task Get([FromRoute] Guid id)
+ {
+ var subprocess = await subprocessService.Get()
+ .Include(t => t.Tnks)
+ .FirstOrDefaultAsync(t => t.Id == id);
+
+ if (subprocess == null)
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Не найден подпроцесс с id: {id}" } }));
+
+ var response = mapper.Map>(subprocess.Tnks.OrderBy(t => t.Name).ToList());
+
+ return Ok(new Response>(response, true));
+ }
+
+
+ ///
+ /// Обновить подпроцесс
+ ///
+ ///
+ ///
+ ///
+ [HttpPut(ApiRoutes.Subprocess.Update)]
+ public async Task Update([FromRoute] Guid id, [FromBody] SubprocessRequest request)
+ {
+ var resultValidate = await validator.ValidateAsync(request);
+ if (!resultValidate.IsValid)
+ return BadRequest(new Response(resultValidate.Errors));
+
+ var orig = await subprocessService.Get()
+ .FirstOrDefaultAsync(t => t.Id == id);
+
+ if (orig == null)
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении подпроцесса. Не найдена подпроцесс Id: {id}" } }));
+
+ orig.Name = request.Name;
+ orig.EsppId = request.EsppId;
+ orig.ProcessId = request.ProcessId;
+
+ if (!await subprocessService.CommitAsync())
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка записи в базу данных изменений подпроцесса." } }));
+
+ logger.LogInformation($"Пользователь {User.Identity?.Name} обновил подпроцесс: {orig.Id}, {orig.Name}, {orig.EsppId}, {orig.ProcessId}");
+
+ return Ok(new Response(mapper.Map(orig), true));
+ }
+
+
+ ///
+ /// Удалить подпроцесс
+ ///
+ ///
+ ///
+ [HttpDelete(ApiRoutes.Subprocess.Delete)]
+ public async Task Delete([FromRoute] Guid id)
+ {
+ var subprocess = await subprocessService.GetAsync(id);
+
+ if (subprocess == null)
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении подпроцесса. Не найден подпроцесс Id: {id}" } }));
+
+ if (!subprocessService.Delete(subprocess) || !await subprocessService.CommitAsync())
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении подпроцесса из базы данных" } }));
+
+ logger.LogInformation($"Пользователь {User.Identity?.Name} удалил подпроцесс: {subprocess.Id}, {subprocess.Name}, {subprocess.EsppId}, {subprocess.ProcessId}");
+
+ return NoContent();
+ }
+ }
+}
diff --git a/PARR.API/Controllers/V1/TnkController.cs b/PARR.API/Controllers/V1/TnkController.cs
index 09e6084f..7d58c368 100644
--- a/PARR.API/Controllers/V1/TnkController.cs
+++ b/PARR.API/Controllers/V1/TnkController.cs
@@ -1,21 +1,20 @@
using AutoMapper;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests;
using PARR.API.Contracts.V1.Requests.Queries;
-using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Contracts.V1.Responses;
+using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base;
+using PARR.API.Extensions;
using PARR.API.Services.Interfaces;
using PARR.Constants;
using PARR.DAL.DomainModels;
-using PARR.DAL.Services.Interfaces;
using PARR.DAL.Models;
-using Microsoft.EntityFrameworkCore;
-using PARR.API.Extensions;
+using PARR.DAL.Services.Interfaces;
namespace PARR.API.Controllers.V1
{
@@ -74,7 +73,7 @@ namespace PARR.API.Controllers.V1
if (!await tnkService.CreateAsync(tnk) || !await tnkService.CommitAsync())
return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при записи новой ТНК в базу данных" } }));
- logger.LogInformation($"Пользователь {User.Identity?.Name} добавил вид работ: {tnk.Name}, {tnk.EsppId}, {tnk.SubprocessId}");
+ logger.LogInformation($"Пользователь {User.Identity?.Name} добавил ТНК: {tnk.Name}, {tnk.EsppId}, {tnk.SubprocessId}");
var locationUri = uriService.GetUri(ApiRoutes.Tnk.Get, ApiRoutes.Tnk.getParam, tnk.Id);
@@ -93,7 +92,6 @@ namespace PARR.API.Controllers.V1
var paginationFilter = mapper.Map(paginationQuery);
IQueryable query = tnkService.Get()
- //.Include(t=>t.Subprocess).ThenInclude(t=>t.Process)
.OrderBy(t => t.Name);
var tnks = await tnkService.GetPage(query, paginationFilter).ToListAsync();
@@ -143,7 +141,7 @@ namespace PARR.API.Controllers.V1
if (tnk == null)
return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Не найдена ТНК с id: {id}" } }));
- var response = mapper.Map>(tnk.Works.OrderBy(t=>t.Name).ToList());//Roles.Select(t => t.Role)).OrderBy(t => t.Description).ToList();
+ var response = mapper.Map>(tnk.Works.OrderBy(t => t.Name).ToList());
return Ok(new Response>(response, true));
}
diff --git a/PARR.API/Validators/SubprocessValidator.cs b/PARR.API/Validators/SubprocessValidator.cs
new file mode 100644
index 00000000..062cf49d
--- /dev/null
+++ b/PARR.API/Validators/SubprocessValidator.cs
@@ -0,0 +1,40 @@
+using FluentValidation;
+using PARR.API.Contracts.V1.Requests;
+using PARR.DAL.Services.Interfaces;
+
+namespace PARR.API.Validators
+{
+ public class SubprocessValidator : AbstractValidator
+ {
+ private readonly IProcessService processService;
+ private bool? isValid = null;
+
+ public SubprocessValidator(
+ IProcessService processService
+ )
+ {
+ this.processService = processService;
+
+ RuleFor(t => t.Name).NotEmpty().NotNull().WithMessage("Имя подпроцесса не может быть пустым");
+
+ RuleFor(t => t.EsppId).NotEmpty().NotNull().WithMessage("EsppId не может быть пустым");
+
+ RuleFor(t => t.ProcessId).NotEmpty().NotNull().WithMessage("Подпроцесс должна быть связан с процессом. ProcessId не может быть пустым");
+
+ RuleFor(t => t.ProcessId)
+ .MustAsync(async (entity, value, c) => await IsProcessExist(entity))
+ .WithMessage("У данного подпроцесса указан несуществующий Id процесса");
+ }
+
+ private async Task IsProcessExist(SubprocessRequest request)
+ {
+ //чтобы не делать 2 раза валидацию
+ if (isValid.HasValue)
+ return isValid.Value;
+
+ isValid = await processService.GetAsync(request.ProcessId) != null;
+
+ return isValid.Value;
+ }
+ }
+}