DD.WellWorkover.Cloud/AsbCloudWebApi/Controllers/WellOperationController.cs
Степанов Дмитрий a2da2c912f Фикс
2023-12-08 15:56:00 +05:00

581 lines
27 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperationImport;
using AsbCloudApp.Services.WellOperationImport;
using AsbCloudApp.Data.WellOperationImport.Options;
using AsbCloudApp.Exceptions;
using AsbCloudDb.Model;
using AsbCloudInfrastructure;
namespace AsbCloudWebApi.Controllers
{
/// <summary>
/// Буровые операции (вводимые вручную)
/// </summary>
[Route("api/well/{idWell}/wellOperations")]
[ApiController]
[Authorize]
public class WellOperationController : ControllerBase
{
private readonly IWellOperationRepository operationRepository;
private readonly IWellService wellService;
private readonly IWellOperationExportService wellOperationExportService;
private readonly IWellOperationImportTemplateService wellOperationImportTemplateService;
private readonly IWellOperationImportService wellOperationImportService;
private readonly IWellOperationExcelParser<WellOperationImportDefaultOptionsDto> wellOperationDefaultExcelParser;
private readonly IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto> wellOperationGazpromKhantosExcelParser;
private readonly IUserRepository userRepository;
public WellOperationController(IWellOperationRepository operationRepository,
IWellService wellService,
IWellOperationImportTemplateService wellOperationImportTemplateService,
IWellOperationExportService wellOperationExportService,
IWellOperationImportService wellOperationImportService,
IWellOperationExcelParser<WellOperationImportDefaultOptionsDto> wellOperationDefaultExcelParser,
IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto> wellOperationGazpromKhantosExcelParser,
IUserRepository userRepository)
{
this.operationRepository = operationRepository;
this.wellService = wellService;
this.wellOperationImportTemplateService = wellOperationImportTemplateService;
this.wellOperationExportService = wellOperationExportService;
this.wellOperationImportService = wellOperationImportService;
this.wellOperationDefaultExcelParser = wellOperationDefaultExcelParser;
this.wellOperationGazpromKhantosExcelParser = wellOperationGazpromKhantosExcelParser;
this.userRepository = userRepository;
}
/// <summary>
/// Возвращает словарь типов секций
/// </summary>
/// <returns></returns>
[HttpGet("sectionTypes")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<WellSectionTypeDto>), (int)System.Net.HttpStatusCode.OK)]
public IActionResult GetSectionTypes()
{
var result = operationRepository.GetSectionTypes();
return Ok(result);
}
/// <summary>
/// Возвращает список имен типов операций на скважине
/// </summary>
/// <param name="includeParents">флаг, нужно ли включать родителей в список</param>
/// <returns></returns>
[HttpGet("categories")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<WellOperationCategoryDto>), (int)System.Net.HttpStatusCode.OK)]
public IActionResult GetCategories(bool includeParents = true)
{
var result = operationRepository.GetCategories(includeParents);
return Ok(result);
}
/// <summary>
/// Возвращает список плановых операций для сопоставления
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="currentDate">дата для нахождения последней сопоставленной плановой операции</param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("operationsPlan")]
[ProducesResponseType(typeof(WellOperationPlanDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetOperationsPlanAsync(
[FromRoute] int idWell,
[FromQuery] DateTime currentDate,
CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var result = await operationRepository
.GetOperationsPlanAsync(idWell, currentDate, token)
.ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Отфильтрованный список фактических операций на скважине.
/// Если не применять фильтр, то вернется весь список. Сортированный по глубине затем по дате
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns>Список операций на скважине</returns>
[HttpGet("fact")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetPageOperationsFactAsync(
[FromRoute] int idWell,
[FromQuery] WellOperationRequestBase request,
CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var requestToService = new WellOperationRequest(request, idWell);
var result = await operationRepository.GetAsync(
requestToService,
token)
.ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Отфильтрованный список плановых операций на скважине.
/// Если не применять фильтр, то вернется весь список. Сортированный по глубине затем по дате
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns>Список операций на скважине в контейнере для постраничного просмотра</returns>
[HttpGet("plan")]
[Permission]
[ProducesResponseType(typeof(PaginationContainer<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetPageOperationsPlanAsync(
[FromRoute] int idWell,
[FromQuery] WellOperationRequestBase request,
CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var requestToService = new WellOperationRequest(request, idWell);
var result = await operationRepository.GetPageAsync(
requestToService,
token)
.ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Статистика операций по скважине, группированая по категориям
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("groupStat")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<WellGroupOpertionDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetGroupOperationsAsync(
[FromRoute] int idWell,
[FromQuery] WellOperationRequestBase request,
CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var requestToService = new WellOperationRequest(request, idWell);
var result = await operationRepository.GetGroupOperationsStatAsync(
requestToService,
token)
.ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Возвращает нужную операцию на скважине
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="idOperation">id нужной операции</param>
/// <param name="token">Токен отмены задачи</param>
/// <returns>Нужную операцию на скважине</returns>
[HttpGet("{idOperation}")]
[Permission]
[ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetOrDefaultAsync(int idWell, int idOperation,
CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var result = await operationRepository.GetOrDefaultAsync(idOperation, token).ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Добавляет новую операцию на скважину
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="idType">Тип добавляемой операции</param>
/// <param name="wellOperation">Добавляемая операция</param>
/// <param name="cancellationToken"></param>
/// <returns>Количество добавленных в БД записей</returns>
[HttpPost("{idType:int}")]
[Permission]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> InsertAsync(
[Range(1, int.MaxValue, ErrorMessage = "Id скважины не может быть меньше 1")] int idWell,
[Range(0, 1, ErrorMessage = "Тип операции недопустим. Допустимые: 0, 1")] int idType,
WellOperationDto wellOperation,
CancellationToken cancellationToken)
{
if (!await CanUserAccessToWellAsync(idWell, cancellationToken))
return Forbid();
if (!await CanUserEditWellOperationsAsync(idWell, cancellationToken))
return Forbid();
wellOperation.IdWell = idWell;
wellOperation.LastUpdateDate = DateTimeOffset.UtcNow;
wellOperation.IdUser = User.GetUserId();
wellOperation.IdType = idType;
var result = await operationRepository.InsertRangeAsync(new[] { wellOperation }, cancellationToken);
return Ok(result);
}
/// <summary>
/// Добавляет новые операции на скважине
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="wellOperations">Добавляемые операции</param>
/// <param name="idType">Тип добавляемых операций</param>
/// <param name="deleteBeforeInsert">Удалить операции перед сохранением</param>
/// <param name="cancellationToken"></param>
/// <returns>Количество добавленных в БД записей</returns>
[HttpPost("{idType:int}/{deleteBeforeInsert:bool}")]
[Permission]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> InsertRangeAsync(
[Range(1, int.MaxValue, ErrorMessage = "Id скважины не может быть меньше 1")] int idWell,
[Range(0, 1, ErrorMessage = "Тип операции недопустим. Допустимые: 0, 1")] int idType,
bool deleteBeforeInsert,
[FromBody] IEnumerable<WellOperationDto> wellOperations,
CancellationToken cancellationToken)
{
if (!await CanUserAccessToWellAsync(idWell, cancellationToken))
return Forbid();
if (!await CanUserEditWellOperationsAsync(idWell, cancellationToken))
return Forbid();
if (deleteBeforeInsert)
{
var existingOperations = await operationRepository.GetAsync(new WellOperationRequest
{
IdWell = idWell,
OperationType = idType
}, cancellationToken);
await operationRepository.DeleteAsync(existingOperations.Select(o => o.Id), cancellationToken);
}
foreach (var wellOperation in wellOperations)
{
wellOperation.IdWell = idWell;
wellOperation.LastUpdateDate = DateTimeOffset.UtcNow;
wellOperation.IdUser = User.GetUserId();
wellOperation.IdType = idType;
}
var result = await operationRepository.InsertRangeAsync(wellOperations, cancellationToken);
return Ok(result);
}
/// <summary>
/// Обновляет выбранную операцию на скважине
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="idOperation">id выбранной операции</param>
/// <param name="value">Новые данные для выбранной операции</param>
/// <param name="token">Токен отмены задачи</param>
/// <returns>Количество обновленных в БД строк</returns>
[HttpPut("{idOperation}")]
[Permission]
[ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> UpdateAsync(int idWell, int idOperation,
[FromBody] WellOperationDto value, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token))
return Forbid();
if (!await CanUserEditWellOperationsAsync(idWell, token))
return Forbid();
value.IdWell = idWell;
value.Id = idOperation;
value.LastUpdateDate = DateTimeOffset.UtcNow;
value.IdUser = User.GetUserId();
var result = await operationRepository.UpdateAsync(value, token)
.ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Удаляет выбранную операцию на скважине
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="idOperation">id выбранной операции</param>
/// <param name="token">Токен отмены задачи</param>
/// <returns>Количество удаленных из БД строк</returns>
[HttpDelete("{idOperation}")]
[Permission]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> DeleteAsync(int idWell, int idOperation, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token))
return Forbid();
if (!await CanUserEditWellOperationsAsync(idWell, token))
return Forbid();
var result = await operationRepository.DeleteAsync(new int[] { idOperation }, token)
.ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Импорт фактических операций из excel (xlsx) файла. Стандартный заполненный шаблон
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="files">Коллекция из одного файла xlsx</param>
/// <param name="deleteBeforeInsert">Удалить операции перед сохранением</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("import/fact/default/{deleteBeforeInsert:bool}")]
[ProducesResponseType(typeof(IEnumerable<WellOperationDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
[Permission]
public Task<IActionResult> ImportFactDefaultExcelFileAsync(int idWell,
[FromForm] IFormFileCollection files,
bool deleteBeforeInsert,
CancellationToken cancellationToken)
{
var options = new WellOperationImportDefaultOptionsDto
{
IdType = WellOperation.IdOperationTypeFact
};
return ImportExcelFileAsync(idWell, files, options,
(stream, _) => wellOperationDefaultExcelParser.Parse(stream, options),
deleteBeforeInsert,
cancellationToken);
}
/// <summary>
/// Импорт плановых операций из excel (xlsx) файла. Стандартный заполненный шаблон
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="files">Коллекция из одного файла xlsx</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("import/plan/default")]
[ProducesResponseType(typeof(IEnumerable<WellOperationDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
[Permission]
public Task<IActionResult> ImportPlanDefaultExcelFileAsync(int idWell,
[FromForm] IFormFileCollection files,
CancellationToken cancellationToken)
{
var options = new WellOperationImportDefaultOptionsDto
{
IdType = WellOperation.IdOperationTypePlan
};
return ImportExcelFileAsync(idWell, files, options,
(stream, _) => wellOperationDefaultExcelParser.Parse(stream, options),
null,
cancellationToken);
}
/// <summary>
/// Импорт операций из excel (xlsx) файла. ГПНХ (Хантос)
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="files">Коллекция из одного файла xlsx</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("import/plan/gazpromKhantos")]
[ProducesResponseType(typeof(IEnumerable<WellOperationDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
[Permission]
public Task<IActionResult> ImportPlanGazpromKhantosExcelFileAsync(int idWell,
[FromForm] IFormFileCollection files,
CancellationToken cancellationToken)
{
var options = new WellOperationImportGazpromKhantosOptionsDto
{
IdType = WellOperation.IdOperationTypePlan
};
return ImportExcelFileAsync(idWell, files, options,
(stream, _) => wellOperationGazpromKhantosExcelParser.Parse(stream, options),
null,
cancellationToken);
}
/// <summary>
/// Создает excel файл с операциями по скважине
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="token">Токен отмены задачи </param>
/// <returns>Запрашиваемый файл</returns>
[HttpGet("export")]
[Permission]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> ExportAsync([FromRoute] int idWell, CancellationToken token)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
if (!await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false))
return Forbid();
var stream = await wellOperationExportService.ExportAsync(idWell, token);
var fileName = await wellService.GetWellCaptionByIdAsync(idWell, token) + "_operations.xlsx";
return File(stream, "application/octet-stream", fileName);
}
/// <summary>
/// Создает excel файл с "сетевым графиком"
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="scheduleReportService"></param>
/// <param name="token"> Токен отмены задачи</param>
/// <returns>Запрашиваемый файл</returns>
[HttpGet("scheduleReport")]
[Permission]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> ScheduleReportAsync([FromRoute] int idWell, [FromServices] IScheduleReportService scheduleReportService, CancellationToken token)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
if (!await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false))
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);
}
/// <summary>
/// Возвращает шаблон файла импорта
/// </summary>
/// <returns>Запрашиваемый файл</returns>
[HttpGet("template")]
[AllowAnonymous]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")]
public IActionResult GetTemplate()
{
var stream = wellOperationImportTemplateService.GetExcelTemplateStream();
var fileName = "ЕЦП_шаблон_файла_операций.xlsx";
return File(stream, "application/octet-stream", fileName);
}
//TODO: deleteBeforeInsert тоже быстрый костыль
private async Task<IActionResult> ImportExcelFileAsync<TOptions>(int idWell, [FromForm] IFormFileCollection files,
TOptions options,
Func<Stream, TOptions, SheetDto> parseMethod,
bool? deleteBeforeInsert,
CancellationToken cancellationToken)
where TOptions : IWellOperationImportOptions
{
var idCompany = User.GetCompanyId();
var idUser = User.GetUserId();
if (!idCompany.HasValue || !idUser.HasValue)
throw new ForbidException("Неизвестный пользователь");
if (!await CanUserAccessToWellAsync(idWell, cancellationToken))
throw new ForbidException("Нет доступа к скважине");
if (!await CanUserEditWellOperationsAsync(idWell, cancellationToken))
throw new ForbidException("Недостаточно прав для редактирования ГГД на завершенной скважине");
if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, cancellationToken))
throw new ForbidException("Скважина недоступна для компании");
if (files.Count < 1)
return this.ValidationBadRequest(nameof(files), "Нет файла");
var file = files[0];
if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
return this.ValidationBadRequest(nameof(files), "Требуется xlsx файл.");
using Stream stream = file.OpenReadStream();
try
{
var sheet = parseMethod(stream, options);
var wellOperations = wellOperationImportService.Import(idWell, idUser.Value, options.IdType, sheet)
.OrderBy(w => w.DateStart);
var dateStart = wellOperations.MinOrDefault(w => w.DateStart);
foreach (var wellOperation in wellOperations)
{
if (dateStart.HasValue)
wellOperation.Day = (wellOperation.DateStart - dateStart.Value).TotalDays;
}
//TODO: очень быстрый костыль
if (deleteBeforeInsert is not null && options.IdType == WellOperation.IdOperationTypeFact)
{
return await InsertRangeAsync(idWell, options.IdType,
deleteBeforeInsert.Value,
wellOperations,
cancellationToken);
}
return Ok(wellOperations);
}
catch (FileFormatException ex)
{
return this.ValidationBadRequest(nameof(files), ex.Message);
}
}
private async Task<bool> CanUserAccessToWellAsync(int idWell, CancellationToken token)
{
int? idCompany = User.GetCompanyId();
return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false);
}
private async Task<bool> 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");
}
}
}