diff --git a/AsbCloudWebApi/Controllers/WellSections/WellSectionPlanController.cs b/AsbCloudWebApi/Controllers/WellSections/WellSectionPlanController.cs
new file mode 100644
index 00000000..68167edb
--- /dev/null
+++ b/AsbCloudWebApi/Controllers/WellSections/WellSectionPlanController.cs
@@ -0,0 +1,168 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using AsbCloudApp.Data;
+using AsbCloudApp.Data.ProcessMaps;
+using AsbCloudApp.Data.WellSections;
+using AsbCloudApp.Exceptions;
+using AsbCloudApp.Services;
+using AsbCloudApp.Services.WellSections;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace AsbCloudWebApi.Controllers.WellSections;
+
+///
+/// Конструкция скважины - план
+///
+[ApiController]
+[Route("api/well/{idWell:int}/[controller]")]
+[Authorize]
+public class WellSectionPlanController : ControllerBase
+{
+ private readonly IWellSectionPlanService wellSectionPlanService;
+ private readonly IWellService wellService;
+ private readonly ICrudRepository wellSectionRepository;
+ private readonly IRepositoryWellRelated wellSectionPlanRepository;
+
+ public WellSectionPlanController(IWellSectionPlanService wellSectionPlanService,
+ IWellService wellService,
+ ICrudRepository wellSectionRepository,
+ IRepositoryWellRelated wellSectionPlanRepository)
+ {
+ this.wellSectionPlanService = wellSectionPlanService;
+ this.wellService = wellService;
+ this.wellSectionRepository = wellSectionRepository;
+ this.wellSectionPlanRepository = wellSectionPlanRepository;
+ }
+
+ //TODO: так же следует вынести в базовый контроллер
+ private int IdUser
+ {
+ get
+ {
+ var idUser = User.GetUserId();
+
+ if (!idUser.HasValue)
+ throw new ForbidException("Неизвестный пользователь");
+
+ return idUser.Value;
+ }
+ }
+
+ ///
+ /// Добавить секцию
+ ///
+ /// Идентификатор скважины
+ /// Секция скважины - план
+ ///
+ ///
+ [HttpPost]
+ [Permission]
+ [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ public async Task InsertAsync(int idWell, WellSectionPlanDto wellSection, CancellationToken cancellationToken)
+ {
+ wellSection.IdWell = idWell;
+ wellSection.IdUser = IdUser;
+
+ await CheckIsExistsWellSectionTypeAsync(wellSection.IdSectionType, cancellationToken);
+
+ await AssertUserAccessToWell(idWell, cancellationToken);
+
+ var wellSectionId = await wellSectionPlanService.InsertAsync(wellSection, cancellationToken);
+
+ return Ok(wellSectionId);
+ }
+
+ ///
+ /// Обновить секцию
+ ///
+ /// Идентификатор скважины
+ /// Секция скважины - план
+ ///
+ ///
+ [HttpPut]
+ [Permission]
+ [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ public async Task UpdateAsync(int idWell, WellSectionPlanDto wellSection, CancellationToken cancellationToken)
+ {
+ wellSection.IdWell = idWell;
+ wellSection.IdUser = IdUser;
+
+ await CheckIsExistsWellSectionTypeAsync(wellSection.IdSectionType, cancellationToken);
+
+ await AssertUserAccessToWell(idWell, cancellationToken);
+
+ var wellSectionId = await wellSectionPlanService.UpdateAsync(wellSection, cancellationToken);
+
+ if (wellSectionId == ICrudRepository.ErrorIdNotFound)
+ return this.ValidationBadRequest(nameof(wellSection.Id), $"Секции скважины с Id: {wellSection.Id} не существует");
+
+ return Ok(wellSectionId);
+ }
+
+ ///
+ /// Получить типы секций
+ ///
+ /// Идентификатор скважины
+ ///
+ ///
+ [HttpGet]
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ public async Task GetWellSectionTypesAsync(int idWell, CancellationToken cancellationToken)
+ {
+ await AssertUserAccessToWell(idWell, cancellationToken);
+
+ var wellSectionTypes = await wellSectionPlanService.GetWellSectionTypesAsync(idWell, cancellationToken);
+
+ if (!wellSectionTypes.Any())
+ return NoContent();
+
+ return Ok(wellSectionTypes);
+ }
+
+ ///
+ /// Удалить секцию
+ ///
+ /// Идентификатор скважины
+ /// Идентификатор плановой секции
+ ///
+ ///
+ [HttpDelete]
+ [Permission]
+ [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ public async Task DeleteAsync(int idWell, int id, CancellationToken cancellationToken)
+ {
+ await AssertUserAccessToWell(idWell, cancellationToken);
+
+ var deletedWellSectionPlanCount = await wellSectionPlanRepository.DeleteAsync(id, cancellationToken);
+
+ return Ok(deletedWellSectionPlanCount);
+ }
+
+ //TODO: нужно создать базовый контроллер связанный со скважиной и вынести этот метод туда. Данный метод много где дублируется
+ private async Task AssertUserAccessToWell(int idWell, CancellationToken cancellationToken)
+ {
+ var idCompany = User.GetCompanyId();
+
+ if (!idCompany.HasValue || !await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, cancellationToken))
+ throw new ForbidException("Нет доступа к скважине");
+ }
+
+ //TODO: тоже нужно вынести в базовый контроллер
+ private async Task CheckIsExistsWellSectionTypeAsync(int idWellSectionType, CancellationToken cancellationToken)
+ {
+ _ = await wellSectionRepository.GetOrDefaultAsync(idWellSectionType, cancellationToken)
+ ?? throw new ArgumentInvalidException(nameof(ProcessMapPlanWellDrillingDto.IdWellSectionType),
+ $"Тип секции с Id: {idWellSectionType} не найден");
+ }
+}
\ No newline at end of file