diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs
index b801ff53..d0436b9c 100644
--- a/PARR.API/Contracts/V1/ApiRoutes.cs
+++ b/PARR.API/Contracts/V1/ApiRoutes.cs
@@ -222,6 +222,66 @@ namespace PARR.API.Contracts.V1
public const string getParam = "{id}";
}
+ #endregion
+
+
+ #region TNK
+
+ public static class Process
+ {
+ public const string GetAll = Base + "/processes/";
+ public const string Get = Base + "/processes/" + getParam;
+
+ public const string GetSubprcesses = Base + "/processes/" + getParam + "/subprocesses";
+
+ public const string Delete = Base + "/processes/" + getParam;
+ public const string Create = Base + "/processes/";
+ public const string Update = Base + "/processes/" + getParam;
+
+ public const string getParam = "{id}";
+ }
+
+ public static class Subprocess
+ {
+ public const string GetAll = Base + "/subprocesses/";
+ public const string Get = Base + "/subprocesses/" + getParam;
+
+ public const string GetTnks = Base + "/subprocesses/" + getParam + "/tnks";
+
+ public const string Delete = Base + "/subprocesses/" + getParam;
+ public const string Create = Base + "/subprocesses/";
+ public const string Update = Base + "/subprocesses/" + getParam;
+
+ public const string getParam = "{id}";
+ }
+
+ public static class Tnk
+ {
+ public const string GetAll = Base + "/tnks/";
+ public const string Get = Base + "/tnks/" + getParam;
+
+ public const string GetWorks = Base + "/tnks/" + getParam + "/works";
+
+ public const string Delete = Base + "/tnks/" + getParam;
+ public const string Create = Base + "/tnks/";
+ public const string Update = Base + "/tnks/" + getParam;
+
+ public const string getParam = "{id}";
+ }
+
+ public static class Work
+ {
+ public const string GetAll = Base + "/works/";
+ public const string Get = Base + "/works/" + getParam;
+ public const string Delete = Base + "/works/" + getParam;
+ public const string Create = Base + "/works/";
+ public const string Update = Base + "/works/" + getParam;
+
+ public const string getParam = "{id}";
+ }
+
+
+
#endregion
}
diff --git a/PARR.API/Contracts/V1/Requests/WorkRequest.cs b/PARR.API/Contracts/V1/Requests/WorkRequest.cs
new file mode 100644
index 00000000..836d1d31
--- /dev/null
+++ b/PARR.API/Contracts/V1/Requests/WorkRequest.cs
@@ -0,0 +1,9 @@
+namespace PARR.API.Contracts.V1.Requests
+{
+ public class WorkRequest
+ {
+ public required string Name { get; set; }
+ public int EsppId { get; set; }
+ public Guid TnkId { get; set; }
+ }
+}
diff --git a/PARR.API/Controllers/V1/WorkController.cs b/PARR.API/Controllers/V1/WorkController.cs
new file mode 100644
index 00000000..8ba3b89e
--- /dev/null
+++ b/PARR.API/Controllers/V1/WorkController.cs
@@ -0,0 +1,183 @@
+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 WorkController : BaseApiController
+ {
+ private readonly ILogger logger;
+ private readonly IMapper mapper;
+ private readonly IWorkService workService;
+ private readonly IValidator validator;
+ private readonly IUriService uriService;
+
+ public WorkController(
+ ILogger logger,
+ IMapper mapper,
+ IWorkService workService,
+ IValidator validator,
+ IUriService uriService
+ )
+ {
+ this.logger = logger;
+ this.mapper = mapper;
+ this.workService = workService;
+ this.validator = validator;
+ this.uriService = uriService;
+ }
+
+
+ ///
+ /// Список видов работ постранично
+ ///
+ ///
+ ///
+ [HttpGet(ApiRoutes.Work.GetAll)]
+ public async Task GetAll([FromQuery] PaginationQuery paginationQuery)
+ {
+ var paginationFilter = mapper.Map(paginationQuery);
+
+ IQueryable query = workService.Get()
+ .OrderBy(t => t.Name);
+
+ var works = await workService.GetPage(query, paginationFilter).ToListAsync();
+
+ if (!works.Any())
+ return NoContent();
+
+ var workResponse = mapper.Map>(works);
+ var paginationResponse = new PagedResponse(workResponse, true).GetPaginatedProps(paginationFilter, query);
+
+ return Ok(paginationResponse);
+ }
+
+
+ ///
+ /// Создать вид работы
+ ///
+ ///
+ ///
+ [HttpPost(ApiRoutes.Work.Create)]
+ public async Task Create([FromBody] WorkRequest request)
+ {
+ var resultValidate = await validator.ValidateAsync(request);
+ if (!resultValidate.IsValid)
+ return BadRequest(new Response(resultValidate.Errors));
+
+ var existName = await workService.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 work = new Work
+ {
+ Id = Guid.NewGuid(),
+ Name = request.Name,
+ EsppId = request.EsppId,
+ TnkId = request.TnkId,
+ };
+
+ if (!await workService.CreateAsync(work) || !await workService.CommitAsync())
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при создании вида работ." } }));
+
+ logger.LogInformation($"Пользователь {User.Identity?.Name} добавил вид работ: {work.Name}, {work.EsppId}, {work.TnkId}");
+
+ var locationUri = uriService.GetUri(ApiRoutes.Work.Get, ApiRoutes.Work.getParam, work.Id);
+
+ return Created(locationUri, new Response(mapper.Map(work), true));
+ }
+
+
+ ///
+ /// Получить работу по id
+ ///
+ ///
+ ///
+ [HttpGet(ApiRoutes.Work.Get)]
+ public async Task GetById([FromRoute] Guid id)
+ {
+ var work = await workService.Get()
+ .FirstOrDefaultAsync(t => t.Id == id);
+
+ if (work == null)
+ return NotFound();
+
+ var response = mapper.Map(work);
+
+ return Ok(new Response(response, true));
+ }
+
+
+ ///
+ /// Обновить вид работ
+ ///
+ ///
+ ///
+ ///
+ [HttpPut(ApiRoutes.Work.Update)]
+ public async Task Update([FromRoute] Guid id, [FromBody] WorkRequest request)
+ {
+ var resultValidate = await validator.ValidateAsync(request);
+ if (!resultValidate.IsValid)
+ return BadRequest(new Response(resultValidate.Errors));
+
+ var orig = await workService.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.TnkId = request.TnkId;
+
+ if (!await workService.CommitAsync())
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка записи в базу данных изменений вида работ." } }));
+
+ logger.LogInformation($"Пользователь {User.Identity?.Name} обновил работу: {orig.Id}, {orig.Name}, {orig.EsppId}, {orig.TnkId}");
+
+ return Ok(new Response(mapper.Map(orig), true));
+ }
+
+
+ ///
+ /// Удалить вид работ
+ ///
+ ///
+ ///
+ [HttpDelete(ApiRoutes.Work.Delete)]
+ public async Task Delete([FromRoute] Guid id)
+ {
+ var work = await workService.GetAsync(id);
+
+ if (work == null)
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении вида работ. Не найдена работа с id: {id}" } }));
+
+ if (!workService.Delete(work) || !await workService.CommitAsync())
+ return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении вида работ." } }));
+
+ logger.LogInformation($"Пользователь {User.Identity?.Name} удалил вид работ: {work.Id}, {work.Name}, {work.EsppId}, {work.TnkId}");
+
+ return NoContent();
+ }
+
+ }
+}
diff --git a/PARR.API/Validators/WorkRequestValidator.cs b/PARR.API/Validators/WorkRequestValidator.cs
new file mode 100644
index 00000000..e0161c55
--- /dev/null
+++ b/PARR.API/Validators/WorkRequestValidator.cs
@@ -0,0 +1,42 @@
+using FluentValidation;
+using PARR.API.Contracts.V1.Requests;
+using PARR.DAL.Services.Interfaces;
+
+namespace PARR.API.Validators
+{
+ public class WorkRequestValidator : AbstractValidator
+ {
+ private readonly ITnkService tnkService;
+
+ private bool? isValid = null;
+
+ public WorkRequestValidator(
+ ITnkService tnkService
+ )
+ {
+ this.tnkService = tnkService;
+
+ RuleFor(t => t.Name).NotEmpty().NotNull().WithMessage("Имя работ не может быть пустым");
+
+ RuleFor(t => t.EsppId).NotEmpty().NotNull().WithMessage("EsppId не может быть пустым");
+
+ RuleFor(t => t.TnkId).NotEmpty().NotNull().WithMessage("Работа должна быть связана с ТНК. TnkId не может быть пустым");
+
+ RuleFor(t => t.TnkId)
+ .MustAsync(async (entity, value, c) => await IsTnkExist(entity))
+ .WithMessage("У данной работы указан не существующий Id ТНК");
+ }
+
+ private async Task IsTnkExist(WorkRequest request)
+ {
+ //чтобы не делать 2 раза валидацию
+ if (isValid.HasValue)
+ return isValid.Value;
+
+ isValid = await tnkService.GetAsync(request.TnkId) != null;
+
+ return isValid.Value;
+ }
+
+ }
+}