using AsbCloudApp.Data; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.WellOperation; using AsbCloudApp.Requests.ExportOptions; using AsbCloudApp.Requests.ParserOptions; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.WellOperations.Factories; using System.Linq; namespace AsbCloudWebApi.Controllers; /// /// Буровые операции (вводимые вручную) /// [Route("api/well/{idWell}/wellOperations")] [ApiController] [Authorize] public class WellOperationController : ControllerBase { private readonly IDictionary templateNames = new Dictionary { { WellOperation.IdOperationTypeFact, "ЕЦП_шаблон_файла_фактические_операции.xlsx" }, { WellOperation.IdOperationTypePlan, "ЕЦП_шаблон_файла_плановые_операции.xlsx" } }; private readonly IUserRepository userRepository; private readonly IWellOperationRepository wellOperationRepository; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; private readonly IWellService wellService; private readonly IWellOperationService wellOperationService; private readonly WellOperationParserFactory wellOperationParserFactory; private readonly WellOperationExportServiceFactory wellOperationExportServiceFactory; public WellOperationController(IWellOperationRepository wellOperationRepository, IWellOperationCategoryRepository wellOperationCategoryRepository, IWellService wellService, IUserRepository userRepository, WellOperationParserFactory wellOperationParserFactory, WellOperationExportServiceFactory wellOperationExportServiceFactory, IWellOperationService wellOperationService) { this.wellOperationRepository = wellOperationRepository; this.wellOperationCategoryRepository = wellOperationCategoryRepository; this.wellService = wellService; this.userRepository = userRepository; this.wellOperationParserFactory = wellOperationParserFactory; this.wellOperationExportServiceFactory = wellOperationExportServiceFactory; this.wellOperationService = wellOperationService; } /// /// Добавляет новые операции на скважине /// /// Id скважины /// Добавляемые операции /// Удалить операции перед сохранением /// /// Количество добавленных в БД записей [HttpPost("{deleteBeforeInsert:bool}")] [Permission] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task InsertRangeAsync( [Range(1, int.MaxValue, ErrorMessage = "Id скважины не может быть меньше 1")] int idWell, bool deleteBeforeInsert, [FromBody] IEnumerable dtos, CancellationToken cancellationToken) { if (!await CanUserAccessToWellAsync(idWell, cancellationToken)) return Forbid(); if (!await CanUserEditWellOperationsAsync(idWell, cancellationToken)) return Forbid(); foreach (var dto in dtos) { dto.IdWell = idWell; dto.LastUpdateDate = null; dto.IdUser = User.GetUserId(); } var result = await wellOperationRepository.InsertRangeAsync(dtos, deleteBeforeInsert, cancellationToken); return Ok(result); } /// /// Обновляет выбранную операцию на скважине /// /// id скважины /// /// Токен отмены задачи /// Количество обновленных в БД строк [HttpPut] [Permission] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] public async Task UpdateRangeAsync(int idWell, [FromBody] IEnumerable dtos, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); foreach (var dto in dtos) { dto.IdWell = idWell; dto.IdUser = User.GetUserId(); dto.LastUpdateDate = DateTimeOffset.UtcNow; } var result = await wellOperationRepository.UpdateRangeAsync(dtos, token); return Ok(result); } /// /// Возвращает словарь типов секций /// /// [HttpGet("sectionTypes")] [Permission] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public IActionResult GetSectionTypes() { var result = wellOperationRepository.GetSectionTypes(); return Ok(result); } /// /// Статистика операций по скважине, группированная по категориям /// /// id скважины /// /// /// [HttpGet("groupStat")] [Permission] [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] public async Task GetGroupOperationsAsync( [FromRoute] int idWell, [FromQuery] WellOperationRequestBase request, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) return Forbid(); var requestToservice = new WellOperationRequest(request, new[] { idWell }); var result = await wellOperationService.GetGroupOperationsStatAsync(requestToservice, token); return Ok(result); } /// /// Возвращает список имен типов операций на скважине /// /// флаг, нужно ли включать родителей в список /// [HttpGet("categories")] [Permission] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public IActionResult GetCategories(bool includeParents = true) { var result = wellOperationCategoryRepository.Get(includeParents, false); return Ok(result); } /// /// Постраничный список операций на скважине. /// /// id скважины /// /// /// Список операций на скважине [HttpGet] [Permission] [ProducesResponseType(typeof(PaginationContainer), StatusCodes.Status200OK)] public async Task GetPageAsync( [FromRoute] int idWell, [FromQuery] WellOperationRequestBase request, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); var requestToService = new WellOperationRequest(request, new[] { idWell }); var result = await wellOperationService.GetPageAsync(requestToService, token); return Ok(result); } /// /// Получение страницу с нужной операцией /// /// id скважины /// id операции /// тип получаемых операций /// кол-во записей на странице /// параметры сортировки страниц /// /// [HttpGet("getPageWithOperation")] [Permission] [ProducesResponseType(typeof(PaginationContainer), StatusCodes.Status200OK)] public async Task GetPageWithOperationAsync([FromRoute] int idWell, int id, int operationType, int? take, [FromQuery] IEnumerable? sortFields, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); var paginationContainer = await wellOperationService.GetPageAsync(idWell, id, operationType, take, sortFields, token); if (paginationContainer == null) return NoContent(); return Ok(paginationContainer); } /// /// Создает excel файл с "сетевым графиком" /// /// id скважины /// /// /// Запрашиваемый файл [HttpGet("scheduleReport")] [Permission] [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK)] public async Task ScheduleReportAsync([FromRoute] int idWell, [FromServices] IScheduleReportService scheduleReportService, CancellationToken token) { var idCompany = User.GetCompanyId(); if (idCompany is null) return Forbid(); if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token)) return Forbid(); var stream = await scheduleReportService.MakeReportAsync(idWell, token); var fileName = await wellService.GetWellCaptionByIdAsync(idWell, token) + "_ScheduleReport.xlsx"; return File(stream, "application/octet-stream", fileName); } /// /// Удаляет выбранную операцию на скважине /// /// id скважины /// id выбранной операции /// Токен отмены задачи /// Количество удаленных из БД строк [HttpDelete("{idOperation}")] [Permission] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] public async Task DeleteAsync(int idWell, int idOperation, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); var result = await wellOperationRepository.DeleteRangeAsync(new[] { idOperation }, token); return Ok(result); } /// /// Удаляет выбранные операции по скважине /// /// id скважины /// ids выбранных операций /// Токен отмены задачи /// Количество удаленных из БД строк [HttpDelete] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task DeleteRangeAsync([FromRoute] int idWell, IEnumerable ids, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); if (!ids.Any()) return this.ValidationBadRequest(nameof(ids), "Пустой список операций"); var result = await wellOperationRepository.DeleteRangeAsync(ids, token); if(result == ICrudRepository.ErrorIdNotFound) return this.ValidationBadRequest(nameof(ids), "Минимум одна из операций не найдена в базе"); return Ok(result); } /// /// Формирование excel файла с операциями на скважине /// /// /// /// /// [HttpGet("export")] [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")] public async Task ExportAsync(int idWell, int idType, CancellationToken token) { var options = new WellOperationExportRequest(idWell, idType); var exportService = wellOperationExportServiceFactory.CreateExportService(idType); var (fileName, file) = await exportService.ExportAsync(options, token); return File(file, "application/octet-stream", fileName); } /// /// Парсинг ГГД из excel (xlsx) файла /// /// /// /// /// /// [HttpPost("parse/{idType}")] [Permission] [ProducesResponseType(typeof(ParserResultDto), StatusCodes.Status200OK)] public async Task ParseAsync(int idWell, int idType, [Required] IFormFile file, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); var stream = file.GetExcelFile(); try { var timezone = wellService.GetTimezone(idWell); var options = new WellOperationParserRequest(idWell, idType, timezone); var parser = wellOperationParserFactory.CreateParser(idType); var result = parser.Parse(stream, options); return Ok(result); } catch (FileFormatException ex) { return this.ValidationBadRequest(nameof(file), ex.Message); } } /// /// Получение шаблона для заполнения ГГД /// /// [HttpGet("template")] [AllowAnonymous] [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")] public IActionResult GetTemplate(int idType) { var parser = wellOperationParserFactory.CreateParser(idType); var stream = parser.GetTemplateFile(); return File(stream, "application/octet-stream", templateNames[idType]); } private async Task CanUserAccessToWellAsync(int idWell, CancellationToken token) { var idCompany = User.GetCompanyId(); return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token).ConfigureAwait(false); } private async Task CanUserEditWellOperationsAsync(int idWell, CancellationToken token) { var idUser = User.GetUserId(); if (!idUser.HasValue) return false; var well = await wellService.GetOrDefaultAsync(idWell, token); if (well is null) return false; return well.IdState != 2 || userRepository.HasPermission(idUser.Value, "WellOperation.editCompletedWell"); } }