forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/wedges
This commit is contained in:
commit
5536c5e1dc
@ -13,7 +13,6 @@ public class AutoGeneratedDailyReportDto : AutoGeneratedDailyReportInfoDto
|
||||
/// </summary>
|
||||
public HeadBlockDto Head { get; set; } = null!;
|
||||
|
||||
//TODO: поля не должны быть массивами
|
||||
/// <summary>
|
||||
/// Блок подсистем
|
||||
/// </summary>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.Data;
|
||||
|
||||
@ -25,12 +26,14 @@ public class NotificationDto : IId
|
||||
/// <summary>
|
||||
/// Заголовок уведомления
|
||||
/// </summary>
|
||||
[Required, StringLength(300, MinimumLength = 1, ErrorMessage = "Заголовок должен мыть не меньше 1-го знака и не больше 300")]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Сообщение уведомления
|
||||
/// </summary>
|
||||
public string Message { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Сообщение уведомления
|
||||
/// </summary>
|
||||
[Required, StringLength(2048, MinimumLength = 1, ErrorMessage = "Заголовок должен мыть не меньше 1-го знака и не больше 2048")]
|
||||
public string Message { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Дата регистрации уведомления
|
||||
@ -90,6 +93,7 @@ public class NotificationDto : IId
|
||||
/// 0 - SignalR
|
||||
/// 1 - Email
|
||||
/// </summary>
|
||||
[Range(0,1)]
|
||||
public int IdTransportType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
107
AsbCloudApp/Data/ProcessMap/ProcessMapWellboreDevelopmentDto.cs
Normal file
107
AsbCloudApp/Data/ProcessMap/ProcessMapWellboreDevelopmentDto.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.Data.ProcessMap;
|
||||
|
||||
/// <summary>
|
||||
/// РТК план проработка скважины
|
||||
/// </summary>
|
||||
public class ProcessMapWellboreDevelopmentDto : IId, IWellRelated, IValidatableObject
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id пользователя
|
||||
/// </summary>
|
||||
public int IdUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата последнего изменения
|
||||
/// </summary>
|
||||
public DateTimeOffset LastUpdate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Стартовая глубина, м
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение стартовой глубины должно быть в пределах от 0 до 99999.9")]
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Окончательная глубина, м
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение окончательной глубины должно быть в пределах от 0 до 99999.9")]
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Количество повторений
|
||||
/// </summary>
|
||||
[Range(0, 100, ErrorMessage = "Значение количества повторений должно быть в пределах от 0 до 100")]
|
||||
public double Repeats { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Вращение при движении вверх, об/мин
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение количества вращений вверх должно быть в пределах от 0 до 99999.9")]
|
||||
public double SpinUpward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Вращение при движении вниз, об/мин
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение количества вращений вниз должно быть в пределах от 0 до 99999.9")]
|
||||
public double SpinDownward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Скорость подъёма, м/ч
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение скорости подъёма должно быть в пределах от 0 до 99999.9")]
|
||||
public double SpeedUpward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Скорость спуска, м/ч
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение скорости спуска должно быть в пределах от 0 до 99999.9")]
|
||||
public double SpeedDownward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Уставка зятяжки, т
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение затяжек уставки должно быть в пределах от 0 до 99999.9")]
|
||||
public double SetpointDrag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Уставка посадки, т
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение посадки уставки должно быть в пределах от 0 до 99999.9")]
|
||||
public double SetpointTight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Давление, атм
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение давления должно быть в пределах от 0 до 99999.9")]
|
||||
public double Pressure { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Момент, кН*м
|
||||
/// </summary>
|
||||
[Range(0, 99999.9, ErrorMessage = "Значение крутящего момента должно быть в пределах от 0 до 99999.9")]
|
||||
public double Torque { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Комментарий
|
||||
/// </summary>
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (DepthEnd < DepthStart)
|
||||
yield return new ValidationResult($"{nameof(DepthEnd)}:{DepthEnd:#0.0} меньше {nameof(DepthStart)}:{DepthStart:#0.0}", new[] { nameof(DepthEnd), nameof(DepthStart) });
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
@ -12,15 +12,6 @@ namespace AsbCloudApp.Data.SAUB
|
||||
/// </summary>
|
||||
public DateTime DateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// метка времени данных (legacy)
|
||||
/// </summary>
|
||||
public DateTime Date // TODO: remove this legacy after all panels updated (> 3.2.0407)
|
||||
{
|
||||
get { return DateTime; }
|
||||
set { DateTime = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Режим работы САУБ:
|
||||
/// 0 - "РУЧНОЙ"
|
||||
|
@ -53,8 +53,13 @@ namespace AsbCloudApp.Data
|
||||
public IEnumerable<CompanyDto> Companies { get; set; } = Enumerable.Empty<CompanyDto>();
|
||||
|
||||
/// <summary>
|
||||
/// Отставание от ГГД, проценты
|
||||
/// Отставание от ГГД, дни
|
||||
/// </summary>
|
||||
public double? TvdLagPercent { get; set; }
|
||||
public double? TvdLagDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Кол-во дней бурения по ГГД
|
||||
/// </summary>
|
||||
public double? TvdDrillingDays { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace AsbCloudApp.Data.User
|
||||
/// логин
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Логин не должен быть пустым")]
|
||||
[StringLength(50, MinimumLength = 1, ErrorMessage = "Допустимая длина логина от 1 до 50 символов")]
|
||||
[StringLength(50, MinimumLength = 3, ErrorMessage = "Допустимая длина логина от 3 до 50 символов")]
|
||||
public string Login { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
@ -39,7 +39,7 @@ namespace AsbCloudApp.Data.User
|
||||
/// Email
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(260, MinimumLength = 1, ErrorMessage = "Допустимая длина email от 1 до 260 символов")]
|
||||
[StringLength(260, MinimumLength = 3, ErrorMessage = "Допустимая длина email от 3 до 260 символов")]
|
||||
public string Email { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
|
@ -9,7 +9,7 @@ namespace AsbCloudApp.Data.User
|
||||
/// пароль, используется только при регистрации.
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Пароль не должен быть пустым")]
|
||||
[StringLength(50, MinimumLength = 1, ErrorMessage = "Допустимая длина пароля от 1 до 50 символов")]
|
||||
[StringLength(50, MinimumLength = 3, ErrorMessage = "Допустимая длина пароля от 3 до 50 символов")]
|
||||
public string Password { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ namespace AsbCloudApp.Data
|
||||
/// <summary>
|
||||
/// ID типа скважины
|
||||
/// </summary>
|
||||
[Range(1, 2, ErrorMessage = "Тип скважины указан неправильно.")]
|
||||
public int IdWellType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -59,6 +60,7 @@ namespace AsbCloudApp.Data
|
||||
/// 1 - в работе,
|
||||
/// 2 - завершена
|
||||
/// </summary>
|
||||
[Range(0, 2, ErrorMessage = "Текущее состояние работы скважины указано неправильно.")]
|
||||
public int IdState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -125,8 +125,13 @@ namespace AsbCloudApp.Data
|
||||
public PlanFactDto<double?> WellDepth { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Отставание от ГГД, проценты
|
||||
/// Отставание от ГГД, дни
|
||||
/// </summary>
|
||||
public double TvdLagPercent { get; set; }
|
||||
public double? TvdLagDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Кол-во дней бурения по ГГД
|
||||
/// </summary>
|
||||
public double? TvdDrillingDays { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using AsbCloudApp.ValidationAttributes;
|
||||
using AsbCloudApp.Validation;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
54
AsbCloudApp/Data/WellOperationImport/RowDto.cs
Normal file
54
AsbCloudApp/Data/WellOperationImport/RowDto.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
|
||||
namespace AsbCloudApp.Data.WellOperationImport;
|
||||
|
||||
/// <summary>
|
||||
/// Объект строки полученный из файла excel
|
||||
/// </summary>
|
||||
public class RowDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Номер строки
|
||||
/// </summary>
|
||||
public int Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Название секции
|
||||
/// </summary>
|
||||
public string? Section { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Категория
|
||||
/// </summary>
|
||||
public string? Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Описание категории
|
||||
/// </summary>
|
||||
public string CategoryInfo { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Начальная глубина операции
|
||||
/// </summary>
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Конечная глубина операции
|
||||
/// </summary>
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата начала операции
|
||||
/// </summary>
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Длительность операции
|
||||
/// </summary>
|
||||
public double Duration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Комментарий
|
||||
/// </summary>
|
||||
public string? Comment { get; set; }
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.Data.WellOperationImport;
|
||||
|
||||
/// <summary>
|
||||
/// Опции для настройки парсинга документа
|
||||
/// </summary>
|
||||
public class WellOperationParserOptionsDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Название листа
|
||||
/// </summary>
|
||||
[StringLength(250, MinimumLength =1, ErrorMessage = "Название листа должно быть задано")]
|
||||
public string SheetName { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Id шаблона
|
||||
/// 0 - Дефолтный шаблон
|
||||
/// 1 - Газпром хантос
|
||||
/// </summary>
|
||||
public int IdTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Начальная строка
|
||||
/// </summary>
|
||||
public int? StartRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Конечная строка
|
||||
/// </summary>
|
||||
public int? EndRow { get; set; }
|
||||
}
|
@ -15,32 +15,12 @@ namespace AsbCloudApp.Exceptions
|
||||
/// <summary>
|
||||
/// конструктор
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="paramName"></param>
|
||||
public ArgumentInvalidException(string message, string paramName)
|
||||
/// <param name="message"></param>
|
||||
public ArgumentInvalidException(string paramName, string message)
|
||||
: base(message)
|
||||
{
|
||||
ParamName = paramName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// преобразование в объект валидации
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public object ToValidationErrorObject()
|
||||
=> MakeValidationError(ParamName, Message);
|
||||
|
||||
/// <summary>
|
||||
/// фабрика объекта валидации
|
||||
/// </summary>
|
||||
/// <param name="paramName"></param>
|
||||
/// <param name="errors"></param>
|
||||
/// <returns></returns>
|
||||
public static object MakeValidationError(string paramName, params string[] errors)
|
||||
=> new
|
||||
{
|
||||
name = paramName,
|
||||
errors,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.ProcessMap;
|
||||
using AsbCloudApp.Services;
|
||||
|
||||
namespace AsbCloudApp.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Репозиторий для проработки скважины
|
||||
/// </summary>
|
||||
public interface IProcessMapWellboreDevelopmentRepository : IRepositoryWellRelated<ProcessMapWellboreDevelopmentDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Получить проработку начиная с даты
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="updateFrom"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ProcessMapWellboreDevelopmentDto>> GetAllAsync(int idWell, DateTime? updateFrom, CancellationToken cancellationToken);
|
||||
}
|
@ -18,7 +18,7 @@ namespace AsbCloudApp.Repositories
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<WellFinalDocumentDBDto>> UpdateRangeAsync(int idWell, IEnumerable<WellFinalDocumentInputDto>? dtos, CancellationToken token);
|
||||
Task<IEnumerable<WellFinalDocumentDBDto>> UpdateRangeAsync(int idWell, IEnumerable<WellFinalDocumentInputDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение всех записей
|
||||
|
@ -1,3 +1,4 @@
|
||||
using AsbCloudApp.Validation;
|
||||
using System;
|
||||
|
||||
namespace AsbCloudApp.Requests;
|
||||
@ -20,10 +21,12 @@ public class ReportParametersRequest
|
||||
/// <summary>
|
||||
/// Дата начала интервала
|
||||
/// </summary>
|
||||
[DateValidation(GtDate ="2000-01-01")]
|
||||
public DateTime Begin { get; set; } = default;
|
||||
|
||||
/// <summary>
|
||||
/// Дата окончания интервала
|
||||
/// </summary>
|
||||
public DateTime End { get; set; } = default;
|
||||
/// <summary>
|
||||
/// Дата окончания интервала
|
||||
/// </summary>
|
||||
[DateValidation(GtDate ="2000-01-01")]
|
||||
public DateTime End { get; set; } = default;
|
||||
}
|
@ -1,23 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Requests
|
||||
{
|
||||
/// <summary>
|
||||
/// класс с фильтрами для запроса
|
||||
/// </summary>
|
||||
public class SubsystemOperationTimeRequest: RequestBase
|
||||
public class SubsystemOperationTimeRequest: RequestBase, IValidatableObject
|
||||
{
|
||||
private static readonly DateTime validationMinDate = new DateTime(2020,01,01,0,0,0,DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор подсистемы
|
||||
/// </summary>
|
||||
public IEnumerable<int>? IdsSubsystems { get; set; }
|
||||
public IEnumerable<int> IdsSubsystems { get; set; } = Enumerable.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
@ -58,5 +62,32 @@ namespace AsbCloudApp.Requests
|
||||
/// Режим выборки элементов
|
||||
/// </summary>
|
||||
public int SelectMode { get; set; } = SelectModeOuter;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (GtDate.HasValue && GtDate < validationMinDate)
|
||||
yield return new ValidationResult(
|
||||
$"Должно быть больше {validationMinDate:O})",
|
||||
new[] { nameof(GtDate) });
|
||||
|
||||
if (LtDate.HasValue && GtDate.HasValue)
|
||||
{
|
||||
if (LtDate < GtDate)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LtDate)} должно быть больше {nameof(GtDate)}. ({LtDate:O} < {GtDate:O})",
|
||||
new[] { nameof(LtDate), nameof(GtDate) });
|
||||
}
|
||||
|
||||
if (LtDepth.HasValue && GtDepth.HasValue)
|
||||
{
|
||||
if (LtDepth < GtDepth)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LtDepth)} должно быть больше {nameof(GtDepth)}. ({LtDepth:O} < {GtDepth:O})",
|
||||
new[] { nameof(LtDepth), nameof(GtDepth) });
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="newPassword"></param>
|
||||
/// <returns></returns>
|
||||
int ChangePassword(int idUser, string newPassword);
|
||||
void ChangePassword(int idUser, string newPassword);
|
||||
|
||||
/// <summary>
|
||||
/// Смена пароля пользователю
|
||||
@ -24,7 +24,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="userLogin"></param>
|
||||
/// <param name="newPassword"></param>
|
||||
/// <returns></returns>
|
||||
int ChangePassword(string userLogin, string newPassword);
|
||||
void ChangePassword(string userLogin, string newPassword);
|
||||
|
||||
/// <summary>
|
||||
/// Авторизация
|
||||
@ -50,6 +50,6 @@ namespace AsbCloudApp.Services
|
||||
/// </summary>
|
||||
/// <param name="userDto"></param>
|
||||
/// <returns></returns>
|
||||
int Register(UserRegistrationDto userDto);
|
||||
void Register(UserRegistrationDto userDto);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.ProcessMap;
|
||||
|
||||
namespace AsbCloudApp.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Сервис для проработок скважины
|
||||
/// </summary>
|
||||
public interface IProcessMapWellboreDevelopmentService
|
||||
{
|
||||
/// <summary>
|
||||
/// Добавить запись проработки
|
||||
/// </summary>
|
||||
/// <param name="processMapWellboreDevelopment"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> InsertAsync(ProcessMapWellboreDevelopmentDto processMapWellboreDevelopment, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить запись проработки
|
||||
/// </summary>
|
||||
/// <param name="processMapWellboreDevelopment"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> UpdateAsync(ProcessMapWellboreDevelopmentDto processMapWellboreDevelopment, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Получить записи проработок по уникальному ключу телеметрии
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="updateFrom"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ProcessMapWellboreDevelopmentDto>> GetByTelemetryAsync(string uid, DateTime updateFrom,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace AsbCloudApp.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// сервис импорта/экспорта операций по скважине вводимых вручную
|
||||
/// </summary>
|
||||
public interface IWellOperationImportService
|
||||
{
|
||||
/// <summary>
|
||||
/// скачать в excel
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <returns></returns>
|
||||
Stream Export(int idWell);
|
||||
|
||||
/// <summary>
|
||||
/// скачать шаблон для заполнения
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Stream GetExcelTemplateStream();
|
||||
|
||||
/// <summary>
|
||||
/// закгрузить из excel список операций
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="deleteWellOperationsBeforeImport">Очистить старые перед импортом (если файл проходит валидацию)</param>
|
||||
void Import(int idWell, Stream stream, int idUser, bool deleteWellOperationsBeforeImport = false);
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ public class NotificationService
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var notificationCategory = await notificationCategoryRepository.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
|
||||
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdNotificationCategory), "Категория уведомления не найдена");
|
||||
|
||||
var notification = new NotificationDto
|
||||
{
|
||||
@ -75,10 +75,10 @@ public class NotificationService
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var notification = await notificationRepository.GetOrDefaultAsync(idNotification, cancellationToken)
|
||||
?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification));
|
||||
?? throw new ArgumentInvalidException(nameof(idNotification), "Уведомление не найдено");
|
||||
|
||||
if(isRead && !notification.SentDate.HasValue)
|
||||
throw new ArgumentInvalidException("Уведомление не может быть прочитано", nameof(isRead));
|
||||
throw new ArgumentInvalidException(nameof(isRead), "Уведомление не может быть прочитано");
|
||||
|
||||
notification.ReadDate = isRead ? DateTime.UtcNow : null;
|
||||
|
||||
@ -111,7 +111,7 @@ public class NotificationService
|
||||
{
|
||||
var notificationTransportService = notificationTransportServices
|
||||
.FirstOrDefault(s => s.IdTransportType == idTransportType)
|
||||
?? throw new ArgumentInvalidException("Доставщик уведомлений не найден", nameof(idTransportType));
|
||||
?? throw new ArgumentInvalidException(nameof(idTransportType), "Доставщик уведомлений не найден");
|
||||
|
||||
return notificationTransportService;
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
|
||||
namespace AsbCloudApp.Services.WellOperationImport;
|
||||
|
||||
/// <summary>
|
||||
/// Парсинг операций из excel файла
|
||||
/// </summary>
|
||||
public interface IWellOperationExcelParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Id шаблона
|
||||
/// </summary>
|
||||
int IdTemplate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Типы операций, которые можно получить из файла
|
||||
/// </summary>
|
||||
IEnumerable<int> IdTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Метод парсинга документа
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<RowDto> Parse(Stream stream, WellOperationParserOptionsDto options);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudApp.Services.WellOperationImport;
|
||||
|
||||
/// <summary>
|
||||
/// Экспорт ГГД
|
||||
/// </summary>
|
||||
public interface IWellOperationExportService
|
||||
{
|
||||
/// <summary>
|
||||
/// Скачать в excel
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
|
||||
namespace AsbCloudApp.Services.WellOperationImport;
|
||||
|
||||
/// <summary>
|
||||
/// Импорт ГГД
|
||||
/// </summary>
|
||||
public interface IWellOperationImportService
|
||||
{
|
||||
/// <summary>
|
||||
/// Загрузить из excel список операций
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="idType"></param>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="deleteWellOperationsBeforeImport"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <param name="options"></param>
|
||||
Task ImportAsync(int idWell, int idUser, int idType, Stream stream, WellOperationParserOptionsDto options,
|
||||
bool deleteWellOperationsBeforeImport,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using System.IO;
|
||||
|
||||
namespace AsbCloudApp.Services.WellOperationImport;
|
||||
|
||||
/// <summary>
|
||||
/// Сервис для получения шаблонов ГГД
|
||||
/// </summary>
|
||||
public interface IWellOperationImportTemplateService
|
||||
{
|
||||
/// <summary>
|
||||
/// Скачать шаблон для заполнения
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Stream GetExcelTemplateStream();
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.ValidationAttributes
|
||||
namespace AsbCloudApp.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Атрибут валидации даты-времени
|
8632
AsbCloudDb/Migrations/20230925052808_Add_ProcessMapWellboreDevelopment.Designer.cs
generated
Normal file
8632
AsbCloudDb/Migrations/20230925052808_Add_ProcessMapWellboreDevelopment.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Add_ProcessMapWellboreDevelopment : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "t_process_map_wellbore_development",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
id_well = table.Column<int>(type: "integer", nullable: false, comment: "Id скважины"),
|
||||
last_update = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата последнего изменения"),
|
||||
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Стартовая глубина"),
|
||||
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Окончательная глубина"),
|
||||
repeats = table.Column<double>(type: "double precision", nullable: false, comment: "Количество повторений"),
|
||||
spin_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вверх, об/мин"),
|
||||
spin_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вниз, об/мин"),
|
||||
speed_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость подъёма, м/ч"),
|
||||
speed_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость спуска, м/ч"),
|
||||
setpoint_drags = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка зятяжки, т"),
|
||||
setpoint_tights = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка посадки, т"),
|
||||
pressure = table.Column<double>(type: "double precision", nullable: false, comment: "Давление"),
|
||||
torque = table.Column<double>(type: "double precision", nullable: false, comment: "Момент, кН м"),
|
||||
comment = table.Column<string>(type: "text", nullable: true, comment: "Комментарий")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_t_process_map_wellbore_development", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "FK_t_process_map_wellbore_development_t_well_id_well",
|
||||
column: x => x.id_well,
|
||||
principalTable: "t_well",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
},
|
||||
comment: "Проработка скважины");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_t_process_map_wellbore_development_id_well",
|
||||
table: "t_process_map_wellbore_development",
|
||||
column: "id_well");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "t_process_map_wellbore_development");
|
||||
}
|
||||
}
|
||||
}
|
8544
AsbCloudDb/Migrations/20230925081405_Add_New_Permission_For_Manuals.Designer.cs
generated
Normal file
8544
AsbCloudDb/Migrations/20230925081405_Add_New_Permission_For_Manuals.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Add_New_Permission_For_Manuals : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.InsertData(
|
||||
table: "t_permission",
|
||||
columns: new[] { "id", "description", "name" },
|
||||
values: new object[] { 527, "Разрешение на удаление инструкций", "Manual.delete" });
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "t_relation_user_role_permission",
|
||||
columns: new[] { "id_permission", "id_user_role" },
|
||||
values: new object[] { 527, 1 });
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "t_relation_user_role_permission",
|
||||
keyColumns: new[] { "id_permission", "id_user_role" },
|
||||
keyValues: new object[] { 527, 1 });
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "t_permission",
|
||||
keyColumn: "id",
|
||||
keyValue: 527);
|
||||
}
|
||||
}
|
||||
}
|
8647
AsbCloudDb/Migrations/20230925132919_Update_ProcessMapWellboreDevelopment.Designer.cs
generated
Normal file
8647
AsbCloudDb/Migrations/20230925132919_Update_ProcessMapWellboreDevelopment.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,158 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Update_ProcessMapWellboreDevelopment : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "setpoint_tights",
|
||||
table: "t_process_map_wellbore_development",
|
||||
newName: "setpoint_tight");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "setpoint_drags",
|
||||
table: "t_process_map_wellbore_development",
|
||||
newName: "setpoint_drag");
|
||||
|
||||
migrationBuilder.AlterTable(
|
||||
name: "t_process_map_wellbore_development",
|
||||
comment: "РТК план проработка скважины",
|
||||
oldComment: "Проработка скважины");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "torque",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Момент, кН*м",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Момент, кН м");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "pressure",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Давление, атм",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Давление");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "depth_start",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Стартовая глубина, м",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Стартовая глубина");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "depth_end",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Окончательная глубина, м",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Окончательная глубина");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "id_user",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
comment: "Id пользователя");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_t_process_map_wellbore_development_id_user",
|
||||
table: "t_process_map_wellbore_development",
|
||||
column: "id_user");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_process_map_wellbore_development_t_user_id_user",
|
||||
table: "t_process_map_wellbore_development",
|
||||
column: "id_user",
|
||||
principalTable: "t_user",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_process_map_wellbore_development_t_user_id_user",
|
||||
table: "t_process_map_wellbore_development");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_t_process_map_wellbore_development_id_user",
|
||||
table: "t_process_map_wellbore_development");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "id_user",
|
||||
table: "t_process_map_wellbore_development");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "setpoint_tight",
|
||||
table: "t_process_map_wellbore_development",
|
||||
newName: "setpoint_tights");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "setpoint_drag",
|
||||
table: "t_process_map_wellbore_development",
|
||||
newName: "setpoint_drags");
|
||||
|
||||
migrationBuilder.AlterTable(
|
||||
name: "t_process_map_wellbore_development",
|
||||
comment: "Проработка скважины",
|
||||
oldComment: "РТК план проработка скважины");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "torque",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Момент, кН м",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Момент, кН*м");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "pressure",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Давление",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Давление, атм");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "depth_start",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Стартовая глубина",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Стартовая глубина, м");
|
||||
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "depth_end",
|
||||
table: "t_process_map_wellbore_development",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
comment: "Окончательная глубина",
|
||||
oldClrType: typeof(double),
|
||||
oldType: "double precision",
|
||||
oldComment: "Окончательная глубина, м");
|
||||
}
|
||||
}
|
||||
}
|
8659
AsbCloudDb/Migrations/20230928055323_WellOperations_Add_OnDelete_SetNull_Behavior.Designer.cs
generated
Normal file
8659
AsbCloudDb/Migrations/20230928055323_WellOperations_Add_OnDelete_SetNull_Behavior.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class WellOperations_Add_OnDelete_SetNull_Behavior : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_well_operation_t_well_operation_id_plan",
|
||||
table: "t_well_operation");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_well_operation_t_well_operation_id_plan",
|
||||
table: "t_well_operation",
|
||||
column: "id_plan",
|
||||
principalTable: "t_well_operation",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.SetNull);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_well_operation_t_well_operation_id_plan",
|
||||
table: "t_well_operation");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_well_operation_t_well_operation_id_plan",
|
||||
table: "t_well_operation",
|
||||
column: "id_plan",
|
||||
principalTable: "t_well_operation",
|
||||
principalColumn: "id");
|
||||
}
|
||||
}
|
||||
}
|
@ -2274,6 +2274,12 @@ namespace AsbCloudDb.Migrations
|
||||
Id = 526,
|
||||
Description = "Разрешение на редактирование операций у завершенной скважины",
|
||||
Name = "WellOperation.editCompletedWell"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 527,
|
||||
Description = "Разрешение на удаление инструкций",
|
||||
Name = "Manual.delete"
|
||||
});
|
||||
});
|
||||
|
||||
@ -2467,6 +2473,101 @@ namespace AsbCloudDb.Migrations
|
||||
b.HasComment("Операции по скважине – РТК");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.ProcessMapWellboreDevelopment", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Comment")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("comment")
|
||||
.HasComment("Комментарий");
|
||||
|
||||
b.Property<double>("DepthEnd")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("depth_end")
|
||||
.HasComment("Окончательная глубина, м");
|
||||
|
||||
b.Property<double>("DepthStart")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("depth_start")
|
||||
.HasComment("Стартовая глубина, м");
|
||||
|
||||
b.Property<int>("IdUser")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id_user")
|
||||
.HasComment("Id пользователя");
|
||||
|
||||
b.Property<int>("IdWell")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id_well")
|
||||
.HasComment("Id скважины");
|
||||
|
||||
b.Property<DateTimeOffset>("LastUpdate")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_update")
|
||||
.HasComment("Дата последнего изменения");
|
||||
|
||||
b.Property<double>("Pressure")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("pressure")
|
||||
.HasComment("Давление, атм");
|
||||
|
||||
b.Property<double>("Repeats")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("repeats")
|
||||
.HasComment("Количество повторений");
|
||||
|
||||
b.Property<double>("SetpointDrag")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("setpoint_drag")
|
||||
.HasComment("Уставка зятяжки, т");
|
||||
|
||||
b.Property<double>("SetpointTight")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("setpoint_tight")
|
||||
.HasComment("Уставка посадки, т");
|
||||
|
||||
b.Property<double>("SpeedDownward")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("speed_downward")
|
||||
.HasComment("Скорость спуска, м/ч");
|
||||
|
||||
b.Property<double>("SpeedUpward")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("speed_upward")
|
||||
.HasComment("Скорость подъёма, м/ч");
|
||||
|
||||
b.Property<double>("SpinDownward")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("spin_downward")
|
||||
.HasComment("Вращение при движении вниз, об/мин");
|
||||
|
||||
b.Property<double>("SpinUpward")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("spin_upward")
|
||||
.HasComment("Вращение при движении вверх, об/мин");
|
||||
|
||||
b.Property<double>("Torque")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("torque")
|
||||
.HasComment("Момент, кН*м");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IdUser");
|
||||
|
||||
b.HasIndex("IdWell");
|
||||
|
||||
b.ToTable("t_process_map_wellbore_development");
|
||||
|
||||
b.HasComment("РТК план проработка скважины");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.RelationCompanyWell", b =>
|
||||
{
|
||||
b.Property<int>("IdCompany")
|
||||
@ -3836,6 +3937,11 @@ namespace AsbCloudDb.Migrations
|
||||
{
|
||||
IdUserRole = 1,
|
||||
IdPermission = 526
|
||||
},
|
||||
new
|
||||
{
|
||||
IdUserRole = 1,
|
||||
IdPermission = 527
|
||||
});
|
||||
});
|
||||
|
||||
@ -7912,6 +8018,25 @@ namespace AsbCloudDb.Migrations
|
||||
b.Navigation("WellSectionType");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.ProcessMapWellboreDevelopment", b =>
|
||||
{
|
||||
b.HasOne("AsbCloudDb.Model.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("IdUser")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AsbCloudDb.Model.Well", "Well")
|
||||
.WithMany()
|
||||
.HasForeignKey("IdWell")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
|
||||
b.Navigation("Well");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.RelationCompanyWell", b =>
|
||||
{
|
||||
b.HasOne("AsbCloudDb.Model.Company", "Company")
|
||||
@ -8283,7 +8408,8 @@ namespace AsbCloudDb.Migrations
|
||||
|
||||
b.HasOne("AsbCloudDb.Model.WellOperation", "OperationPlan")
|
||||
.WithMany()
|
||||
.HasForeignKey("IdPlan");
|
||||
.HasForeignKey("IdPlan")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("AsbCloudDb.Model.Well", "Well")
|
||||
.WithMany("WellOperations")
|
||||
|
@ -17,6 +17,7 @@ namespace AsbCloudDb.Model
|
||||
public virtual DbSet<DetectedOperation> DetectedOperations => Set<DetectedOperation>();
|
||||
public virtual DbSet<PlannedTrajectory> PlannedTrajectories => Set<PlannedTrajectory>();
|
||||
public virtual DbSet<ProcessMap> ProcessMap => Set<ProcessMap>();
|
||||
public virtual DbSet<ProcessMapWellboreDevelopment> ProcessMapWellboreDevelopments => Set<ProcessMapWellboreDevelopment>();
|
||||
public virtual DbSet<DrillingProgramPart> DrillingProgramParts => Set<DrillingProgramPart>();
|
||||
public virtual DbSet<FileCategory> FileCategories => Set<FileCategory>();
|
||||
public virtual DbSet<FileInfo> Files => Set<FileInfo>();
|
||||
@ -276,6 +277,11 @@ namespace AsbCloudDb.Model
|
||||
{
|
||||
entity.HasIndex(d => d.DepthEnd);
|
||||
entity.HasIndex(d => d.DateStart);
|
||||
|
||||
entity.HasOne(o => o.OperationPlan)
|
||||
.WithMany()
|
||||
.HasForeignKey(o => o.IdPlan)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<DrillingProgramPart>(entity =>
|
||||
|
@ -161,7 +161,9 @@
|
||||
new() { Id = 524, Name = "Manual.get", Description = "Разрешить получение инструкций"},
|
||||
|
||||
new (){ Id = 525, Name = "ProcessMap.editCompletedWell", Description = "Разрешение на редактирование РТК у завершенной скважины"},
|
||||
new (){ Id = 526, Name = "WellOperation.editCompletedWell", Description = "Разрешение на редактирование операций у завершенной скважины"}
|
||||
new (){ Id = 526, Name = "WellOperation.editCompletedWell", Description = "Разрешение на редактирование операций у завершенной скважины"},
|
||||
|
||||
new() { Id = 527, Name = "Manual.delete", Description = "Разрешение на удаление инструкций"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ namespace AsbCloudDb.Model
|
||||
DbSet<DetectedOperation> DetectedOperations { get; }
|
||||
DbSet<PlannedTrajectory> PlannedTrajectories { get; }
|
||||
DbSet<ProcessMap> ProcessMap { get; }
|
||||
DbSet<ProcessMapWellboreDevelopment> ProcessMapWellboreDevelopments { get; }
|
||||
DbSet<DrillingProgramPart> DrillingProgramParts { get; }
|
||||
DbSet<FileCategory> FileCategories { get; }
|
||||
DbSet<FileInfo> Files { get; }
|
||||
|
65
AsbCloudDb/Model/ProcessMapWellboreDevelopment.cs
Normal file
65
AsbCloudDb/Model/ProcessMapWellboreDevelopment.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace AsbCloudDb.Model;
|
||||
|
||||
[Table("t_process_map_wellbore_development"), Comment("РТК план проработка скважины")]
|
||||
public class ProcessMapWellboreDevelopment : IId, IWellRelated
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("id_well"), Comment("Id скважины")]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
[Column("id_user"), Comment("Id пользователя")]
|
||||
public int IdUser { get; set; }
|
||||
|
||||
[Column("last_update", TypeName = "timestamp with time zone"), Comment("Дата последнего изменения")]
|
||||
public DateTimeOffset LastUpdate { get; set; }
|
||||
|
||||
[Column("depth_start"), Comment("Стартовая глубина, м")]
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
[Column("depth_end"), Comment("Окончательная глубина, м")]
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
[Column("repeats"), Comment("Количество повторений")]
|
||||
public double Repeats { get; set; }
|
||||
|
||||
[Column("spin_upward"), Comment("Вращение при движении вверх, об/мин")]
|
||||
public double SpinUpward { get; set; }
|
||||
|
||||
[Column("spin_downward"), Comment("Вращение при движении вниз, об/мин")]
|
||||
public double SpinDownward { get; set; }
|
||||
|
||||
[Column("speed_upward"), Comment("Скорость подъёма, м/ч")]
|
||||
public double SpeedUpward { get; set; }
|
||||
|
||||
[Column("speed_downward"), Comment("Скорость спуска, м/ч")]
|
||||
public double SpeedDownward { get; set; }
|
||||
|
||||
[Column("setpoint_drag"), Comment("Уставка зятяжки, т")]
|
||||
public double SetpointDrag { get; set; }
|
||||
|
||||
[Column("setpoint_tight"), Comment("Уставка посадки, т")]
|
||||
public double SetpointTight { get; set; }
|
||||
|
||||
[Column("pressure"), Comment("Давление, атм")]
|
||||
public double Pressure { get; set; }
|
||||
|
||||
[Column("torque"), Comment("Момент, кН*м")]
|
||||
public double Torque { get; set; }
|
||||
|
||||
[Column("comment"), Comment("Комментарий")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[ForeignKey(nameof(IdWell))]
|
||||
public virtual Well Well { get; set; } = null!;
|
||||
|
||||
[ForeignKey(nameof(IdUser))]
|
||||
public virtual User User { get; set; } = null!;
|
||||
}
|
@ -66,7 +66,7 @@ namespace AsbCloudDb.Model
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey(nameof(IdPlan))]
|
||||
public virtual WellOperation OperationPlan { get; set; } = null!;
|
||||
public virtual WellOperation? OperationPlan { get; set; } = null!;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,12 +34,18 @@
|
||||
<EmbeddedResource Include="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
|
||||
<EmbeddedResource Include="Services\ProcessMap\ProcessMapReportTemplate.xlsx" />
|
||||
<EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
|
||||
<EmbeddedResource Include="Services\WellOperationService\WellOperationImportTemplate.xlsx" />
|
||||
<EmbeddedResource Include="Services\ProcessMap\ProcessMapPlanTemplate.xlsx" />
|
||||
<EmbeddedResource Include="Services\AutoGeneratedDailyReports\AutogeneratedDailyReportTemplate.xlsx" />
|
||||
<EmbeddedResource Include="Services\WellOperationImport\Files\WellOperationImportTemplate.xlsx" />
|
||||
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\Operations.txt" />
|
||||
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\Sections.txt" />
|
||||
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\OperationAttributes.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsbSaubReport" Version="3.2.1" />
|
||||
<PackageReference Include="AsbSaubReportLas" Version="3.2.1" />
|
||||
<PackageReference Include="AsbSaubReportPdf" Version="3.2.1" />
|
||||
<PackageReference Include="CliWrap" Version="3.6.0" />
|
||||
<PackageReference Include="ClosedXML" Version="0.96.0" />
|
||||
<PackageReference Include="itext7" Version="7.2.3" />
|
||||
@ -59,15 +65,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="AsbSaubReport">
|
||||
<HintPath>CommonLibs\AsbSaubReport.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="AsbSaubReportLas">
|
||||
<HintPath>CommonLibs\AsbSaubReportLas.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="AsbSaubReportPdf">
|
||||
<HintPath>CommonLibs\AsbSaubReportPdf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="AsbWitsInfo">
|
||||
<HintPath>CommonLibs\AsbWitsInfo.dll</HintPath>
|
||||
</Reference>
|
||||
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -26,8 +26,12 @@ using System;
|
||||
using AsbCloudApp.Data.Manuals;
|
||||
using AsbCloudApp.Services.AutoGeneratedDailyReports;
|
||||
using AsbCloudApp.Services.Notifications;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudDb.Model.Manuals;
|
||||
using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
|
||||
using AsbCloudInfrastructure.Services.ProcessMap.ProcessMapWellboreDevelopment;
|
||||
|
||||
namespace AsbCloudInfrastructure
|
||||
{
|
||||
@ -119,6 +123,7 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<IAuthService, AuthService>();
|
||||
services.AddTransient<IDepositRepository, DepositRepository>();
|
||||
services.AddTransient<IProcessMapPlanRepository, ProcessMapRepository>();
|
||||
services.AddTransient<IProcessMapWellboreDevelopmentRepository, ProcessMapWellboreDevelopmentRepository>();
|
||||
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
|
||||
services.AddTransient<IEventService, EventService>();
|
||||
services.AddTransient<FileService>();
|
||||
@ -131,7 +136,6 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<ITelemetryUserService, TelemetryUserService>();
|
||||
services.AddTransient<ITimezoneService, TimezoneService>();
|
||||
services.AddTransient<IWellService, WellService>();
|
||||
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
||||
services.AddTransient<IProcessMapPlanImportService, ProcessMapPlanImportService>();
|
||||
services.AddTransient<IPlannedTrajectoryImportService, PlannedTrajectoryImportService>();
|
||||
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
||||
@ -147,6 +151,7 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
|
||||
services.AddTransient<IProcessMapReportMakerService, ProcessMapReportMakerService>();
|
||||
services.AddTransient<IProcessMapService, ProcessMapService>();
|
||||
services.AddTransient<IProcessMapWellboreDevelopmentService, ProcessMapWellboreDevelopmentService>();
|
||||
services.AddTransient<WellInfoService>();
|
||||
services.AddTransient<IHelpPageService, HelpPageService>();
|
||||
|
||||
@ -231,6 +236,13 @@ namespace AsbCloudInfrastructure
|
||||
|
||||
services.AddTransient<IWellboreService, WellboreService>();
|
||||
|
||||
services.AddTransient<IWellOperationExportService, WellOperationExportService>();
|
||||
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
||||
services.AddTransient<IWellOperationImportTemplateService, WellOperationImportTemplateService>();
|
||||
|
||||
services.AddTransient<IWellOperationExcelParser, WellOperationDefaultExcelParser>();
|
||||
services.AddTransient<IWellOperationExcelParser, WellOperationGazpromKhantosExcelParser>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbSaubReport.Model;
|
||||
using iText.Forms.Xfdf;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -38,10 +37,10 @@ namespace AsbCloudInfrastructure
|
||||
.ThenInclude(r => r.Company)
|
||||
.Include(w => w.Telemetry)
|
||||
.FirstOrDefault(w => w.Id == idWell)
|
||||
?? throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
|
||||
|
||||
idTelemetry = well?.IdTelemetry
|
||||
?? throw new ArgumentInvalidException($"Well {idWell} doesn't contain telemetry", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} doesn't contain telemetry");
|
||||
|
||||
events = context.TelemetryEvents
|
||||
.Where(e => e.IdTelemetry == idTelemetry)
|
||||
|
@ -93,7 +93,7 @@ namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
var sourceFaqs = db.Faqs.Where(e => e.Id == sourceId1 || e.Id == sourceId2).ToArray();
|
||||
if (sourceFaqs.Count() < 2)
|
||||
throw new ArgumentInvalidException("Questions with target ids don't exist", nameof(sourceFaqs));
|
||||
throw new ArgumentInvalidException(nameof(sourceFaqs), "Questions with target ids don't exist");
|
||||
|
||||
var newFaq = new Faq()
|
||||
{
|
||||
@ -115,7 +115,7 @@ namespace AsbCloudInfrastructure.Repository
|
||||
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
||||
|
||||
if (newFaq.Id == 0)
|
||||
throw new ArgumentInvalidException("Error creating new question", nameof(newFaq));
|
||||
throw new ArgumentInvalidException(nameof(sourceId1), "Error creating new question");
|
||||
|
||||
foreach (var sourceFaq in sourceFaqs)
|
||||
{
|
||||
@ -138,9 +138,8 @@ namespace AsbCloudInfrastructure.Repository
|
||||
|
||||
public async Task<int> MarkAsDeletedAsync(int id, CancellationToken token)
|
||||
{
|
||||
var entity = db.Faqs.FirstOrDefault(e => e.Id == id);
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException("Question doesn't exist", nameof(id));
|
||||
var entity = db.Faqs.FirstOrDefault(e => e.Id == id)
|
||||
?? throw new ArgumentInvalidException(nameof(id), "Question doesn't exist");
|
||||
|
||||
entity.State = Faq.StateDeleted;
|
||||
entity.DateLastEditedQuestion = DateTimeOffset.UtcNow;
|
||||
@ -151,9 +150,8 @@ namespace AsbCloudInfrastructure.Repository
|
||||
|
||||
public async Task<int> DeleteAsync(int id, CancellationToken token)
|
||||
{
|
||||
var faq = db.Faqs.FirstOrDefault(f => f.Id == id);
|
||||
if (faq is null)
|
||||
throw new ArgumentInvalidException("Question doesn't exist", nameof(id));
|
||||
var faq = db.Faqs.FirstOrDefault(f => f.Id == id)
|
||||
?? throw new ArgumentInvalidException(nameof(id), "Question doesn't exist");
|
||||
|
||||
db.Faqs.Remove(faq);
|
||||
return await db.SaveChangesAsync(token);
|
||||
|
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.ProcessMap;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository;
|
||||
|
||||
public class ProcessMapWellboreDevelopmentRepository :
|
||||
CrudWellRelatedRepositoryBase<ProcessMapWellboreDevelopmentDto, ProcessMapWellboreDevelopment>,
|
||||
IProcessMapWellboreDevelopmentRepository
|
||||
{
|
||||
private readonly IWellService wellService;
|
||||
|
||||
public ProcessMapWellboreDevelopmentRepository(IAsbCloudDbContext context, IWellService wellService) : base(context)
|
||||
{
|
||||
this.wellService = wellService;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProcessMapWellboreDevelopmentDto>> GetAllAsync(int idWell, DateTime? updateFrom,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var query = dbContext.ProcessMapWellboreDevelopments
|
||||
.Where(p => p.IdWell == idWell);
|
||||
|
||||
if (updateFrom.HasValue)
|
||||
{
|
||||
var timezone = wellService.GetTimezone(idWell);
|
||||
var updateFromUtc = updateFrom.Value.ToUtcDateTimeOffset(timezone.Hours);
|
||||
query = query.Where(p => p.LastUpdate >= updateFromUtc);
|
||||
}
|
||||
|
||||
var entities = await query
|
||||
.OrderBy(p => p.DepthStart)
|
||||
.ThenBy(p => p.Id)
|
||||
.AsNoTracking()
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
return entities.Select(Convert);
|
||||
}
|
||||
}
|
@ -28,7 +28,8 @@ namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
var idWell = plannedTrajectoryRows.First().IdWell;
|
||||
if (!plannedTrajectoryRows.All(r => r.IdWell == idWell))
|
||||
throw new ArgumentInvalidException("Все строки должны относиться к одной скважине", nameof(plannedTrajectoryRows));
|
||||
throw new ArgumentInvalidException(nameof(plannedTrajectoryRows), "Все строки должны относиться к одной скважине");
|
||||
|
||||
var offsetHours = wellService.GetTimezone(idWell).Hours;
|
||||
var entities = plannedTrajectoryRows
|
||||
.Select(e =>
|
||||
@ -77,9 +78,9 @@ namespace AsbCloudInfrastructure.Repository
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<TrajectoryGeoPlanDto>> GetAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var well = wellService.GetOrDefault(idWell);
|
||||
if (well is null || well.Timezone is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
|
||||
var well = wellService.GetOrDefault(idWell)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
|
||||
|
||||
var offsetHours = well.Timezone.Hours;
|
||||
var query = db.PlannedTrajectories
|
||||
.AsNoTracking()
|
||||
|
@ -97,13 +97,10 @@ namespace AsbCloudInfrastructure.Repository
|
||||
public async Task<int> UpdateAsync(UserExtendedDto dto, CancellationToken token)
|
||||
{
|
||||
if (dto.Id <= 1)
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), $"Invalid id {dto.Id}. You can't edit this user.");
|
||||
|
||||
var oldUser = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == dto.Id);
|
||||
if (oldUser is null)
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
|
||||
var oldUser = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == dto.Id)
|
||||
?? throw new ArgumentInvalidException(nameof(dto), $"Invalid id {dto.Id}. You can't edit this user.");
|
||||
|
||||
if (oldUser.Login != dto.Login)
|
||||
await AssertLoginIsBusyAsync(dto.Login, token);
|
||||
@ -111,10 +108,9 @@ namespace AsbCloudInfrastructure.Repository
|
||||
var userRoles = await userRoleRepository.GetByNamesAsync(dto.RoleNames, token).ConfigureAwait(false);
|
||||
await UpdateRolesCacheForUserAsync(dto.Id, userRoles, token);
|
||||
|
||||
var entity = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id);
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
|
||||
var entity = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id)
|
||||
?? throw new ArgumentInvalidException(nameof(dto), $"Invalid id {dto.Id}. You can't edit this user.");
|
||||
|
||||
entity.Id = dto.Id;
|
||||
entity.Login = dto.Login;
|
||||
entity.Name = dto.Name;
|
||||
@ -132,10 +128,9 @@ namespace AsbCloudInfrastructure.Repository
|
||||
|
||||
public async Task<int> DeleteAsync(int id, CancellationToken token)
|
||||
{
|
||||
var user = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
|
||||
if (user is null)
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {id}. You can't edit this user.", nameof(id));
|
||||
var user = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id)
|
||||
?? throw new ArgumentInvalidException(nameof(id), $"Invalid id {id}. You can't edit this user.");
|
||||
|
||||
var query = dbContext
|
||||
.Users
|
||||
.Where(u => u.Id == id);
|
||||
@ -147,7 +142,7 @@ namespace AsbCloudInfrastructure.Repository
|
||||
return result.Entity.Id;
|
||||
}
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {id}. You can't edit this user.", nameof(id));
|
||||
(nameof(id), $"Invalid id {id}. You can't edit this user.");
|
||||
}
|
||||
|
||||
public IEnumerable<UserRoleDto> GetRolesByIdUser(int idUser, int nestedLevel = 0)
|
||||
@ -161,6 +156,7 @@ namespace AsbCloudInfrastructure.Repository
|
||||
var roles = GetRolesByIdUser(idUser, 7);
|
||||
if (roles is null)
|
||||
return Enumerable.Empty<PermissionDto>();
|
||||
|
||||
var permissions = roles
|
||||
.Where(r => r.Permissions is not null)
|
||||
.SelectMany(r => r.Permissions);
|
||||
@ -198,10 +194,9 @@ namespace AsbCloudInfrastructure.Repository
|
||||
.FirstOrDefault(u => u.Login.ToLower() == login.ToLower());
|
||||
|
||||
if (existingUserDto is not null)
|
||||
throw new ArgumentInvalidException($"Login {login} is busy by {existingUserDto.MakeDisplayName()}, id{existingUserDto.Id}", nameof(login));
|
||||
throw new ArgumentInvalidException(nameof(login), $"Login {login} is busy by {existingUserDto.MakeDisplayName()}, id{existingUserDto.Id}");
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<RelationUserUserRole> GetCachRelationUserUserRoleCacheTag()
|
||||
{
|
||||
var cache = memoryCache.GetOrCreate(relationUserUserRoleCacheTag, cacheEntry =>
|
||||
@ -216,6 +211,7 @@ namespace AsbCloudInfrastructure.Repository
|
||||
});
|
||||
return cache!;
|
||||
}
|
||||
|
||||
private void DropCacheRelationUserUserRoleCacheTag()
|
||||
{
|
||||
memoryCache.Remove(relationUserUserRoleCacheTag);
|
||||
|
@ -85,7 +85,7 @@ namespace AsbCloudInfrastructure.Repository
|
||||
.Where(r => names.Contains(r.Caption));
|
||||
|
||||
if (entities?.Count() != names.Count())
|
||||
throw new ArgumentInvalidException("Invalid role names", nameof(names));
|
||||
throw new ArgumentInvalidException(nameof(names), "Invalid role names");
|
||||
|
||||
return entities.Select(Convert);
|
||||
}
|
||||
@ -196,7 +196,7 @@ namespace AsbCloudInfrastructure.Repository
|
||||
var idsIncludeRole = GetNestedByIds(dto.Roles.Select(x => x.Id)).Select(x => x.Id);
|
||||
|
||||
if (idsIncludeRole.Any(x => x == dto.Id))
|
||||
throw new ArgumentInvalidException("Invalid include role (self reference)", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), "Invalid include role (self reference)");
|
||||
|
||||
var removeRelationsQuery = dbContext.RelationUserRoleUserRoles
|
||||
.Where(r => r.Id == dto.Id);
|
||||
|
@ -32,10 +32,10 @@ namespace AsbCloudInfrastructure.Repository
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public async Task<IEnumerable<WellFinalDocumentDBDto>> UpdateRangeAsync(int idWell, IEnumerable<WellFinalDocumentInputDto>? dtos, CancellationToken token)
|
||||
public async Task<IEnumerable<WellFinalDocumentDBDto>> UpdateRangeAsync(int idWell, IEnumerable<WellFinalDocumentInputDto> dtos, CancellationToken token)
|
||||
{
|
||||
if (dtos is null)
|
||||
throw new ArgumentInvalidException("Данные по категориям отсутствуют.", nameof(dtos));
|
||||
if (!dtos.Any())
|
||||
throw new ArgumentInvalidException(nameof(dtos), "Данные по категориям отсутствуют.");
|
||||
|
||||
var entities = dtos
|
||||
.Where(dto => dto.IdsPublishers?.Any() == true)
|
||||
@ -128,11 +128,8 @@ namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
var entity = await context.WellFinalDocuments
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.IdWell == idWell && x.IdCategory == idCategory && x.IdUser == idUser, token);
|
||||
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException("Пользователь не является ответственным за загрузку файла для данной категории.", nameof(entity));
|
||||
|
||||
.FirstOrDefaultAsync(x => x.IdWell == idWell && x.IdCategory == idCategory && x.IdUser == idUser, token)
|
||||
?? throw new ArgumentInvalidException(nameof(idUser), "Пользователь не является ответственным за загрузку файла для данной категории.");
|
||||
var dto = Convert(entity);
|
||||
return dto;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using AsbCloudApp.Data.User;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
@ -76,27 +77,10 @@ namespace AsbCloudInfrastructure.Services
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Register(UserRegistrationDto userDto)
|
||||
public void Register(UserRegistrationDto userDto)
|
||||
{
|
||||
if (userDto.Login is null || userDto.Login.Length is < 3 or > 50)
|
||||
return -1;
|
||||
|
||||
if (userDto.Password is null || userDto.Password.Length is < 3 or > 50)
|
||||
return -2;
|
||||
|
||||
if (userDto.Email.Length > 255)
|
||||
return -3;
|
||||
|
||||
if (userDto.Phone?.Length > 50)
|
||||
return -4;
|
||||
|
||||
if (userDto.Position?.Length > 255)
|
||||
return -5;
|
||||
|
||||
var user = db.Users.FirstOrDefault(u => u.Login == userDto.Login);
|
||||
|
||||
if (user is not null)
|
||||
return -6;
|
||||
var user = db.Users.FirstOrDefault(u => u.Login == userDto.Login)
|
||||
?? throw new ArgumentInvalidException(nameof(userDto.Login), "Логин уже занят");
|
||||
|
||||
var salt = GenerateSalt();
|
||||
|
||||
@ -115,49 +99,35 @@ namespace AsbCloudInfrastructure.Services
|
||||
};
|
||||
|
||||
db.Users.Add(newUser);
|
||||
|
||||
try
|
||||
db.SaveChanges();
|
||||
db.RelationUserUserRoles.Add(new RelationUserUserRole
|
||||
{
|
||||
db.SaveChanges();
|
||||
db.RelationUserUserRoles.Add(new RelationUserUserRole
|
||||
{
|
||||
IdUser = newUser.Id,
|
||||
IdUserRole = 2
|
||||
});
|
||||
db.SaveChanges();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return -7;
|
||||
}
|
||||
|
||||
return 0;
|
||||
IdUser = newUser.Id,
|
||||
IdUserRole = 2
|
||||
});
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int ChangePassword(string userLogin, string newPassword)
|
||||
public void ChangePassword(string userLogin, string newPassword)
|
||||
{
|
||||
var user = db.Users.AsNoTracking().FirstOrDefault(u => u.Login == userLogin);
|
||||
if (user == null)
|
||||
return -1;
|
||||
var user = db.Users.FirstOrDefault(u => u.Login == userLogin)
|
||||
?? throw new ArgumentInvalidException(nameof(userLogin), "Логин не зарегистрирован");
|
||||
|
||||
var salt = GenerateSalt();
|
||||
user.PasswordHash = salt + ComputeHash(salt, newPassword);
|
||||
db.SaveChanges();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int ChangePassword(int idUser, string newPassword)
|
||||
public void ChangePassword(int idUser, string newPassword)
|
||||
{
|
||||
var user = db.Users.FirstOrDefault(u => u.Id == idUser);
|
||||
if (user == null)
|
||||
return -1;
|
||||
var user = db.Users.FirstOrDefault(u => u.Id == idUser)
|
||||
?? throw new ArgumentInvalidException(nameof(idUser), $"Пользователь с idUser:{idUser} не зарегистрирован");
|
||||
|
||||
var salt = GenerateSalt();
|
||||
user.PasswordHash = salt + ComputeHash(salt, newPassword);
|
||||
db.SaveChanges();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private async Task<UserTokenDto?> MakeUserTokenDto(User user, CancellationToken token)
|
||||
|
@ -57,10 +57,10 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
|
||||
var reports = new List<AutoGeneratedDailyReportInfoDto>();
|
||||
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
|
||||
?? throw new ArgumentInvalidException("Скважина не найдена", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "Скважина не найдена");
|
||||
|
||||
if (!well.IdTelemetry.HasValue)
|
||||
throw new ArgumentInvalidException("Телеметрия для скважины отсутствует", nameof(idWell));
|
||||
throw new ArgumentInvalidException(nameof(idWell), "Телеметрия для скважины отсутствует");
|
||||
|
||||
var datesRange = await GetDatesRangeAsync(idWell, cancellationToken);
|
||||
|
||||
@ -112,10 +112,10 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
|
||||
var finishDate = startDate.AddDays(1);
|
||||
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
|
||||
?? throw new ArgumentInvalidException("Скважина не найдена", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "Скважина не найдена");
|
||||
|
||||
if (!well.IdTelemetry.HasValue)
|
||||
throw new ArgumentInvalidException("Телеметрия для скважины отсутствует", nameof(idWell));
|
||||
throw new ArgumentInvalidException(nameof(idWell), "Телеметрия для скважины отсутствует");
|
||||
|
||||
var factOperations = await GetFactOperationsAsync(well.Id, startDate, finishDate,
|
||||
cancellationToken);
|
||||
|
@ -42,9 +42,8 @@ namespace AsbCloudInfrastructure.Services.DailyReport
|
||||
|
||||
public async Task<IEnumerable<DailyReportDto>> GetListAsync(int idWell, DateOnly? begin, DateOnly? end, CancellationToken token)
|
||||
{
|
||||
var well = wellService.GetOrDefault(idWell);
|
||||
if (well is null || well.Timezone is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
|
||||
var well = wellService.GetOrDefault(idWell)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
|
||||
|
||||
var query = db.DailyReports.Where(r => r.IdWell == idWell);
|
||||
|
||||
@ -90,15 +89,13 @@ namespace AsbCloudInfrastructure.Services.DailyReport
|
||||
|
||||
public async Task<int> AddAsync(int idWell, DateOnly startDate, int idUser, CancellationToken token)
|
||||
{
|
||||
var well = wellService.GetOrDefault(idWell);
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
|
||||
|
||||
var well = wellService.GetOrDefault(idWell)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
|
||||
|
||||
var hasEntity = await db.DailyReports
|
||||
.AnyAsync(r => r.IdWell == idWell && r.StartDate == startDate, token);
|
||||
if (hasEntity)
|
||||
throw new ArgumentInvalidException($"daily report on {startDate} already exists", nameof(startDate));
|
||||
throw new ArgumentInvalidException(nameof(startDate), $"daily report on {startDate} already exists");
|
||||
|
||||
var entity = new AsbCloudDb.Model.DailyReport.DailyReport
|
||||
{
|
||||
@ -116,14 +113,11 @@ namespace AsbCloudInfrastructure.Services.DailyReport
|
||||
|
||||
public async Task<int> UpdateBlockAsync(int idWell, DateOnly startDate, ItemInfoDto dto, CancellationToken token)
|
||||
{
|
||||
var well = wellService.GetOrDefault(idWell);
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
|
||||
var well = wellService.GetOrDefault(idWell)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
|
||||
|
||||
var entity = await db.DailyReports.FirstOrDefaultAsync(r => r.IdWell == idWell && r.StartDate == startDate, token);
|
||||
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException("Daily report doesn`t exist", nameof(startDate));
|
||||
var entity = await db.DailyReports.FirstOrDefaultAsync(r => r.IdWell == idWell && r.StartDate == startDate, token)
|
||||
?? throw new ArgumentInvalidException(nameof(startDate), "Daily report doesn`t exist");
|
||||
|
||||
dto.LastUpdateDate = DateTimeOffset.Now;
|
||||
if (dto is HeadDto headDto)
|
||||
@ -161,10 +155,8 @@ namespace AsbCloudInfrastructure.Services.DailyReport
|
||||
private async Task<DailyReportDto?> GetOrDefaultAsync(int idWell, DateOnly date, CancellationToken token)
|
||||
{
|
||||
var entity = await db.DailyReports
|
||||
.FirstOrDefaultAsync(r => r.IdWell == idWell && r.StartDate == date, token);
|
||||
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException("Daily report doesn`t exist", nameof(date));
|
||||
.FirstOrDefaultAsync(r => r.IdWell == idWell && r.StartDate == date, token)
|
||||
?? throw new ArgumentInvalidException(nameof(date), "Daily report doesn`t exist");
|
||||
|
||||
var factOperationsForDtos = await GetFactOperationsForDailyReportAsync(idWell, token);
|
||||
var userDtos = await userRepository.GetAllAsync(token);
|
||||
|
@ -185,10 +185,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
var part = await context.DrillingProgramParts
|
||||
.Include(p => p.RelatedUsers)
|
||||
.ThenInclude(r => r.User)
|
||||
.FirstOrDefaultAsync(p => p.IdWell == idWell && p.IdFileCategory == idFileCategory, token);
|
||||
|
||||
if (part == null)
|
||||
throw new ArgumentInvalidException($"DrillingProgramPart id == {idFileCategory} does not exist", nameof(idFileCategory));
|
||||
.FirstOrDefaultAsync(p => p.IdWell == idWell && p.IdFileCategory == idFileCategory, token)
|
||||
?? throw new ArgumentInvalidException(nameof(idFileCategory), $"DrillingProgramPart id == {idFileCategory} does not exist");
|
||||
|
||||
if (!part.RelatedUsers.Any(r => r.IdUser == idUser && r.IdUserRole == idUserRolePublisher))
|
||||
throw new ForbidException($"User {idUser} is not in the publisher list.");
|
||||
@ -246,19 +244,16 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
|
||||
public async Task<int> AddUserAsync(int idWell, int idFileCategory, int idUser, int idUserRole, CancellationToken token = default)
|
||||
{
|
||||
var user = await userRepository.GetOrDefaultAsync(idUser, token);
|
||||
if (user is null)
|
||||
throw new ArgumentInvalidException($"User id == {idUser} does not exist", nameof(idUser));
|
||||
var user = await userRepository.GetOrDefaultAsync(idUser, token)
|
||||
?? throw new ArgumentInvalidException(nameof(idUser), $"User id: {idUser} does not exist");
|
||||
|
||||
var part = await context.DrillingProgramParts
|
||||
.Include(p => p.FileCategory)
|
||||
.FirstOrDefaultAsync(p => p.IdWell == idWell && p.IdFileCategory == idFileCategory, token);
|
||||
|
||||
if (part is null)
|
||||
throw new ArgumentInvalidException($"DrillingProgramPart idFileCategory == {idFileCategory} does not exist", nameof(idFileCategory));
|
||||
.FirstOrDefaultAsync(p => p.IdWell == idWell && p.IdFileCategory == idFileCategory, token)
|
||||
?? throw new ArgumentInvalidException(nameof(idFileCategory), $"DrillingProgramPart idFileCategory: {idFileCategory} does not exist");
|
||||
|
||||
if (idUserRole != idUserRoleApprover && idUserRole != idUserRolePublisher)
|
||||
throw new ArgumentInvalidException($"idUserRole ({idUserRole}), should be approver ({idUserRoleApprover}) or publisher ({idUserRolePublisher})", nameof(idUserRole));
|
||||
throw new ArgumentInvalidException(nameof(idUserRole), $"idUserRole ({idUserRole}), should be approver ({idUserRoleApprover}) or publisher ({idUserRolePublisher})");
|
||||
|
||||
var oldRelation = await context.RelationDrillingProgramPartUsers
|
||||
.FirstOrDefaultAsync(r => r.IdUser == idUser && r.IdDrillingProgramPart == part.Id, token);
|
||||
@ -300,17 +295,14 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
{
|
||||
if (fileMarkDto.IdMarkType != idMarkTypeApprove &&
|
||||
fileMarkDto.IdMarkType != idMarkTypeReject)
|
||||
throw new ArgumentInvalidException($"В этом методе допустимы только отметки о принятии или отклонении.", nameof(fileMarkDto));
|
||||
throw new ArgumentInvalidException(nameof(fileMarkDto), $"В этом методе допустимы только отметки о принятии или отклонении.");
|
||||
|
||||
var fileInfo = await fileService.GetOrDefaultAsync(fileMarkDto.IdFile, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (fileInfo is null)
|
||||
throw new ArgumentInvalidException($"Файла для такой отметки не существует.", nameof(fileMarkDto));
|
||||
?? throw new ArgumentInvalidException(nameof(fileMarkDto), $"Файла для такой отметки не существует.");
|
||||
|
||||
if (fileInfo.IdCategory < idFileCategoryDrillingProgramPartsStart ||
|
||||
fileInfo.IdCategory > idFileCategoryDrillingProgramPartsEnd)
|
||||
throw new ArgumentInvalidException($"Этот метод допустим только для файлов-частей программы бурения.", nameof(fileMarkDto));
|
||||
throw new ArgumentInvalidException(nameof(fileMarkDto), $"Этот метод допустим только для файлов-частей программы бурения.");
|
||||
|
||||
var part = await context.DrillingProgramParts
|
||||
.Include(p => p.RelatedUsers)
|
||||
@ -318,9 +310,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p => p.IdWell == fileInfo.IdWell && p.IdFileCategory == fileInfo.IdCategory, token);
|
||||
|
||||
var user = part?.RelatedUsers.FirstOrDefault(r => r.IdUser == idUser && r.IdUserRole == idUserRoleApprover)?.User;
|
||||
if (user is null)
|
||||
throw new ForbidException($"User {idUser} is not in the approvers list.");
|
||||
var user = part?.RelatedUsers.FirstOrDefault(r => r.IdUser == idUser && r.IdUserRole == idUserRoleApprover)?.User
|
||||
?? throw new ForbidException($"User {idUser} is not in the approvers list.");
|
||||
|
||||
fileMarkDto.User = user.Adapt<UserDto>();
|
||||
|
||||
@ -363,7 +354,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
|
||||
if (fileInfo.IdCategory < idFileCategoryDrillingProgramPartsStart ||
|
||||
fileInfo.IdCategory > idFileCategoryDrillingProgramPartsEnd)
|
||||
throw new ArgumentInvalidException($"Этот метод допустим только для файлов-частей программы бурения.", nameof(idMark));
|
||||
throw new ArgumentInvalidException(nameof(idMark), $"Этот метод допустим только для файлов-частей программы бурения.");
|
||||
|
||||
var result = await fileService.MarkFileMarkAsDeletedAsync(idMark, token)
|
||||
.ConfigureAwait(false);
|
||||
@ -375,9 +366,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private async Task NotifyPublisherOnFullAccepAsync(FileMarkDto fileMark, CancellationToken token)
|
||||
{
|
||||
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file!.IdWell, token);
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(file.IdWell));
|
||||
var well = await wellService.GetOrDefaultAsync(file!.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(file.IdWell), "idWell doesn`t exist");
|
||||
|
||||
var user = file.Author!;
|
||||
var factory = new DrillingMailBodyFactory(configuration);
|
||||
@ -397,9 +387,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
|
||||
{
|
||||
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file!.IdWell, token);
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(file.IdWell));
|
||||
var well = await wellService.GetOrDefaultAsync(file!.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(file.IdWell), "idWell doesn`t exist");
|
||||
|
||||
var user = file.Author!;
|
||||
var factory = new DrillingMailBodyFactory(configuration);
|
||||
@ -418,9 +407,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
|
||||
private async Task NotifyApproversAsync(DrillingProgramPart part, int idFile, string fileName, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(part.IdWell, token);
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(part.IdWell));
|
||||
var well = await wellService.GetOrDefaultAsync(part.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(part.IdWell), "idWell doesn`t exist");
|
||||
|
||||
var factory = new DrillingMailBodyFactory(configuration);
|
||||
var subject = factory.MakeSubject(well, "Загружен новый документ для согласования.");
|
||||
@ -444,9 +432,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
|
||||
private async Task NotifyNewPublisherAsync(int idWell, UserDto user, string documentCategory, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
|
||||
|
||||
var factory = new DrillingMailBodyFactory(configuration);
|
||||
var subject = factory.MakeSubject(well, $"От вас ожидается загрузка на портал документа «{documentCategory}»");
|
||||
|
@ -25,7 +25,7 @@ namespace AsbCloudInfrastructure.Services.Email
|
||||
public static string GetOrEmptyImageBase64(string resourceFileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(resourceFileName))
|
||||
throw new ArgumentInvalidException("ResourceFileName doesn`t exist", nameof(resourceFileName));
|
||||
throw new ArgumentInvalidException(nameof(resourceFileName), "ResourceFileName doesn`t exist");
|
||||
|
||||
var baseDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
|
||||
?? string.Empty;
|
||||
|
@ -70,25 +70,21 @@ namespace AsbCloudInfrastructure.Services.Email
|
||||
return Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
|
||||
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(NotificationDto notification)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(notification.Title))
|
||||
throw new ArgumentInvalidException($"{nameof(notification.Title)} should be set", nameof(notification.Title));
|
||||
|
||||
return async (_, serviceProvider, token) =>
|
||||
{
|
||||
var notificationRepository = serviceProvider.GetRequiredService<INotificationRepository>();
|
||||
var userRepository = serviceProvider.GetRequiredService<IUserRepository>();
|
||||
|
||||
var user = await userRepository.GetOrDefaultAsync(notification.IdUser, token)
|
||||
?? throw new ArgumentInvalidException("Пользователь не найден" , nameof(notification.IdUser));
|
||||
?? throw new ArgumentInvalidException(nameof(notification.IdUser), "Пользователь не найден");
|
||||
|
||||
if(!MailAddress.TryCreate(user.Email, out var mailAddress))
|
||||
{
|
||||
Trace.TraceWarning($"Mail {user.Email} is not correct.");
|
||||
|
||||
if (mailAddress is null)
|
||||
throw new ArgumentInvalidException($"Mail {user.Email} is not null.", nameof(user.Email));
|
||||
throw new ArgumentInvalidException(nameof(user.Email), $"Mail {user.Email} is not null.");
|
||||
}
|
||||
|
||||
var from = new MailAddress(sender);
|
||||
var message = new MailMessage
|
||||
|
@ -47,8 +47,8 @@ public class ManualCatalogService : IManualCatalogService
|
||||
|
||||
if (!validExtensions.Contains(extension))
|
||||
throw new ArgumentInvalidException(
|
||||
$"Невозможно загрузить файл с расширением '{extension}'. Допустимые форматы файлов: {string.Join(", ", validExtensions)}",
|
||||
extension);
|
||||
nameof(name),
|
||||
$"Невозможно загрузить файл с расширением '{extension}'. Допустимые форматы файлов: {string.Join(", ", validExtensions)}");
|
||||
|
||||
var path = await BuildFilePathAsync(idDirectory, name, cancellationToken);
|
||||
|
||||
@ -69,7 +69,7 @@ public class ManualCatalogService : IManualCatalogService
|
||||
public async Task<int> AddDirectoryAsync(string name, int? idParent, CancellationToken cancellationToken)
|
||||
{
|
||||
if (idParent.HasValue && !await manualDirectoryRepository.IsExistsAsync(idParent.Value, cancellationToken))
|
||||
throw new ArgumentInvalidException("Родительской директории не существует", nameof(idParent));
|
||||
throw new ArgumentInvalidException(nameof(idParent), "Родительской директории не существует");
|
||||
|
||||
var directory = new ManualDirectoryDto
|
||||
{
|
||||
@ -78,7 +78,7 @@ public class ManualCatalogService : IManualCatalogService
|
||||
};
|
||||
|
||||
if (await IsExistDirectoryAsync(directory, cancellationToken))
|
||||
throw new ArgumentInvalidException("Директория с таким названием уже существует", name);
|
||||
throw new ArgumentInvalidException(name, "Директория с таким названием уже существует");
|
||||
|
||||
return await manualDirectoryRepository.InsertAsync(directory, cancellationToken);
|
||||
}
|
||||
@ -86,12 +86,12 @@ public class ManualCatalogService : IManualCatalogService
|
||||
public async Task UpdateDirectoryAsync(int id, string name, CancellationToken cancellationToken)
|
||||
{
|
||||
var directory = await manualDirectoryRepository.GetOrDefaultAsync(id, cancellationToken)
|
||||
?? throw new ArgumentInvalidException($"Директории с Id: {id} не существует", nameof(id));
|
||||
?? throw new ArgumentInvalidException(nameof(id), $"Директории с Id: {id} не существует");
|
||||
|
||||
directory.Name = name;
|
||||
|
||||
if (await IsExistDirectoryAsync(directory, cancellationToken))
|
||||
throw new ArgumentInvalidException("Директория с таким названием уже существует", name);
|
||||
throw new ArgumentInvalidException(name, "Директория с таким названием уже существует");
|
||||
|
||||
await manualDirectoryRepository.UpdateAsync(directory, cancellationToken);
|
||||
}
|
||||
@ -112,7 +112,7 @@ public class ManualCatalogService : IManualCatalogService
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
throw new ArgumentInvalidException(ex.Message, nameof(id));
|
||||
throw new ArgumentInvalidException(nameof(id), ex.Message);
|
||||
}
|
||||
|
||||
return await manualDirectoryRepository.DeleteAsync(directory.Id, cancellationToken);
|
||||
@ -157,15 +157,14 @@ public class ManualCatalogService : IManualCatalogService
|
||||
var directiories = await manualDirectoryRepository.GetAllAsync(cancellationToken);
|
||||
|
||||
var directory = directiories.FirstOrDefault(d => d.Id == idDirectory)
|
||||
?? throw new ArgumentInvalidException($"Директории с Id: {idDirectory} не существует", nameof(idDirectory));
|
||||
?? throw new ArgumentInvalidException(nameof(idDirectory), $"Директории с Id: {idDirectory} не существует");
|
||||
|
||||
var pathSegments = new List<int> { directory.Id };
|
||||
|
||||
while (directory.IdParent.HasValue)
|
||||
{
|
||||
directory = directiories.FirstOrDefault(d => d.Id == directory.IdParent.Value);
|
||||
|
||||
pathSegments.Insert(0, directory.Id);
|
||||
pathSegments.Insert(0, directory!.Id);
|
||||
}
|
||||
|
||||
return string.Join("/", pathSegments);
|
||||
|
@ -84,9 +84,9 @@ namespace AsbCloudInfrastructure.Services
|
||||
public Task<int> InsertAsync(int idWell, MeasureDto dto, CancellationToken token)
|
||||
{
|
||||
if (dto.IdCategory < 1)
|
||||
throw new ArgumentInvalidException("wrong idCategory", nameof(dto));
|
||||
if (dto.Data is null)
|
||||
throw new ArgumentInvalidException("data.data is not optional", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), "wrong idCategory");
|
||||
if (!dto.Data.Any())
|
||||
throw new ArgumentInvalidException(nameof(dto), "data.data is not optional");
|
||||
var timezone = wellService.GetTimezone(idWell);
|
||||
var entity = Convert(dto, timezone.Hours);
|
||||
entity.IdWell = idWell;
|
||||
@ -97,19 +97,16 @@ namespace AsbCloudInfrastructure.Services
|
||||
public async Task<int> UpdateAsync(int idWell, MeasureDto dto, CancellationToken token)
|
||||
{
|
||||
if (dto.Id < 1)
|
||||
throw new ArgumentInvalidException("wrong id", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), "wrong id");
|
||||
if (dto.IdCategory < 1)
|
||||
throw new ArgumentInvalidException("wrong idCategory", nameof(dto));
|
||||
if (dto.Data is null)
|
||||
throw new ArgumentInvalidException("data.data is not optional", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), "wrong idCategory");
|
||||
if (!dto.Data.Any())
|
||||
throw new ArgumentInvalidException(nameof(dto), "data.data is not optional");
|
||||
|
||||
var entity = await db.Measures
|
||||
.Where(m => m.Id == dto.Id && !m.IsDeleted)
|
||||
.FirstOrDefaultAsync(token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException("id doesn't exist", nameof(dto));
|
||||
?? throw new ArgumentInvalidException(nameof(dto), "id doesn't exist");
|
||||
|
||||
var timezone = wellService.GetTimezone(idWell);
|
||||
entity.IdWell = idWell;
|
||||
@ -122,14 +119,11 @@ namespace AsbCloudInfrastructure.Services
|
||||
public async Task<int> MarkAsDeleteAsync(int idWell, int idData, CancellationToken token)
|
||||
{
|
||||
if (idData < 1)
|
||||
throw new ArgumentInvalidException("wrong id", nameof(idData));
|
||||
throw new ArgumentInvalidException(nameof(idData), "wrong id");
|
||||
|
||||
var entity = await db.Measures.Where(m => m.IdWell == idWell && m.Id == idData)
|
||||
.FirstOrDefaultAsync(token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException($"Measure doesn't exist", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), $"Measure doesn't exist");
|
||||
|
||||
entity.IsDeleted = true;
|
||||
|
||||
@ -139,7 +133,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
public Task<int> DeleteAsync(int idWell, int idData, CancellationToken token)
|
||||
{
|
||||
if (idData < 1)
|
||||
throw new ArgumentInvalidException("wrong id", nameof(idData));
|
||||
throw new ArgumentInvalidException(nameof(idData), "wrong id");
|
||||
db.Measures.RemoveRange(db.Measures.Where(m => m.IdWell == idWell && m.Id == idData));
|
||||
return db.SaveChangesAsync(token);
|
||||
}
|
||||
|
@ -343,6 +343,7 @@ public class ProcessMapPlanImportService : IProcessMapPlanImportService
|
||||
_ => "Ручной",
|
||||
};
|
||||
|
||||
//TODO: вынести в метод расширения
|
||||
private static T GetCellValue<T>(IXLRow row, int columnNumber)
|
||||
{
|
||||
try
|
||||
|
@ -35,10 +35,10 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
|
||||
public async Task<IEnumerable<ProcessMapReportDto>> GetProcessMapReportAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var well = wellService.GetOrDefault(idWell)
|
||||
?? throw new ArgumentInvalidException("idWell not found", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell not found");
|
||||
|
||||
var idTelemetry = well.IdTelemetry
|
||||
?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "telemetry by well not found");
|
||||
|
||||
var processMapPlan = await processMapPlanRepository.GetByIdWellAsync(idWell, token);
|
||||
|
||||
|
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.ProcessMap;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ProcessMap.ProcessMapWellboreDevelopment;
|
||||
|
||||
public class ProcessMapWellboreDevelopmentService : IProcessMapWellboreDevelopmentService
|
||||
{
|
||||
private readonly ITelemetryService telemetryService;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IProcessMapWellboreDevelopmentRepository processMapWellboreDevelopmentRepository;
|
||||
|
||||
public ProcessMapWellboreDevelopmentService(ITelemetryService telemetryService,
|
||||
IWellService wellService,
|
||||
IProcessMapWellboreDevelopmentRepository processMapWellboreDevelopmentRepository)
|
||||
{
|
||||
this.telemetryService = telemetryService;
|
||||
this.wellService = wellService;
|
||||
this.processMapWellboreDevelopmentRepository = processMapWellboreDevelopmentRepository;
|
||||
}
|
||||
|
||||
public async Task<int> InsertAsync(ProcessMapWellboreDevelopmentDto processMapWellboreDevelopment, CancellationToken cancellationToken)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(processMapWellboreDevelopment.IdWell, cancellationToken)
|
||||
?? throw new ArgumentInvalidException(nameof(processMapWellboreDevelopment.IdWell),
|
||||
$"Скважины с Id: {processMapWellboreDevelopment.IdWell} не существует");
|
||||
|
||||
processMapWellboreDevelopment.LastUpdate = DateTimeOffset.UtcNow;
|
||||
|
||||
return await processMapWellboreDevelopmentRepository.InsertAsync(processMapWellboreDevelopment, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<int> UpdateAsync(ProcessMapWellboreDevelopmentDto processMapWellboreDevelopment, CancellationToken cancellationToken)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(processMapWellboreDevelopment.IdWell, cancellationToken);
|
||||
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException(nameof(processMapWellboreDevelopment.IdWell),
|
||||
$"Скважины с Id: {processMapWellboreDevelopment.IdWell} не существует");
|
||||
|
||||
processMapWellboreDevelopment.LastUpdate = DateTimeOffset.UtcNow;
|
||||
|
||||
var result = await processMapWellboreDevelopmentRepository.UpdateAsync(processMapWellboreDevelopment, cancellationToken);
|
||||
|
||||
if (result == ICrudRepository<ProcessMapWellboreDevelopmentDto>.ErrorIdNotFound)
|
||||
throw new ArgumentInvalidException(nameof(processMapWellboreDevelopment.Id),
|
||||
$"Проработки с Id: {processMapWellboreDevelopment.Id} не существует");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProcessMapWellboreDevelopmentDto>> GetByTelemetryAsync(string uid, DateTime updateFrom,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
||||
|
||||
if (!idWell.HasValue)
|
||||
throw new ArgumentInvalidException(nameof(uid), $"Неправильный телеметрии. Uid: {uid}");
|
||||
|
||||
return await processMapWellboreDevelopmentRepository.GetAllAsync(idWell.Value, updateFrom, cancellationToken);
|
||||
}
|
||||
}
|
@ -168,6 +168,14 @@ namespace AsbCloudInfrastructure.Services
|
||||
//PDF
|
||||
_ => new AsbSaubReportPdf.ReprotGeneratorPdf(dataSource),
|
||||
};
|
||||
|
||||
if(begin == default || end == default)
|
||||
{
|
||||
var analyzeResult = dataSource.Analyze();
|
||||
begin = begin == default ? analyzeResult.MinDate : begin;
|
||||
end = end == default ? begin.AddDays(1) : end;
|
||||
}
|
||||
|
||||
generator.Begin = begin;
|
||||
generator.End = end;
|
||||
generator.Step = TimeSpan.FromSeconds(stepSeconds);
|
||||
|
@ -1,5 +1,4 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb;
|
||||
using AsbCloudDb.Model;
|
||||
@ -64,10 +63,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
||||
return entity;
|
||||
});
|
||||
|
||||
var entityMaxDate = entities.Max(e => e.DateTime);
|
||||
|
||||
var dbset = db.Set<TEntity>();
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var dbset = db.Set<TEntity>();
|
||||
try
|
||||
{
|
||||
return await db.Database.ExecInsertOrUpdateAsync(dbset, entities, token).ConfigureAwait(false);
|
||||
|
@ -177,6 +177,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
||||
var idTelemetry = well.IdTelemetry!.Value;
|
||||
var hoursOffset = well.Timezone.Hours;
|
||||
|
||||
System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}>: Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}");
|
||||
var cacheItem = await GetOrDefaultCacheDataFromDbAsync<TEntity>(db, idTelemetry, capacity, hoursOffset, token);
|
||||
if(cacheItem is not null)
|
||||
{
|
||||
|
@ -114,10 +114,10 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
||||
{
|
||||
double intervalSec = (endDate - beginDate).TotalSeconds;
|
||||
if (intervalSec > 60*60*24*3)
|
||||
throw new ArgumentInvalidException("Слишком большой диапазон", nameof(endDate));
|
||||
throw new ArgumentInvalidException(nameof(endDate), "Слишком большой диапазон");
|
||||
|
||||
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell)
|
||||
?? throw new ArgumentInvalidException($"Скважина id:{idWell} не содержит телеметрии", nameof(idWell));
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина id:{idWell} не содержит телеметрии");
|
||||
|
||||
var approxPointsCount = intervalSec switch
|
||||
{
|
||||
|
@ -182,7 +182,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems
|
||||
IdSubsystem = IdSubsystemAKB,
|
||||
SubsystemName = "АПД",
|
||||
UsedTimeHours = apdParts.Sum(part => part.UsedTimeHours),
|
||||
KUsage = apdParts.Sum(part => part.KUsage),
|
||||
KUsage = apdParts.Sum(part => part.SumDepthInterval) / GetDepthIntervalSubsystem(IdSubsystemAKB, depthInterval),
|
||||
SumDepthInterval = apdParts.Sum(part => part.SumDepthInterval),
|
||||
OperationCount = apdParts.Sum(part => part.OperationCount),
|
||||
};
|
||||
@ -336,16 +336,15 @@ namespace AsbCloudInfrastructure.Services.Subsystems
|
||||
|
||||
private IQueryable<SubsystemOperationTime> BuildQuery(SubsystemOperationTimeRequest request)
|
||||
{
|
||||
var well = wellService.GetOrDefault(request.IdWell);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
throw new ArgumentInvalidException($"Not valid IdWell = {request.IdWell}", nameof(request.IdWell));
|
||||
var well = wellService.GetOrDefault(request.IdWell)
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Not valid IdWell = {request.IdWell}");
|
||||
|
||||
var query = db.SubsystemOperationTimes
|
||||
.Include(o => o.Subsystem)
|
||||
.Where(o => o.IdTelemetry == well.IdTelemetry)
|
||||
.AsNoTracking();
|
||||
|
||||
if (request.IdsSubsystems?.Any() == true)
|
||||
if (request.IdsSubsystems.Any())
|
||||
query = query.Where(o => request.IdsSubsystems.Contains(o.IdSubsystem));
|
||||
|
||||
// # Dates range condition
|
||||
|
@ -110,7 +110,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
}));
|
||||
|
||||
if(!docs.Any())
|
||||
throw new ArgumentInvalidException("Нет такой категории, или в нее уже загружен документ", nameof(idCategory));
|
||||
throw new ArgumentInvalidException(nameof(idCategory), "Нет такой категории, или в нее уже загружен документ");
|
||||
|
||||
var message = requester.MakeDisplayName() + " ожидает от Вас загрузку на портал документа «{{0}}»";
|
||||
await NotifyUsersAsync(docs, message, token);
|
||||
@ -126,9 +126,8 @@ namespace AsbCloudInfrastructure.Services
|
||||
if (user?.Email is not null)
|
||||
{
|
||||
var category = await fileCategoryService.GetOrDefaultAsync(item.IdCategory, token);
|
||||
var well = await wellService.GetOrDefaultAsync(item.IdWell, token);
|
||||
if(well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(item.IdWell));
|
||||
var well = await wellService.GetOrDefaultAsync(item.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(item.IdWell), "idWell doesn`t exist");
|
||||
|
||||
await SendMessageAsync(well, user, category?.Name ?? string.Empty, message,
|
||||
token);
|
||||
|
@ -188,7 +188,8 @@ namespace AsbCloudInfrastructure.Services
|
||||
wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAKB?.KUsage ?? 0d;
|
||||
wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemSpinMaster?.KUsage ?? 0d;
|
||||
wellMapInfo.TorqueKUsage = wellSubsystemStat?.SubsystemTorqueMaster?.KUsage ?? 0d;
|
||||
wellMapInfo.TvdLagPercent = wellOperationsStat?.TvdLagPercent ?? 0d;
|
||||
wellMapInfo.TvdLagDays = wellOperationsStat?.TvdLagDays;
|
||||
wellMapInfo.TvdDrillingDays = wellOperationsStat?.TvdDrillingDays;
|
||||
wellMapInfo.IdsCompanies = well.Companies.Select(c => c.Id);
|
||||
|
||||
return wellMapInfo;
|
||||
|
@ -0,0 +1,17 @@
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
|
||||
public static class DefaultTemplateInfo
|
||||
{
|
||||
public const string SheetNamePlan = "План";
|
||||
public const string SheetNameFact = "Факт";
|
||||
|
||||
public const int HeaderRowsCount = 1;
|
||||
public const int ColumnSection = 1;
|
||||
public const int ColumnCategory = 2;
|
||||
public const int ColumnCategoryInfo = 3;
|
||||
public const int ColumnDepthStart = 4;
|
||||
public const int ColumnDepthEnd = 5;
|
||||
public const int ColumnDate = 6;
|
||||
public const int ColumnDuration = 7;
|
||||
public const int ColumnComment = 8;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
|
||||
public static class OperationAttributes
|
||||
{
|
||||
public const string CategoryInfo = "Описание";
|
||||
public const string SectionDiameter = "ОК";
|
||||
public const string Depth = "Забой";
|
||||
public const string Duration = "Время операции";
|
||||
public const string Date = "Дата окончания операции";
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
|
||||
public static class Templates
|
||||
{
|
||||
public const int IdDefaultTemplate = 0;
|
||||
public const int IdGazpromKhantosTemplate = 1;
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser.StringSimilarity;
|
||||
|
||||
public class CosineSimilarity
|
||||
{
|
||||
private const int DefaultK = 2;
|
||||
|
||||
protected int K { get; }
|
||||
|
||||
public CosineSimilarity(int k)
|
||||
{
|
||||
if (k <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(k), "k should be positive!");
|
||||
}
|
||||
|
||||
K = k;
|
||||
}
|
||||
|
||||
public CosineSimilarity() : this(DefaultK) { }
|
||||
|
||||
public double Similarity(IDictionary<string, int> profile1, IDictionary<string, int> profile2)
|
||||
=> DotProduct(profile1, profile2)
|
||||
/ (Norm(profile1) * Norm(profile2));
|
||||
|
||||
public Dictionary<string, int> GetProfile(string s)
|
||||
{
|
||||
var shingles = new Dictionary<string, int>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(s))
|
||||
return shingles;
|
||||
|
||||
var cleanString = Stemming(s);
|
||||
|
||||
for (int i = 0; i < (cleanString.Length - K + 1); i++)
|
||||
{
|
||||
var shingle = cleanString.Substring(i, K);
|
||||
|
||||
if (shingles.TryGetValue(shingle, out var old))
|
||||
{
|
||||
shingles[shingle] = old + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
shingles[shingle] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return shingles;
|
||||
}
|
||||
|
||||
private static string Stemming(string s)
|
||||
{
|
||||
var cleaned = Regex.Replace(s.ToLower(), "[^a-zа-я0-9]", "");
|
||||
var words = cleaned.Split(' ');
|
||||
var filteredWords = words.Where(word => word.Length > 1).ToArray();
|
||||
return string.Concat(filteredWords);
|
||||
}
|
||||
|
||||
private static double Norm(IDictionary<string, int> profile)
|
||||
{
|
||||
double agg = 0;
|
||||
|
||||
foreach (var entry in profile)
|
||||
{
|
||||
agg += 1.0 * entry.Value * entry.Value;
|
||||
}
|
||||
|
||||
return Math.Sqrt(agg);
|
||||
}
|
||||
|
||||
private static double DotProduct(IDictionary<string, int> profile1, IDictionary<string, int> profile2)
|
||||
{
|
||||
var smallProfile = profile2;
|
||||
var largeProfile = profile1;
|
||||
|
||||
if (profile1.Count < profile2.Count)
|
||||
{
|
||||
smallProfile = profile1;
|
||||
largeProfile = profile2;
|
||||
}
|
||||
|
||||
double agg = 0;
|
||||
foreach (var entry in smallProfile)
|
||||
{
|
||||
if (!largeProfile.TryGetValue(entry.Key, out var i))
|
||||
continue;
|
||||
|
||||
agg += 1.0 * entry.Value * i;
|
||||
}
|
||||
|
||||
return agg;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
|
||||
|
||||
public class WellOperationDefaultExcelParser : IWellOperationExcelParser
|
||||
{
|
||||
public int IdTemplate => Templates.IdDefaultTemplate;
|
||||
public IEnumerable<int> IdTypes => new[] { WellOperation.IdOperationTypePlan, WellOperation.IdOperationTypeFact };
|
||||
|
||||
public IEnumerable<RowDto> Parse(Stream stream, WellOperationParserOptionsDto options)
|
||||
{
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
|
||||
return ParseWorkbook(workbook, options);
|
||||
}
|
||||
|
||||
private static IEnumerable<RowDto> ParseWorkbook(IXLWorkbook workbook, WellOperationParserOptionsDto options)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(options.SheetName))
|
||||
throw new ArgumentInvalidException(nameof(options.SheetName), "Не указано название листа");
|
||||
|
||||
var sheet = workbook.Worksheets.FirstOrDefault(ws =>
|
||||
string.Equals(ws.Name, options.SheetName, StringComparison.CurrentCultureIgnoreCase))
|
||||
?? throw new FileFormatException($"Книга excel не содержит листа '{options.SheetName}'");
|
||||
|
||||
return ParseSheet(sheet);
|
||||
}
|
||||
|
||||
private static IEnumerable<RowDto> ParseSheet(IXLWorksheet sheet)
|
||||
{
|
||||
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
|
||||
|
||||
var count = sheet.RowsUsed().Count() - DefaultTemplateInfo.HeaderRowsCount;
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case > 1024:
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество операций.");
|
||||
case <= 0:
|
||||
return Enumerable.Empty<RowDto>();
|
||||
}
|
||||
|
||||
var rows = new RowDto[count];
|
||||
|
||||
var cellValuesErrors = new List<string>();
|
||||
|
||||
for (int i = 0; i < rows.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var xlRow = sheet.Row(1 + i + DefaultTemplateInfo.HeaderRowsCount);
|
||||
|
||||
rows[i] = ParseRow(xlRow);
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
cellValuesErrors.Add(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (cellValuesErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", cellValuesErrors));
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static RowDto ParseRow(IXLRow xlRow)
|
||||
{
|
||||
return new RowDto
|
||||
{
|
||||
Number = xlRow.RowNumber(),
|
||||
Section = GetCellValue<string>(xlRow.Cell(DefaultTemplateInfo.ColumnSection)),
|
||||
Category = GetCellValue<string>(xlRow.Cell(DefaultTemplateInfo.ColumnCategory)),
|
||||
CategoryInfo = GetCellValue<string>(xlRow.Cell(DefaultTemplateInfo.ColumnCategoryInfo)),
|
||||
DepthStart = GetCellValue<double>(xlRow.Cell(DefaultTemplateInfo.ColumnDepthStart)),
|
||||
DepthEnd = GetCellValue<double>(xlRow.Cell(DefaultTemplateInfo.ColumnDepthEnd)),
|
||||
Date = GetCellValue<DateTime>(xlRow.Cell(DefaultTemplateInfo.ColumnDate)),
|
||||
Duration = GetCellValue<double>(xlRow.Cell(DefaultTemplateInfo.ColumnDuration)),
|
||||
Comment = GetCellValue<string>(xlRow.Cell(DefaultTemplateInfo.ColumnComment))
|
||||
};
|
||||
}
|
||||
|
||||
//TODO: вынести в метод расширения
|
||||
private static T GetCellValue<T>(IXLCell cell)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T)Convert.ChangeType(cell.Value, typeof(T));
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new FileFormatException(
|
||||
$"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser.StringSimilarity;
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
|
||||
|
||||
public class WellOperationGazpromKhantosExcelParser : IWellOperationExcelParser
|
||||
{
|
||||
private class Operation
|
||||
{
|
||||
public int RowNumber { get; set; }
|
||||
|
||||
public string CategoryInfo { get; set; } = null!;
|
||||
|
||||
public double SectionDiameter { get; set; }
|
||||
|
||||
public double Depth { get; set; }
|
||||
|
||||
public double Duration { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
}
|
||||
|
||||
private readonly CosineSimilarity cosineSimilarity;
|
||||
|
||||
private readonly Dictionary<string, string> operationDict = InitDict("Operations.txt", '=');
|
||||
private readonly Dictionary<string, string> sectionDict = InitDict("Sections.txt", '=');
|
||||
private readonly Dictionary<string, string> operationAttributesDict = InitDict("OperationAttributes.txt", '=');
|
||||
|
||||
|
||||
public WellOperationGazpromKhantosExcelParser()
|
||||
{
|
||||
cosineSimilarity = new CosineSimilarity();
|
||||
}
|
||||
|
||||
public int IdTemplate => Templates.IdGazpromKhantosTemplate;
|
||||
|
||||
public IEnumerable<int> IdTypes => new[] { WellOperation.IdOperationTypePlan };
|
||||
|
||||
public IEnumerable<RowDto> Parse(Stream stream, WellOperationParserOptionsDto options)
|
||||
{
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
|
||||
return ParseWorkBook(workbook, options);
|
||||
}
|
||||
|
||||
private IEnumerable<RowDto> ParseWorkBook(IXLWorkbook workbook, WellOperationParserOptionsDto options)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(options.SheetName))
|
||||
throw new ArgumentInvalidException(nameof(options.SheetName), "Не указано название листа");
|
||||
|
||||
if (options.StartRow is null or < 1 or > 1048576)
|
||||
throw new ArgumentInvalidException(nameof(options.StartRow), "Некорректное значение начальной строки");
|
||||
|
||||
if (options.EndRow is null or < 1 or > 1048576)
|
||||
throw new ArgumentInvalidException(nameof(options.EndRow), "Некорректное значение конечной строки");
|
||||
|
||||
if (options.EndRow < options.StartRow)
|
||||
throw new ArgumentInvalidException(nameof(options.EndRow), "Конечный номер строки не может быть больше начального");
|
||||
|
||||
var sheet = workbook.Worksheets.FirstOrDefault(ws =>
|
||||
string.Equals(ws.Name, options.SheetName, StringComparison.CurrentCultureIgnoreCase))
|
||||
?? throw new FileFormatException($"Книга excel не содержит листа '{options.SheetName}'");
|
||||
|
||||
return ParseSheet(sheet, options.StartRow.Value, options.EndRow.Value);
|
||||
}
|
||||
|
||||
private IEnumerable<RowDto> ParseSheet(IXLWorksheet sheet, int startRow, int endRow)
|
||||
{
|
||||
var operationAttributes = GetOperationAttributes(sheet.RowsUsed());
|
||||
|
||||
if (operationAttributes is null)
|
||||
return Enumerable.Empty<RowDto>();
|
||||
|
||||
var rowsCount = endRow - startRow + 1;
|
||||
|
||||
var operations = new List<Operation>();
|
||||
|
||||
var cellValuesErrors = new List<string>();
|
||||
|
||||
for (int i = 0; i < rowsCount; i++)
|
||||
{
|
||||
var xlRow = sheet.Row(startRow + i);
|
||||
|
||||
try
|
||||
{
|
||||
operations.Add(new Operation
|
||||
{
|
||||
RowNumber = xlRow.RowNumber(),
|
||||
CategoryInfo = GetCellValue<string>(xlRow.Cell(operationAttributes[OperationAttributes.CategoryInfo])),
|
||||
SectionDiameter = GetCellValue<double>(xlRow.Cell(operationAttributes[OperationAttributes.SectionDiameter])),
|
||||
Depth = GetCellValue<double>(xlRow.Cell(operationAttributes[OperationAttributes.Depth])),
|
||||
Duration = GetCellValue<double>(xlRow.Cell(operationAttributes[OperationAttributes.Duration])),
|
||||
Date = GetCellValue<DateTime>(xlRow.Cell(operationAttributes[OperationAttributes.Date]))
|
||||
});
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
cellValuesErrors.Add(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (cellValuesErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", cellValuesErrors));
|
||||
|
||||
return BuildRows();
|
||||
|
||||
IEnumerable<(double Diameter, string Name)> BuildSections()
|
||||
{
|
||||
var groupedOperations = operations.GroupBy(o => o.SectionDiameter)
|
||||
.Select(s => new
|
||||
{
|
||||
Diameter = s.Key,
|
||||
CategoryInfo = string.Concat(s.Select(o => o.CategoryInfo))
|
||||
});
|
||||
|
||||
var repeatedSections = new[] { "xвостовик" };
|
||||
|
||||
var sections = new List<(double diameter, string section)>();
|
||||
|
||||
foreach (var groupedOperation in groupedOperations)
|
||||
{
|
||||
var sectionNamesSet = new HashSet<string>(sections.Select(s => s.section));
|
||||
|
||||
sections.Add(new ValueTuple<double, string>(groupedOperation.Diameter, sectionDict.FirstOrDefault(item =>
|
||||
groupedOperation.CategoryInfo.Contains(item.Key) &&
|
||||
(!sectionNamesSet.Contains(item.Value) || repeatedSections.Contains(item.Value.ToLowerInvariant()))).Value));
|
||||
}
|
||||
|
||||
return sections;
|
||||
}
|
||||
|
||||
IEnumerable<RowDto> BuildRows()
|
||||
{
|
||||
if (!operations.Any())
|
||||
return Enumerable.Empty<RowDto>();
|
||||
|
||||
var rows = new List<RowDto>();
|
||||
|
||||
for (int i = 0; i < operations.Count; i++)
|
||||
{
|
||||
var currentOperation = operations[i];
|
||||
var nextOperation = i + 1 < operations.Count ? operations[i + 1] : currentOperation;
|
||||
|
||||
rows.Add(new RowDto
|
||||
{
|
||||
Number = currentOperation.RowNumber,
|
||||
Section = BuildSections().FirstOrDefault(s => Math.Abs(s.Diameter - currentOperation.SectionDiameter) < 0.1).Name,
|
||||
Category = GetValueDictionary(operationDict, currentOperation.CategoryInfo, 0.3),
|
||||
CategoryInfo = currentOperation.CategoryInfo,
|
||||
DepthStart = currentOperation.Depth,
|
||||
DepthEnd = nextOperation.Depth,
|
||||
Duration = currentOperation.Duration,
|
||||
Date = currentOperation.Date.AddHours(-currentOperation.Duration)
|
||||
});
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
private IDictionary<string, int>? GetOperationAttributes(IXLRows xlRows)
|
||||
{
|
||||
const int countOperationAttributes = 5;
|
||||
|
||||
IDictionary<string, int>? operationAttributes = null;
|
||||
|
||||
foreach (var xlRow in xlRows)
|
||||
{
|
||||
operationAttributes = new Dictionary<string, int>();
|
||||
|
||||
var cells = xlRow.CellsUsed().ToArray();
|
||||
|
||||
foreach (var cell in cells)
|
||||
{
|
||||
var operationAttribute = GetValueDictionary(operationAttributesDict, GetCellValue<string>(cell), 0.7);
|
||||
|
||||
if (operationAttribute is null || operationAttributes.Any(a => a.Key == operationAttribute))
|
||||
continue;
|
||||
|
||||
operationAttributes.Add(operationAttribute, cell.Address.ColumnNumber);
|
||||
}
|
||||
|
||||
if (operationAttributes.Count >= countOperationAttributes)
|
||||
break;
|
||||
}
|
||||
|
||||
return operationAttributes is not null && operationAttributes.Count == countOperationAttributes ? operationAttributes : null;
|
||||
}
|
||||
|
||||
private string? GetValueDictionary(IDictionary<string, string> dict, string cellValue, double? minSimilarity)
|
||||
{
|
||||
var similarValues = new List<(double similarity, string value)>();
|
||||
|
||||
var profile1 = cosineSimilarity.GetProfile(cellValue);
|
||||
|
||||
foreach (var item in dict)
|
||||
{
|
||||
var profile2 = cosineSimilarity.GetProfile(item.Key);
|
||||
|
||||
var similarity = cosineSimilarity.Similarity(profile1, profile2);
|
||||
|
||||
similarValues.Add((similarity, item.Value));
|
||||
}
|
||||
|
||||
var mostSimilarValue = similarValues.MaxBy(v => v.similarity);
|
||||
|
||||
return minSimilarity.HasValue && mostSimilarValue.similarity >= minSimilarity ? mostSimilarValue.value : null;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> InitDict(string fileName, char separator)
|
||||
{
|
||||
var resourceName = Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith(fileName))!;
|
||||
|
||||
var stream = Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream(resourceName)!;
|
||||
|
||||
using var reader = new StreamReader(stream);
|
||||
|
||||
return reader.ReadToEnd().Split('\r')
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Select(line => line.Split(separator))
|
||||
.ToDictionary(parts => parts[0].Trim(), parts => parts[1].Trim());
|
||||
}
|
||||
|
||||
//TODO: вынести в метод расширения
|
||||
private static T GetCellValue<T>(IXLCell cell)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (typeof(T) != typeof(DateTime))
|
||||
return (T)Convert.ChangeType(cell.GetFormattedString(), typeof(T), CultureInfo.InvariantCulture);
|
||||
|
||||
return (T)(object)DateTime.FromOADate((double)cell.Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new FileFormatException(
|
||||
$"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
Описание=Описание
|
||||
ОК=ОК
|
||||
Секция=ОК
|
||||
Забой, м=Забой
|
||||
Время=Время операции
|
||||
Плановое время бурения, сут=Время операции
|
||||
Окончание=Дата окончания операции
|
||||
Дата окончания План РГ=Дата окончания операции
|
@ -0,0 +1,190 @@
|
||||
Сборка КНБК=Сборка КНБК
|
||||
Сборка роторной КНБК=Сборка КНБК
|
||||
Шаблонирование спуск КНБК=Шаблонирование перед спуском
|
||||
Бурение под направлением=Бурение ротором
|
||||
Шаблонирование перед спуском=Шаблонирование перед спуском
|
||||
Шаблонировка пробуренного интервала + промывка на забое+ подъем КНБК=Шаблонирование перед спуском
|
||||
Разборка КНБК=Разборка КНБК
|
||||
ПР к спуску направления 324мм=ПЗР при спуске ОК
|
||||
Спуск направления=Спуск ОК
|
||||
Спуск направления 324мм=Спуск ОК
|
||||
Цементаж направления 324мм=Цементирование
|
||||
ОЗЦ. Оборудование устья.=ОЗЦ
|
||||
ОЗЦ. Чистка забурочной ямы. Чистка ВШН. Отворот доп. патрубка. ЗГР=ОЗЦ
|
||||
Перетяжка талевого каната / замена.=Перетяжка талевого каната
|
||||
Шаблонирование подъём КНБК=Шаблонировка подъем БИ, продувка
|
||||
Сборка СБТ 127мм-300м=Сборка БИ с мостков на подсвечник
|
||||
Сборка КНБК для бурения кондуктора=Сборка КНБК
|
||||
Сборка КНБК для бурения. Компоновка БК согласно собранного БИ в п.10=Сборка КНБК
|
||||
Cпуск КНБК=Спуск КНБК
|
||||
Cпуск КНБК со сборкой БИ с мостков=Спуск бурильного инструмента со сборкой с мостков
|
||||
Разбурка оснастки (ЦКОД, цем.стакан, БК), замена раствора=Разбуривание тех.оснастки
|
||||
Бурение под кондуктор. Наращивание св.=Бурение ротором
|
||||
Промывка, ОБР, МBТ БР<70 кг/м3=Промывка
|
||||
Промывка на забое=Промывка
|
||||
Шаблонирование (подъем)=Шаблонировка во время бурения
|
||||
Шаблонирование (спуск)=Шаблонировка во время бурения
|
||||
Промывка на забое. Прокачка ВУС, ОБР, МBТ БР <70 кг/м3=Промывка
|
||||
Подъем=Подъем КНБК
|
||||
Разборка КНБК с телесистемой=Разборка КНБК
|
||||
ПЗР к спуску ОК 245мм=ПЗР при спуске ОК
|
||||
Спуск ОК 245мм с промежуточными промывками (500 м, 1000м). Вывоз БР с БДЕ=Спуск ОК
|
||||
Промывка перед цементажем=Промывка при спуске ОК
|
||||
Цементаж кондуктора 245мм=Цементирование
|
||||
Монтаж ОУС. Вывоз БР, Чистка емкостей=Чистка ЦСГО/емкостного блока
|
||||
Монтаж ОУС=Монтаж ПВО
|
||||
Заготовка бурового раствора, чистка емкостей.=Опрессовка ПВО
|
||||
Монтаж ПВО, монтаж разрезной воронки и устьевого желоба. Вывоз БР, заготовка БР=Монтаж ПВО
|
||||
Опрессовка глухих плашек ППГ, БГ, БД , выкидных линий, крестовины с коренными задвижками. ЗБР=Опрессовка ПВО
|
||||
Сборка КНБК на бурение=Сборка КНБК
|
||||
Сборка СБТ 127мм-465м=Сборка БИ с мостков на подсвечник
|
||||
Спуск КНБК со сборкой с мостков СБТ -127 (1700м)=Спуск КНБК
|
||||
Сборка КНБК на бурение транспортного ствола=Сборка КНБК
|
||||
Опрессовка трубных плашек, ПУГ=Опрессовка ПВО
|
||||
Разбурка оснастки (ЦКОД, цем.стакан, БК, углубление на 2 метра ниже БК, опрессовка цементного кольца)=Разбуривание тех.оснастки
|
||||
Разбурка БК, ЦКОДа и цем.стакана=Разбуривание тех.оснастки
|
||||
Перевод скважины на новый раствор, чистка ЦСГО=Промывка - перевод скважины на новый раствор
|
||||
Перевод скважины на новый буровой раствор=Промывка - перевод скважины на новый раствор
|
||||
Бурение транспортного ствола наращ.св. (прокачка укрепляющих пачек ч/з каждые 150-200м)=Бурение ротором
|
||||
Промывка после ХМ св TVD - 1660 м (ниже на 50 м)=Промывка
|
||||
Чистка ЦСГО (опрессовка цем. кольца кондуктора во время чистки ЦСГО)=Чистка ЦСГО/емкостного блока
|
||||
Промывка после Алымской св TVD - 2140 м (ниже на 50 м)=Промывка
|
||||
Бурение транспортного ствола наращ. cв. (прокачка укрепляющих пачек ч/з каждые 150-200м).=Бурение ротором
|
||||
Бурение транспортного ствола (1000м первые сутки бурения)=Бурение ротором
|
||||
Подъем КНБК шаблонировка ствола скважины=Шаблонировка подъем БИ, продувка
|
||||
Промывка (по согласованию с ЦУСС)=Промывка
|
||||
Шаблонировка. Подъем КНБК (по согласованию с ЦУСС)=Шаблонировка во время бурения
|
||||
Шаблонировка.Спуск КНБК со сборкой БИ 300м (по согласованию с ЦУСС)=Шаблонировка во время бурения
|
||||
Промывка=Промывка
|
||||
Шаблонировка. Подъем КНБК=Шаблонировка во время бурения
|
||||
Шаблонировка.Спуск КНБК=Шаблонировка во время бурения
|
||||
Разборка КНБК с т/с=Разборка КНБК
|
||||
Промывка на забое, прокачка кольмат. пачки=Помывка
|
||||
ПЗР к спуску ОК-178мм.=ПЗР при спуске ОК
|
||||
Спуск ОК 178 мм (до устья, не потайная) с промежуточными промывками=Спуск ОК
|
||||
Цементирование ОК-178мм=Цементирование
|
||||
Отворот и выброс допускной трубы, демонтаж ПВО, замыв шурфа для выброса СБТ-127мм, чистка емкостей, приготовление БР=Демонтаж ПВО
|
||||
Промывка, установка смазывающей пачки=Промывка
|
||||
Выброс СБТ-127мм на мостки, чистка емкостей, приготовление БР=Подъем БИ с выбросом на мостки
|
||||
Подъем КНБК с выбросом БИ - 500м (выброс согласовать с куратором ЦУСС)=Подъем КНБК
|
||||
Монтаж ПВО, замена трубных плашек 127мм на 102мм, замена рабочего переводника на СВП, приготовление БР=Перетяжка талевого каната
|
||||
ПЗР к спуску ОК 178мм=ПЗР при спуске ОК
|
||||
Спуск ОК 178мм с промывками. Вывоз БР с БДЕ=Спуск ОК
|
||||
Цементирование 178мм ОК. Вывоз БР с БДЕ=Цементирование
|
||||
Частичный демонтаж ПВО=Демонтаж ПВО
|
||||
Выброс БИ 127 на мостки - 1600м (Оставляем БИ 127 1400 м на бурение под кондуктор). Вывоз БР, чистка емкостей=Подъем БИ с выбросом на мостки
|
||||
Частичный монтаж ПВО=Монтаж ПВО
|
||||
Опрессовка (200 атм) глухих плашек ППГ, БГ, БД, выкидных линий, крестовины с коренными задвижками, ЗБР. Сборка БИ-102мм - 1000м для бурения ГС свечами.=Опрессовка ПВО
|
||||
Сборка КНБК на бурение секции под хвостовик 114мм=Сборка КНБК
|
||||
Спуск КНБК со сборкой БИ 102 и промежуточными промывками.=Промывка - перевод скважины на новый раствор
|
||||
Опрессовка трубных плашек ППГ, ПУГ. Промывка, перезапись гаммы=Опрессовка ПВО
|
||||
Разбурка оснастки (ЦКОД, цем.стакан, БК)=Разбуривание тех.оснастки
|
||||
Перевод на новый раствор=Промывка - перевод скважины на новый раствор
|
||||
Чистка ЦСГО=Чистка ЦСГО/емкостного блока
|
||||
Бурение горизонтального участка скважины (прокачка укрепляющих пачек ч/з каждые 100 м)=Бурение ротором
|
||||
Подъем БИ в БК Ø178мм.=Подъем КНБК
|
||||
Спуск БИ со сборкой ТБТ 88,9мм на опрессовку (20м до БК 178)=Спуск КНБК
|
||||
Опрессовка БИ, установка на подсвечник ТБТ=Опрессовка БИ
|
||||
Проработка в 2 этапа:1 этап - прямая принудительная проработка; 2 этап - спуск на "сухую"(имитация спуска хвостовика)=Проработка принудительная
|
||||
Cборка хвостовика=Сборка хвостовика 114мм (согласно схеме)
|
||||
Промывка, прокачка ВУС=Промывка
|
||||
Подъем КНБК=Подъем КНБК
|
||||
ПЗР к спуску хвостовика=ПЗР при спуске ОК
|
||||
Сборка хвостовика 114мм (согласно схеме)=Сборка хвостовика 114мм (согласно схеме)
|
||||
Спуск хвостовика 114мм на БИ. В БК 178 перевод на тех.воду (по согл.с ЦУСС)=Спуск ОК
|
||||
Активация подвески (4ч). Перевод на жидкость заканчивания (2ч).=Активация подвески, опрессовка
|
||||
Подъем БИ с выбросом на мостки. Оставляем ТБТ 89 (800 м) на следующую скв=Подъем БИ с выбросом на мостки
|
||||
Демонтаж ПВО=Демонтаж ПВО
|
||||
Монтаж, опрессовка ФА=Монтаж, опрессовка ФА
|
||||
5% времени на ТО БУ=Ремонт
|
||||
Монтаж ФА=Монтаж, опрессовка ФА
|
||||
Подъем разъединителя с выбросом СБТ-102мм на мостки=Подъем инструмента
|
||||
Активация подвески. Перевод на жидкость заканчивания. Опрессовка пакера подвески хвостовика.=Активация подвески (потайной колонны, хвостовика)
|
||||
ПР к спуску хвостовика=ПЗР при спуске ОК
|
||||
Подъем КНБК с частичным выбросом СБТ-102мм на приемные мостки=Подъем БИ с выбросом на мостки
|
||||
Бурение горизонтального участка скважины (прокачка укрепляющих пачек ч/з каждые 100м)=Бурение ротором
|
||||
Промывка перезапись ГК=Промывка
|
||||
Спуск КНБК со сборкой СБТ-102мм с приемных мостков, с промежуточными промывками каждые 500м=Спуск бурильного инструмента со сборкой с мостков
|
||||
Сборка КНБК для бурения горизонтального участка скважины=Сборка БИ с мостков на подсвечник
|
||||
Опрессовка глухих плашек ППГ, БГ, БД, выкидных линий, крестовины с коренными задвижками, приготовление бур.раствора=Опрессовка ПВО
|
||||
ВМР=ВМР
|
||||
Долив затруба при подъёме=Долив затруба при подъёме
|
||||
Закачка/прокачка пачки=Закачка/прокачка пачки
|
||||
Комплекс ГИС на жестком кабеле=Комплекс ГИС на жестком кабеле
|
||||
Комплекс ГИС на кабеле=Комплекс ГИС на кабеле
|
||||
Комплекс ГИС на трубах=Комплекс ГИС на трубах
|
||||
Контролируемое ГНВП=Контролируемое ГНВП
|
||||
Ловильные работы=Ловильные работы
|
||||
Наработка жёлоба=Наработка жёлоба
|
||||
Наращивание=Наращивание
|
||||
НПВ / прочее=НПВ / прочее
|
||||
Обвязка устья с циркуляционной системой=Обвязка устья с циркуляционной системой
|
||||
Оборудование устья=Оборудование устья
|
||||
Обработка БР=Обработка БР
|
||||
Обработка раствора (несоответствие параметров)=Обработка раствора (несоответствие параметров)
|
||||
Ожидание=Ожидание
|
||||
Определение места прихвата и ЛМ=Определение места прихвата и ЛМ
|
||||
Опрессовка ОК=Опрессовка ОК
|
||||
Ориентирование ТС при бурении=Ориентирование ТС при бурении
|
||||
Отворот допускной трубы=Отворот допускной трубы
|
||||
Перезапись гаммы-каротажа=Перезапись гаммы-каротажа
|
||||
Перемонтаж ПВО=Перемонтаж ПВО
|
||||
ПЗР к спуску УЭЦН=ПЗР к спуску УЭЦН
|
||||
ПЗР при сборке КНБК=ПЗР при сборке КНБК
|
||||
ПЗР при цементировании=ПЗР при цементировании
|
||||
Поглощение=Поглощение
|
||||
Подготовка ствола скважины. Перезапись ГК в интервале установки КО.=Подготовка ствола скважины. Перезапись ГК в интервале установки КО.
|
||||
Подъем БИ с выбросом на мостки=Подъем БИ с выбросом на мостки
|
||||
подъем ОК=подъем ОК
|
||||
Подъем приборов ГИС (на трубах)=Подъем приборов ГИС (на трубах)
|
||||
Полная замена талевого каната=Полная замена талевого каната
|
||||
ПР перед забуркой направления=ПР перед забуркой направления
|
||||
Приготовление БР=Приготовление БР
|
||||
Продувка манифольда=Продувка манифольда
|
||||
Промывка перед наращиванием=Промывка перед наращиванием
|
||||
Проработка во время бурения=Проработка во время бурения
|
||||
Проработка перед наращиванием=Проработка перед наращиванием
|
||||
Работа яссом=Работа яссом
|
||||
Разборка комплекса приборов ГИС=Разборка комплекса приборов ГИС
|
||||
Разбуривание тех.оснастк=Разбуривание тех.оснастки
|
||||
Расхаживани=Расхаживание
|
||||
Ревизия КНБК/инструмента/ЗТС=Ревизия КНБК/инструмента/ЗТС
|
||||
Ремонт бурового оборудования=Ремонт бурового оборудования
|
||||
Сальникообразование=Сальникообразование
|
||||
Сборка и спуск ТБТ=Сборка и спуск ТБТ
|
||||
Сборка комплекса приборов ГИС=Сборка комплекса приборов ГИС
|
||||
Сборка устройства ориентирования КО=Сборка устройства ориентирования КО
|
||||
Смена рабочего переводника ВСП=Смена рабочего переводника ВСП
|
||||
СПО - колокол=СПО - колокол
|
||||
СПО - метчик=СПО - метчик
|
||||
СПО - овершот=СПО - овершот
|
||||
СПО - труболовка=СПО - труболовка
|
||||
Спуск БИ со сборкой с мостков=Спуск БИ со сборкой с мостков
|
||||
Спуск инструмента=Спуск инструмента
|
||||
Спуск инструмента с проработкой=Спуск инструмента с проработкой
|
||||
Спуск КО на транспотрной колонне=Спуск КО на транспотрной колонне
|
||||
Спуск приборов ГИС (на трубах)=Спуск приборов ГИС (на трубах)
|
||||
Срезка=Срезка
|
||||
Тайм-дриллинг=Тайм-дриллинг
|
||||
Тех.отстой=Тех.отстой
|
||||
Торпедирование (встряхивание)=Торпедирование (встряхивание)
|
||||
Торпедирование (отстрел)=Торпедирование (отстрел)
|
||||
Удержание в клиньях=Удержание в клиньях
|
||||
Установка ванн=Установка ванн
|
||||
Утяжеление БР=Утяжеление БР
|
||||
Учебная тревога "Выброс"=Учебная тревога "Выброс"
|
||||
Фрезеровка=Фрезеровка
|
||||
Шаблонировка подъем БИ, продувка=Шаблонировка подъем БИ, продувка
|
||||
Шаблонировка перед наращиванием=Шаблонировка перед наращиванием
|
||||
Демонтаж ПВО ( переоборудование устья скважины). Вывоз БР=Демонтаж ПВО
|
||||
Сборка БИ 127/147с мостков установкой на подсвечник=Сборка БИ с мостков на подсвечник
|
||||
Спуск приборов комплекса АМАК.=Спуск приборов ГИС (на трубах)
|
||||
Подъем с записью=Подъем приборов ГИС (на трубах)
|
||||
ОЗЦ под давлением (по согласованию с ЦУСС)=ОЗЦ
|
||||
"Демонтаж ПВО ( переоборудование устья скважины). Вывоз БР=Демонтаж ПВО
|
||||
Сборка CБТ-127 (0м) с мостков установкой на подсвечник (оставлено СБТ-127 (1500м) с пердыдущей скв). Заготовка БР=Сборка БИ с мостков на подсвечник
|
||||
ПЗР к спуску ОК=ПЗР при спуске ОК
|
||||
Выброс СБТ 127 (2100м), оставляется СБТ-127 (700 м) на след скв. ЗБР, чистка емкостей, вывоз БР.=Подъем БИ с выбросом на мостки
|
||||
Монтаж ПВО повторный (смена плашек ПВО). ЗБР, чистка емкостей, вывоз БР=Монтаж ПВО
|
||||
Опрессовка ПВО (200 атм), глухие=Опрессовка ПВО
|
||||
Сборка ТБТ на 2 этапе (кол-во по согласованию с ЦУСС). Подъем/спуск БИ со сборкой ТБТ 102 мм. Опрессовка БИ (1.5 ч)=Сборка и спуск ТБТ
|
@ -0,0 +1,7 @@
|
||||
направ=Направление
|
||||
конд=Кондуктор
|
||||
техн=Техническая колонна
|
||||
экспл=Эксплуатационная колонна
|
||||
транс=Транспортный ствол
|
||||
пилот=Пилотный ствол
|
||||
хвост=Хвостовик
|
@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport;
|
||||
|
||||
public class WellOperationExportService : IWellOperationExportService
|
||||
{
|
||||
private readonly IWellOperationRepository wellOperationRepository;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IWellOperationImportTemplateService wellOperationImportTemplateService;
|
||||
|
||||
public WellOperationExportService(IWellOperationRepository wellOperationRepository,
|
||||
IWellService wellService,
|
||||
IWellOperationImportTemplateService wellOperationImportTemplateService)
|
||||
{
|
||||
this.wellOperationRepository = wellOperationRepository;
|
||||
this.wellService = wellService;
|
||||
this.wellOperationImportTemplateService = wellOperationImportTemplateService;
|
||||
}
|
||||
|
||||
public async Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken)
|
||||
{
|
||||
var operations = await wellOperationRepository.GetAsync(new WellOperationRequest()
|
||||
{
|
||||
IdWell = idWell
|
||||
}, cancellationToken);
|
||||
|
||||
var timezone = wellService.GetTimezone(idWell);
|
||||
|
||||
return await MakeExcelFileStreamAsync(operations, timezone.Hours, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<Stream> MakeExcelFileStreamAsync(IEnumerable<WellOperationDto> operations, double timezoneOffset,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using Stream ecxelTemplateStream = wellOperationImportTemplateService.GetExcelTemplateStream();
|
||||
|
||||
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
|
||||
await AddOperationsToWorkbook(workbook, operations, timezoneOffset, cancellationToken);
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private async Task AddOperationsToWorkbook(XLWorkbook workbook, IEnumerable<WellOperationDto> operations, double timezoneOffset,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var planOperations = operations.Where(o => o.IdType == 0);
|
||||
if (planOperations.Any())
|
||||
{
|
||||
var sheetPlan = workbook.Worksheets.FirstOrDefault(ws => ws.Name == DefaultTemplateInfo.SheetNamePlan);
|
||||
if (sheetPlan is not null)
|
||||
await AddOperationsToSheetAsync(sheetPlan, planOperations, timezoneOffset, cancellationToken);
|
||||
}
|
||||
|
||||
var factOperations = operations.Where(o => o.IdType == 1);
|
||||
if (factOperations.Any())
|
||||
{
|
||||
var sheetFact = workbook.Worksheets.FirstOrDefault(ws => ws.Name == DefaultTemplateInfo.SheetNameFact);
|
||||
if (sheetFact is not null)
|
||||
await AddOperationsToSheetAsync(sheetFact, factOperations, timezoneOffset, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddOperationsToSheetAsync(IXLWorksheet sheet, IEnumerable<WellOperationDto> operations, double timezoneOffset,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var operationsToArray = operations.ToArray();
|
||||
|
||||
var sections = wellOperationRepository.GetSectionTypes();
|
||||
var categories = wellOperationRepository.GetCategories(false);
|
||||
|
||||
for (int i = 0; i < operationsToArray.Length; i++)
|
||||
{
|
||||
var row = sheet.Row(1 + i + DefaultTemplateInfo.HeaderRowsCount);
|
||||
AddOperationToRow(row, operationsToArray[i], sections, categories, timezoneOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddOperationToRow(IXLRow row, WellOperationDto operation, IEnumerable<WellSectionTypeDto> sections,
|
||||
IEnumerable<WellOperationCategoryDto> categories, double timezoneOffset)
|
||||
{
|
||||
row.Cell(DefaultTemplateInfo.ColumnSection).Value = sections.First(s => s.Id == operation.IdWellSectionType).Caption;
|
||||
row.Cell(DefaultTemplateInfo.ColumnCategory).Value = categories.First(o => o.Id == operation.IdCategory).Name;
|
||||
row.Cell(DefaultTemplateInfo.ColumnCategoryInfo).Value = operation.CategoryInfo;
|
||||
row.Cell(DefaultTemplateInfo.ColumnDepthStart).Value = operation.DepthStart;
|
||||
row.Cell(DefaultTemplateInfo.ColumnDepthEnd).Value = operation.DepthEnd;
|
||||
row.Cell(DefaultTemplateInfo.ColumnDate).Value = new DateTimeOffset(operation.DateStart).ToRemoteDateTime(timezoneOffset);
|
||||
row.Cell(DefaultTemplateInfo.ColumnDuration).Value = operation.DurationHours;
|
||||
row.Cell(DefaultTemplateInfo.ColumnComment).Value = operation.Comment;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport;
|
||||
|
||||
public class WellOperationImportService : IWellOperationImportService
|
||||
{
|
||||
private readonly IEnumerable<IWellOperationExcelParser> excelParsers;
|
||||
private readonly IWellOperationRepository wellOperationRepository;
|
||||
|
||||
private static readonly DateTime dateLimitMin = new(2001, 1, 1, 0, 0, 0);
|
||||
private static readonly DateTime dateLimitMax = new(2099, 1, 1, 0, 0, 0);
|
||||
private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366);
|
||||
|
||||
public WellOperationImportService(IEnumerable<IWellOperationExcelParser> excelParsers,
|
||||
IWellOperationRepository wellOperationRepository)
|
||||
{
|
||||
this.excelParsers = excelParsers;
|
||||
this.wellOperationRepository = wellOperationRepository;
|
||||
}
|
||||
|
||||
public async Task ImportAsync(int idWell, int idUser, int idType, Stream stream, WellOperationParserOptionsDto options,
|
||||
bool deleteWellOperationsBeforeImport, CancellationToken cancellationToken)
|
||||
{
|
||||
var excelParser = excelParsers.FirstOrDefault(p => p.IdTemplate == options.IdTemplate && p.IdTypes.Contains(idType))
|
||||
?? throw new ArgumentInvalidException(nameof(options.IdTemplate), "Невозможно импортировать файл");
|
||||
|
||||
if (idType != WellOperation.IdOperationTypePlan && idType != WellOperation.IdOperationTypeFact)
|
||||
throw new ArgumentInvalidException(nameof(idType), "Операции не существует");
|
||||
|
||||
RowDto[] rows;
|
||||
var validationErrors = new List<string>();
|
||||
|
||||
var sections = wellOperationRepository.GetSectionTypes();
|
||||
var categories = wellOperationRepository.GetCategories(false);
|
||||
|
||||
switch (options.IdTemplate)
|
||||
{
|
||||
case 0:
|
||||
options.SheetName = idType == WellOperation.IdOperationTypePlan
|
||||
? DefaultTemplateInfo.SheetNamePlan
|
||||
: DefaultTemplateInfo.SheetNameFact;
|
||||
rows = excelParser.Parse(stream, options).ToArray();
|
||||
break;
|
||||
default:
|
||||
if (string.IsNullOrWhiteSpace(options.SheetName))
|
||||
throw new FileFormatException("Не указано название листа");
|
||||
rows = excelParser.Parse(stream, options).ToArray();
|
||||
break;
|
||||
}
|
||||
|
||||
var operations = new List<WellOperationDto>();
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
try
|
||||
{
|
||||
var section = sections.FirstOrDefault(s =>
|
||||
string.Equals(s.Caption, row.Section, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
if (section is null)
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. В строке '{row.Number}' не удалось определить секцию");
|
||||
|
||||
var category = categories.FirstOrDefault(c =>
|
||||
string.Equals(c.Name, row.Category, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
if (category is null)
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. В строке '{row.Number}' не удалось определить операцию");
|
||||
|
||||
if (row.DepthStart is not (>= 0d and <= 20_000d))
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. Строка '{row.Number}' некорректная глубина на начало операции");
|
||||
|
||||
if (row.DepthEnd is not (>= 0d and <= 20_000d))
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. Строка '{row.Number}' некорректная глубина на конец операции");
|
||||
|
||||
if (row.Date < dateLimitMin && row.Date > dateLimitMax)
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. Строка '{row.Number}' неправильно получена дата начала операции");
|
||||
|
||||
if (operations.LastOrDefault()?.DateStart > row.Date)
|
||||
throw new FileFormatException($"Лист '{options.SheetName}' строка '{row.Number}' дата позднее даты предыдущей операции");
|
||||
|
||||
if (row.Duration is not (>= 0d and <= 240d))
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. Строка '{row.Number}' некорректная длительность операции");
|
||||
|
||||
operations.Add(new WellOperationDto
|
||||
{
|
||||
IdWell = idWell,
|
||||
IdUser = idUser,
|
||||
IdType = idType,
|
||||
IdWellSectionType = section.Id,
|
||||
IdCategory = category.Id,
|
||||
CategoryInfo = row.CategoryInfo,
|
||||
DepthStart = row.DepthStart,
|
||||
DepthEnd = row.DepthEnd,
|
||||
DateStart = row.Date,
|
||||
DurationHours = row.Duration
|
||||
});
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
validationErrors.Add(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (operations.Any() && operations.Min(o => o.DateStart) - operations.Max(o => o.DateStart) > drillingDurationLimitMax)
|
||||
validationErrors.Add($"Лист {options.SheetName} содержит диапазон дат больше {drillingDurationLimitMax}");
|
||||
|
||||
if (validationErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", validationErrors));
|
||||
|
||||
if(!operations.Any())
|
||||
return;
|
||||
|
||||
if (deleteWellOperationsBeforeImport)
|
||||
{
|
||||
var existingOperations = await wellOperationRepository.GetAsync(new WellOperationRequest
|
||||
{
|
||||
IdWell = idWell
|
||||
}, cancellationToken);
|
||||
|
||||
await wellOperationRepository.DeleteAsync(existingOperations.Select(o => o.Id), cancellationToken);
|
||||
}
|
||||
|
||||
await wellOperationRepository.InsertRangeAsync(operations, cancellationToken);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport;
|
||||
|
||||
public class WellOperationImportTemplateService : IWellOperationImportTemplateService
|
||||
{
|
||||
public Stream GetExcelTemplateStream()
|
||||
{
|
||||
var resourceName = Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith("WellOperationImportTemplate.xlsx"))!;
|
||||
|
||||
var stream = Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream(resourceName)!;
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
@ -172,81 +172,57 @@ public class OperationsStatService : IOperationsStatService
|
||||
var timezoneOffsetH = wellService.GetTimezone(well.Id).Hours;
|
||||
statWellDto.Sections = CalcSectionsStats(wellOperations, timezoneOffsetH);
|
||||
statWellDto.Total = GetStatTotal(wellOperations, well.IdState, timezoneOffsetH);
|
||||
statWellDto.TvdLagPercent = CalcTvdLagPercent(well.IdTelemetry, wellOperations);
|
||||
statWellDto.TvdLagDays = CalcTvdLagDays(wellOperations);
|
||||
statWellDto.TvdDrillingDays = CalcDrillingDays(wellOperations);
|
||||
|
||||
return statWellDto;
|
||||
}
|
||||
|
||||
private double? CalcTvdLagPercent(int? idTelemetry, IOrderedEnumerable<WellOperation> wellOperations)
|
||||
private static double? CalcDrillingDays(IEnumerable<WellOperation> wellOperations)
|
||||
{
|
||||
var currentDate = DateTimeOffset.UtcNow;
|
||||
var operationsOrdered = wellOperations
|
||||
.OrderBy(o => o.DateStart);
|
||||
|
||||
var wellDepth = wellOperations
|
||||
.LastOrDefault(o => o.IdType == WellOperation.IdOperationTypeFact)?.DepthEnd;
|
||||
var factOperations = operationsOrdered
|
||||
.Where(o => o.IdType == WellOperation.IdOperationTypeFact);
|
||||
|
||||
if (idTelemetry.HasValue)
|
||||
wellDepth = telemetryDataCache.GetLastOrDefault(idTelemetry.Value)?.WellDepth;
|
||||
|
||||
if (wellDepth is null)
|
||||
if (!factOperations.Any())
|
||||
return null;
|
||||
|
||||
var planOperations = wellOperations
|
||||
.Where(o => o.IdType == WellOperation.IdOperationTypePlan)
|
||||
.OrderBy(o => o.DateStart.AddHours(o.DurationHours));
|
||||
var operationFrom = factOperations.First();
|
||||
|
||||
if (!planOperations.Any())
|
||||
return null;
|
||||
var operationTo = factOperations.Last();
|
||||
|
||||
var planDepth = CalcPlanDepth(planOperations, currentDate);
|
||||
|
||||
if (planDepth is null)
|
||||
return null;
|
||||
|
||||
if (planDepth == 0d)
|
||||
return 0d;
|
||||
|
||||
return (1 - wellDepth / planDepth) * 100;
|
||||
return (operationTo.DateStart.AddHours(operationTo.DurationHours) - operationFrom.DateStart).TotalDays;
|
||||
}
|
||||
|
||||
private static double? CalcPlanDepth(IOrderedEnumerable<WellOperation> planOperations, DateTimeOffset currentDate)
|
||||
private static double? CalcTvdLagDays(IEnumerable<WellOperation> wellOperations)
|
||||
{
|
||||
var operationIn = planOperations
|
||||
.FirstOrDefault(o => o.DateStart <= currentDate && o.DateStart.AddHours(o.DurationHours) >= currentDate);
|
||||
var operationsOrdered = wellOperations
|
||||
.OrderBy(o => o.DateStart);
|
||||
|
||||
if (operationIn is not null)
|
||||
return Interpolate(
|
||||
operationIn.DepthStart,
|
||||
operationIn.DepthEnd,
|
||||
operationIn.DateStart,
|
||||
operationIn.DateStart.AddHours(operationIn.DurationHours),
|
||||
currentDate);
|
||||
var factOperations = operationsOrdered
|
||||
.Where(o => o.IdType == WellOperation.IdOperationTypeFact);
|
||||
|
||||
var operationFrom = planOperations
|
||||
.LastOrDefault(o => o.DateStart.AddHours(o.DurationHours) <= currentDate);
|
||||
var lastCorrespondingFactOperation = factOperations
|
||||
.LastOrDefault(o => o.IdPlan is not null);
|
||||
|
||||
var operationTo = planOperations
|
||||
.FirstOrDefault(o => o.DateStart >= currentDate);
|
||||
if (lastCorrespondingFactOperation is null)
|
||||
return null;
|
||||
|
||||
if (operationFrom is null && operationTo is not null)
|
||||
return 0d;
|
||||
else if (operationFrom is not null && operationTo is not null)
|
||||
{
|
||||
return Interpolate(
|
||||
operationFrom.DepthEnd,
|
||||
operationTo.DepthStart,
|
||||
operationFrom.DateStart.AddHours(operationTo.DurationHours),
|
||||
operationTo.DateStart,
|
||||
currentDate);
|
||||
}
|
||||
else if (operationFrom is not null && operationTo is null)
|
||||
return operationFrom.DepthEnd;
|
||||
var lastCorrespondingPlanOperation = wellOperations
|
||||
.FirstOrDefault(o => o.Id == lastCorrespondingFactOperation.IdPlan);
|
||||
|
||||
return null;
|
||||
if (lastCorrespondingPlanOperation is null)
|
||||
return null;
|
||||
|
||||
var factEnd = lastCorrespondingFactOperation.DateStart.AddHours(lastCorrespondingFactOperation.DurationHours);
|
||||
var planEnd = lastCorrespondingPlanOperation.DateStart.AddHours(lastCorrespondingPlanOperation.DurationHours);
|
||||
var lagDays = (planEnd - factEnd).TotalDays;
|
||||
|
||||
return lagDays;
|
||||
}
|
||||
|
||||
private static double Interpolate(double y0, double y1, DateTimeOffset x0, DateTimeOffset x1, DateTimeOffset x)
|
||||
=> y0 + (y1 - y0) * (x - x0).TotalMinutes / (x1 - x0).TotalMinutes;
|
||||
|
||||
private IEnumerable<StatSectionDto> CalcSectionsStats(IEnumerable<WellOperation> operations, double timezoneOffsetH)
|
||||
{
|
||||
var sectionTypeIds = operations
|
||||
|
@ -33,10 +33,8 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
{
|
||||
var tvd = await operationsStatService.GetTvdAsync(idWell, token);
|
||||
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
|
||||
if(well is null)
|
||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
|
||||
|
||||
var ecxelTemplateStream = GetExcelTemplateStream();
|
||||
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
|
||||
|
@ -1,341 +0,0 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using ClosedXML.Excel;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
{
|
||||
|
||||
/*
|
||||
* password for WellOperationImportTemplate.xlsx is ASB2020!
|
||||
*/
|
||||
|
||||
public class WellOperationImportService : IWellOperationImportService
|
||||
{
|
||||
private const string sheetNamePlan = "План";
|
||||
private const string sheetNameFact = "Факт";
|
||||
|
||||
private const int headerRowsCount = 1;
|
||||
private const int columnSection = 1;
|
||||
private const int columnCategory = 2;
|
||||
private const int columnCategoryInfo = 3;
|
||||
private const int columnDepthStart = 4;
|
||||
private const int columnDepthEnd = 5;
|
||||
private const int columnDate = 6;
|
||||
private const int columnDuration = 7;
|
||||
private const int columnComment = 8;
|
||||
|
||||
private static readonly DateTime dateLimitMin = new DateTime(2001, 1, 1, 0, 0, 0);
|
||||
private static readonly DateTime dateLimitMax = new DateTime(2099, 1, 1, 0, 0, 0);
|
||||
private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366);
|
||||
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly IWellService wellService;
|
||||
private List<WellOperationCategory> categories = null!;
|
||||
public List<WellOperationCategory> Categories
|
||||
{
|
||||
get
|
||||
{
|
||||
if (categories is null)
|
||||
{
|
||||
categories = db.WellOperationCategories
|
||||
.Where(c => c.Id >= 5000)
|
||||
.AsNoTracking()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return categories;
|
||||
}
|
||||
}
|
||||
|
||||
private List<WellSectionType> sections = null!;
|
||||
public List<WellSectionType> Sections
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sections is null)
|
||||
sections = db.WellSectionTypes
|
||||
.AsNoTracking()
|
||||
.ToList();
|
||||
return sections;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use WellOperationRepository instead of DB
|
||||
public WellOperationImportService(IAsbCloudDbContext db, IWellService wellService)
|
||||
{
|
||||
this.db = db;
|
||||
this.wellService = wellService;
|
||||
}
|
||||
|
||||
public void Import(int idWell, Stream stream, int idUser, bool deleteWellOperationsBeforeImport = false)
|
||||
{
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
var operations = ParseFileStream(stream);
|
||||
foreach (var operation in operations)
|
||||
{
|
||||
operation.IdWell = idWell;
|
||||
operation.IdUser = idUser;
|
||||
}
|
||||
|
||||
SaveOperations(idWell, operations, deleteWellOperationsBeforeImport);
|
||||
}
|
||||
|
||||
public Stream Export(int idWell)
|
||||
{
|
||||
var operations = db.WellOperations
|
||||
.Include(o => o.WellSectionType)
|
||||
.Include(o => o.OperationCategory)
|
||||
.Where(o => o.IdWell == idWell)
|
||||
.OrderBy(o => o.DateStart)
|
||||
.AsNoTracking()
|
||||
.ToList();
|
||||
|
||||
var timezone = wellService.GetTimezone(idWell);
|
||||
|
||||
return MakeExelFileStream(operations, timezone.Hours);
|
||||
}
|
||||
|
||||
public Stream GetExcelTemplateStream()
|
||||
{
|
||||
var resourceName = System.Reflection.Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith("WellOperationImportTemplate.xlsx"))!;
|
||||
|
||||
var stream = System.Reflection.Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream(resourceName)!;
|
||||
return stream;
|
||||
}
|
||||
|
||||
private Stream MakeExelFileStream(IEnumerable<WellOperation> operations, double timezoneOffset)
|
||||
{
|
||||
using Stream ecxelTemplateStream = GetExcelTemplateStream();
|
||||
|
||||
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
|
||||
AddOperationsToWorkbook(workbook, operations, timezoneOffset);
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private static void AddOperationsToWorkbook(XLWorkbook workbook, IEnumerable<WellOperation> operations, double timezoneOffset)
|
||||
{
|
||||
var planOperations = operations.Where(o => o.IdType == 0);
|
||||
if (planOperations.Any())
|
||||
{
|
||||
var sheetPlan = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlan);
|
||||
if (sheetPlan is not null)
|
||||
AddOperationsToSheet(sheetPlan, planOperations, timezoneOffset);
|
||||
}
|
||||
|
||||
var factOperations = operations.Where(o => o.IdType == 1);
|
||||
if (factOperations.Any())
|
||||
{
|
||||
var sheetFact = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameFact);
|
||||
if (sheetFact is not null)
|
||||
AddOperationsToSheet(sheetFact, factOperations, timezoneOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddOperationsToSheet(IXLWorksheet sheet, IEnumerable<WellOperation> operations, double timezoneOffset)
|
||||
{
|
||||
var operationsList = operations.ToList();
|
||||
for (int i = 0; i < operationsList.Count; i++)
|
||||
{
|
||||
var row = sheet.Row(1 + i + headerRowsCount);
|
||||
AddOperationToRow(row, operationsList[i], timezoneOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddOperationToRow(IXLRow row, WellOperation operation, double timezoneOffset)
|
||||
{
|
||||
row.Cell(columnSection).Value = operation.WellSectionType?.Caption;
|
||||
row.Cell(columnCategory).Value = operation.OperationCategory?.Name;
|
||||
row.Cell(columnCategoryInfo).Value = operation.CategoryInfo;
|
||||
row.Cell(columnDepthStart).Value = operation.DepthStart;
|
||||
row.Cell(columnDepthEnd).Value = operation.DepthEnd;
|
||||
row.Cell(columnDate).Value = operation.DateStart.ToRemoteDateTime(timezoneOffset);
|
||||
row.Cell(columnDuration).Value = operation.DurationHours;
|
||||
row.Cell(columnComment).Value = operation.Comment;
|
||||
}
|
||||
|
||||
private void SaveOperations(int idWell, IEnumerable<WellOperationDto> operations, bool deleteWellOperationsBeforeImport = false)
|
||||
{
|
||||
var timezone = wellService.GetTimezone(idWell);
|
||||
|
||||
var transaction = db.Database.BeginTransaction();
|
||||
try
|
||||
{
|
||||
if (deleteWellOperationsBeforeImport)
|
||||
db.WellOperations.RemoveRange(db.WellOperations.Where(o => o.IdWell == idWell));
|
||||
var entities = operations.Select(o =>
|
||||
{
|
||||
var entity = o.Adapt<WellOperation>();
|
||||
entity.IdWell = idWell;
|
||||
entity.DateStart = o.DateStart.ToUtcDateTimeOffset(timezone.Hours);
|
||||
entity.LastUpdateDate = DateTimeOffset.UtcNow;
|
||||
return entity;
|
||||
});
|
||||
db.WellOperations.AddRange(entities);
|
||||
db.SaveChanges();
|
||||
transaction.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<WellOperationDto> ParseFileStream(Stream stream)
|
||||
{
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
return ParseWorkbook(workbook);
|
||||
}
|
||||
|
||||
private IEnumerable<WellOperationDto> ParseWorkbook(IXLWorkbook workbook)
|
||||
{
|
||||
var sheetPlan = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlan);
|
||||
if (sheetPlan is null)
|
||||
throw new FileFormatException($"Книга excel не содержит листа {sheetNamePlan}.");
|
||||
|
||||
var sheetFact = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameFact);
|
||||
if (sheetFact is null)
|
||||
throw new FileFormatException($"Книга excel не содержит листа {sheetNameFact}.");
|
||||
|
||||
//sheetPlan.RangeUsed().RangeAddress.LastAddress.ColumnNumber
|
||||
var wellOperations = new List<WellOperationDto>();
|
||||
|
||||
var wellOperationsPlan = ParseSheet(sheetPlan, 0);
|
||||
wellOperations.AddRange(wellOperationsPlan);
|
||||
|
||||
var wellOperationsFact = ParseSheet(sheetFact, 1);
|
||||
wellOperations.AddRange(wellOperationsFact);
|
||||
|
||||
return wellOperations;
|
||||
}
|
||||
|
||||
private IEnumerable<WellOperationDto> ParseSheet(IXLWorksheet sheet, int idType)
|
||||
{
|
||||
|
||||
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
|
||||
|
||||
var count = sheet.RowsUsed().Count() - headerRowsCount;
|
||||
|
||||
if (count > 1024)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество операций.");
|
||||
|
||||
if (count <= 0)
|
||||
return new List<WellOperationDto>();
|
||||
|
||||
var operations = new List<WellOperationDto>(count);
|
||||
var parseErrors = new List<string>();
|
||||
DateTime lastOperationDateStart = new DateTime();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var row = sheet.Row(1 + i + headerRowsCount);
|
||||
try
|
||||
{
|
||||
var operation = ParseRow(row, idType);
|
||||
operations.Add(operation);
|
||||
|
||||
if (lastOperationDateStart > operation.DateStart)
|
||||
parseErrors.Add($"Лист {sheet.Name} строка {row.RowNumber()} дата позднее даты предыдущей операции.");
|
||||
|
||||
lastOperationDateStart = operation.DateStart;
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
parseErrors.Add(ex.Message);
|
||||
}
|
||||
};
|
||||
|
||||
if (parseErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", parseErrors));
|
||||
else
|
||||
{
|
||||
if (operations.Any())
|
||||
if (operations.Min(o => o.DateStart) - operations.Max(o => o.DateStart) > drillingDurationLimitMax)
|
||||
parseErrors.Add($"Лист {sheet.Name} содержит диапазон дат больше {drillingDurationLimitMax}");
|
||||
}
|
||||
|
||||
return operations;
|
||||
}
|
||||
|
||||
private WellOperationDto ParseRow(IXLRow row, int idType)
|
||||
{
|
||||
var vSection = row.Cell(columnSection).Value;
|
||||
var vCategory = row.Cell(columnCategory).Value;
|
||||
var vCategoryInfo = row.Cell(columnCategoryInfo).Value;
|
||||
var vDepthStart = row.Cell(columnDepthStart).Value;
|
||||
var vDepthEnd = row.Cell(columnDepthEnd).Value;
|
||||
var vDate = row.Cell(columnDate).Value;
|
||||
var vDuration = row.Cell(columnDuration).Value;
|
||||
var vComment = row.Cell(columnComment).Value;
|
||||
|
||||
var operation = new WellOperationDto { IdType = idType };
|
||||
|
||||
if (vSection is string sectionName)
|
||||
{
|
||||
var section = Sections.Find(c => c.Caption.ToLower() == sectionName.ToLower());
|
||||
if (section is null)
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} указана некорректная секция");
|
||||
|
||||
operation.IdWellSectionType = section.Id;
|
||||
operation.WellSectionTypeName = section.Caption;
|
||||
}
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана секция");
|
||||
|
||||
if (vCategory is string categoryName)
|
||||
{
|
||||
var category = Categories.Find(c => c.Name.ToLower() == categoryName.ToLower());
|
||||
if (category is null)
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} указана некорректная операция ({categoryName})");
|
||||
|
||||
operation.IdCategory = category.Id;
|
||||
operation.CategoryName = category.Name;
|
||||
}
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана операция");
|
||||
|
||||
if (vCategoryInfo is not null)
|
||||
operation.CategoryInfo = vCategoryInfo.ToString();
|
||||
|
||||
if (vDepthStart is double depthStart && depthStart >= 0d && depthStart <= 20_000d)
|
||||
operation.DepthStart = depthStart;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана глубина на начало операции");
|
||||
|
||||
if (vDepthEnd is double depthEnd && depthEnd >= 0d && depthEnd <= 20_000d)
|
||||
operation.DepthEnd = depthEnd;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана глубина при завершении операции");
|
||||
|
||||
if (vDate is DateTime date && date > dateLimitMin && date < dateLimitMax)
|
||||
operation.DateStart = date;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} неправильно указана дата/время начала операции");
|
||||
|
||||
if (vDuration is double duration && duration >= 0d && duration <= 240d)
|
||||
operation.DurationHours = duration;
|
||||
else
|
||||
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана длительность операции");
|
||||
|
||||
if (vComment is not null)
|
||||
operation.Comment = vComment.ToString();
|
||||
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -146,16 +146,10 @@ namespace AsbCloudInfrastructure.Services
|
||||
public override async Task<int> InsertAsync(WellDto dto, CancellationToken token)
|
||||
{
|
||||
if (IsTelemetryAssignedToDifferentWell(dto))
|
||||
throw new ArgumentInvalidException("Телеметрия уже была привязана к другой скважине.", nameof(dto));
|
||||
|
||||
if (dto.IdWellType is < 1 or > 2)
|
||||
throw new ArgumentInvalidException("Тип скважины указан неправильно.", nameof(dto));
|
||||
|
||||
if (dto.IdState is < 0 or > 2)
|
||||
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), "Телеметрия уже была привязана к другой скважине.");
|
||||
|
||||
if (dto.Id != 0 && (await GetCacheAsync(token)).Any(w => w.Id == dto.Id))
|
||||
throw new ArgumentInvalidException($"Нельзя повторно добавить скважину с id: {dto.Id}", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), $"Нельзя повторно добавить скважину с id: {dto.Id}");
|
||||
|
||||
var entity = Convert(dto);
|
||||
|
||||
@ -181,13 +175,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
CancellationToken token)
|
||||
{
|
||||
if (IsTelemetryAssignedToDifferentWell(dto))
|
||||
throw new ArgumentInvalidException("Телеметрия уже была привязана к другой скважине.", nameof(dto));
|
||||
|
||||
if (dto.IdWellType is < 1 or > 2)
|
||||
throw new ArgumentInvalidException("Тип скважины указан неправильно.", nameof(dto));
|
||||
|
||||
if (dto.IdState is < 0 or > 2)
|
||||
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
|
||||
throw new ArgumentInvalidException(nameof(dto), "Телеметрия уже была привязана к другой скважине.");
|
||||
|
||||
var oldRelations = (await GetCacheRelationCompanyWellAsync(token))
|
||||
.Where(r => r.IdWell == dto.Id).ToArray();
|
||||
@ -302,9 +290,8 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public SimpleTimezoneDto GetTimezone(int idWell)
|
||||
{
|
||||
var well = GetOrDefault(idWell);
|
||||
if (well == null)
|
||||
throw new ArgumentInvalidException($"idWell: {idWell} does not exist.", nameof(idWell));
|
||||
var well = GetOrDefault(idWell)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), $"idWell: {idWell} does not exist.");
|
||||
return GetTimezone(well);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using AsbCloudApp.ValidationAttributes;
|
||||
using AsbCloudApp.Validation;
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
|
@ -70,20 +70,11 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <param name="user">Информация о новом пользователе</param>
|
||||
/// <returns code="200">Ок</returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public IActionResult Register(UserRegistrationDto user)
|
||||
{
|
||||
var code = authService.Register(user);
|
||||
return code switch
|
||||
{
|
||||
0 => Ok(),
|
||||
-1 => BadRequest("Логин должен быть длиннее 3х знаков."),
|
||||
-2 => BadRequest("Пароль должен быть длиннее 3х знаков."),
|
||||
-3 => BadRequest("Email не должен быть длиннее 255 знаков."),
|
||||
-4 => BadRequest("Телефон не должен быть длиннее 50 знаков."),
|
||||
-5 => BadRequest("Название должности не должно быть длиннее 255 символов."),
|
||||
-6 => BadRequest("Пользователь с таким логином уже зарегистрирован."),
|
||||
_ => BadRequest(),
|
||||
};
|
||||
authService.Register(user);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -92,6 +83,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <returns code="200">Ок</returns>
|
||||
[Authorize]
|
||||
[HttpPut("{idUser}/ChangePassword")]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public IActionResult ChangePassword([FromRoute] int idUser, [FromBody] string newPassword)
|
||||
{
|
||||
var editorUserId = User.GetUserId();
|
||||
@ -102,13 +94,8 @@ namespace AsbCloudWebApi.Controllers
|
||||
if (!((editorUserId == idUser) || userRepository.HasPermission((int)editorUserId, "Auth.edit")))
|
||||
return Forbid();
|
||||
|
||||
var code = authService.ChangePassword(idUser, newPassword);
|
||||
return code switch
|
||||
{
|
||||
0 => Ok(),
|
||||
-1 => BadRequest("Нет такого пользователя"),
|
||||
_ => BadRequest(),
|
||||
};
|
||||
authService.ChangePassword(idUser, newPassword);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,10 +88,11 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <returns>id</returns>
|
||||
[HttpPost("range")]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public virtual async Task<ActionResult<int>> InsertRangeAsync([FromBody] IEnumerable<T> values, CancellationToken token)
|
||||
{
|
||||
if (!values.Any())
|
||||
return BadRequest("there is no values to add");
|
||||
return this.ValidationBadRequest(nameof(values), "there is no values to add");
|
||||
|
||||
if (InsertForbidAsync is not null)
|
||||
foreach (var value in values)
|
||||
@ -110,6 +111,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <returns>1 - успешно отредактировано, 0 - нет</returns>
|
||||
[HttpPut]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public virtual async Task<ActionResult<int>> UpdateAsync([FromBody] T value, CancellationToken token)
|
||||
{
|
||||
if (UpdateForbidAsync is not null && await UpdateForbidAsync(value, token))
|
||||
@ -117,7 +119,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
|
||||
var result = await service.UpdateAsync(value, token).ConfigureAwait(false);
|
||||
if (result == ICrudRepository<T>.ErrorIdNotFound)
|
||||
return BadRequest($"id:{value.Id} does not exist in the db");
|
||||
return this.ValidationBadRequest(nameof(value.Id), $"id:{value.Id} does not exist");
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -169,8 +169,9 @@ namespace AsbCloudWebApi.Controllers
|
||||
if (!await UserHasAccesToWellAsync(idWell, token))
|
||||
return Forbid();
|
||||
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token)
|
||||
?? throw new ArgumentInvalidException($"Скважина c id:{idWell} не найдена", nameof(idWell));
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
if (well is null)
|
||||
return this.ValidationBadRequest(nameof(idWell), $"Скважина c id:{idWell} не найдена");
|
||||
|
||||
var stream = await dailyReportService.MakeReportAsync(idWell, date, token);
|
||||
if (stream is null)
|
||||
|
@ -119,10 +119,10 @@ namespace AsbCloudWebApi.Controllers
|
||||
return Forbid();
|
||||
|
||||
if (files.Count > 1)
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(files), "only 1 file can be uploaded"));
|
||||
return this.ValidationBadRequest(nameof(files), "only 1 file can be uploaded");
|
||||
|
||||
if (files.Count == 0)
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(files), "at list 1 file should be uploaded"));
|
||||
return this.ValidationBadRequest(nameof(files), "at list 1 file should be uploaded");
|
||||
|
||||
var fileName = files[0].FileName;
|
||||
|
||||
|
@ -2,7 +2,6 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -16,13 +15,10 @@ namespace AsbCloudWebApi.Controllers;
|
||||
public class ManualController : ControllerBase
|
||||
{
|
||||
private readonly IManualCatalogService manualCatalogService;
|
||||
private readonly IUserRepository userRepository;
|
||||
|
||||
public ManualController(IManualCatalogService manualCatalogService,
|
||||
IUserRepository userRepository)
|
||||
public ManualController(IManualCatalogService manualCatalogService)
|
||||
{
|
||||
this.manualCatalogService = manualCatalogService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -46,8 +42,6 @@ public class ManualController : ControllerBase
|
||||
if(!idUser.HasValue)
|
||||
throw new ForbidException("Не удается вас опознать");
|
||||
|
||||
AssertUserHasAccessToManual("Manual.edit");
|
||||
|
||||
using var fileStream = file.OpenReadStream();
|
||||
|
||||
var id = await manualCatalogService.SaveFileAsync(idDirectory, idUser.Value, file.FileName, fileStream, cancellationToken);
|
||||
@ -68,8 +62,6 @@ public class ManualController : ControllerBase
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> GetFileAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
AssertUserHasAccessToManual("Manual.get");
|
||||
|
||||
var file = await manualCatalogService.GetFileAsync(id, cancellationToken);
|
||||
|
||||
if (!file.HasValue)
|
||||
@ -90,16 +82,6 @@ public class ManualController : ControllerBase
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> DeleteFileAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
AssertUserHasAccessToManual("Manual.edit");
|
||||
|
||||
return Ok(await manualCatalogService.DeleteFileAsync(id, cancellationToken));
|
||||
}
|
||||
|
||||
private void AssertUserHasAccessToManual(string permissionName)
|
||||
{
|
||||
var idUser = User.GetUserId();
|
||||
|
||||
if (!idUser.HasValue || !userRepository.HasPermission(idUser.Value, permissionName))
|
||||
throw new ForbidException("У вас недостаточно прав");
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.Manuals;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -17,15 +16,12 @@ public class ManualDirectoryController : ControllerBase
|
||||
{
|
||||
private readonly IManualDirectoryRepository manualDirectoryRepository;
|
||||
private readonly IManualCatalogService manualCatalogService;
|
||||
private readonly IUserRepository userRepository;
|
||||
|
||||
public ManualDirectoryController(IManualDirectoryRepository manualDirectoryRepository,
|
||||
IManualCatalogService manualCatalogService,
|
||||
IUserRepository userRepository)
|
||||
IManualCatalogService manualCatalogService)
|
||||
{
|
||||
this.manualDirectoryRepository = manualDirectoryRepository;
|
||||
this.manualCatalogService = manualCatalogService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -36,14 +32,12 @@ public class ManualDirectoryController : ControllerBase
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Permission]
|
||||
[Permission("Manual.edit")]
|
||||
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> AddDirectoryAsync(string name, int? idParent, CancellationToken cancellationToken)
|
||||
{
|
||||
AssertUserHasAccessToManualDirectory("Manual.edit");
|
||||
|
||||
return Ok(await manualCatalogService.AddDirectoryAsync(name, idParent, cancellationToken));
|
||||
}
|
||||
|
||||
@ -55,13 +49,11 @@ public class ManualDirectoryController : ControllerBase
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
[Permission]
|
||||
[Permission("Manual.edit")]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> UpdateDirectoryAsync(int id, string name, CancellationToken cancellationToken)
|
||||
{
|
||||
AssertUserHasAccessToManualDirectory("Manual.edit");
|
||||
|
||||
await manualCatalogService.UpdateDirectoryAsync(id, name, cancellationToken);
|
||||
|
||||
return Ok();
|
||||
@ -74,13 +66,11 @@ public class ManualDirectoryController : ControllerBase
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[Permission]
|
||||
[Permission("Manual.delete")]
|
||||
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> DeleteDirectoryAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
AssertUserHasAccessToManualDirectory("Manual.edit");
|
||||
|
||||
return Ok(await manualCatalogService.DeleteDirectoryAsync(id, cancellationToken));
|
||||
}
|
||||
|
||||
@ -90,21 +80,11 @@ public class ManualDirectoryController : ControllerBase
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Permission]
|
||||
[Permission("Manual.get")]
|
||||
[ProducesResponseType(typeof(IEnumerable<ManualDirectoryDto>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> GetAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
AssertUserHasAccessToManualDirectory("Manual.get");
|
||||
|
||||
return Ok(await manualDirectoryRepository.GetTreeAsync(cancellationToken));
|
||||
}
|
||||
|
||||
private void AssertUserHasAccessToManualDirectory(string permissionName)
|
||||
{
|
||||
var idUser = User.GetUserId();
|
||||
|
||||
if (!idUser.HasValue || !userRepository.HasPermission(idUser.Value, permissionName))
|
||||
throw new ForbidException("У вас недостаточно прав");
|
||||
}
|
||||
}
|
@ -83,18 +83,15 @@ public class NotificationController : ControllerBase
|
||||
/// <returns></returns>
|
||||
[HttpGet("{idNotification}")]
|
||||
[ProducesResponseType(typeof(NotificationDto), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetAsync([Required] int idNotification,
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetAsync([Required] int idNotification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var notification = await notificationRepository.GetOrDefaultAsync(idNotification, cancellationToken);
|
||||
|
||||
if (notification is null)
|
||||
{
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(idNotification),
|
||||
"Уведомление не найдено"));
|
||||
}
|
||||
return this.ValidationBadRequest(nameof(idNotification), "Уведомление не найдено");
|
||||
|
||||
return Ok(notification);
|
||||
return Ok(notification);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -81,6 +81,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <returns>количество успешно записанных строк в БД</returns>
|
||||
[HttpPost("import/{deleteBeforeImport}")]
|
||||
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> ImportAsync(int idWell,
|
||||
[FromForm] IFormFileCollection files,
|
||||
bool deleteBeforeImport,
|
||||
@ -93,10 +94,10 @@ namespace AsbCloudWebApi.Controllers
|
||||
token).ConfigureAwait(false))
|
||||
return Forbid();
|
||||
if (files.Count < 1)
|
||||
return BadRequest("нет файла");
|
||||
return this.ValidationBadRequest(nameof(files), "нет файла");
|
||||
var file = files[0];
|
||||
if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
|
||||
return BadRequest("Требуется xlsx файл.");
|
||||
return this.ValidationBadRequest(nameof(files), "Требуется xlsx файл.");
|
||||
using Stream stream = file.OpenReadStream();
|
||||
|
||||
try
|
||||
@ -106,7 +107,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
return BadRequest(ex.Message);
|
||||
return this.ValidationBadRequest(nameof(files), ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,11 +64,12 @@ namespace AsbCloudWebApi.Controllers
|
||||
[Obsolete("use GetByUidAsync(..) instead")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(IEnumerable<ProcessMapPlanDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public IActionResult GetByTelemetry(string uid, DateTime updateFrom, CancellationToken token)
|
||||
{
|
||||
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
||||
if (idWell is null)
|
||||
return BadRequest($"Wrong uid {uid}");
|
||||
return this.ValidationBadRequest(nameof(uid), $"Wrong uid {uid}");
|
||||
return Ok(Enumerable.Empty<ProcessMapPlanDto>());
|
||||
}
|
||||
|
||||
@ -82,11 +83,12 @@ namespace AsbCloudWebApi.Controllers
|
||||
[HttpGet("/api/telemetry/{uid}/processMap")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(IEnumerable<ProcessMapPlanDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetByUidAsync(string uid, DateTime updateFrom, CancellationToken token)
|
||||
{
|
||||
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
||||
if (idWell is null)
|
||||
return BadRequest($"Wrong uid {uid}");
|
||||
return this.ValidationBadRequest(nameof(uid), $"Wrong uid {uid}");
|
||||
|
||||
var dto = await service.GetAllAsync((int)idWell,
|
||||
updateFrom, token);
|
||||
@ -191,6 +193,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("import/{idWell}/{options}")]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> ImportAsync(int idWell,
|
||||
int options,
|
||||
[Required] IFormFile file,
|
||||
@ -205,7 +208,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
return Forbid();
|
||||
|
||||
if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
|
||||
return BadRequest("Требуется xlsx файл.");
|
||||
return this.ValidationBadRequest(nameof(file), "Требуется xlsx файл.");
|
||||
|
||||
using Stream stream = file.OpenReadStream();
|
||||
|
||||
@ -219,7 +222,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
return BadRequest(ex.Message);
|
||||
return this.ValidationBadRequest(nameof(file), ex.Message);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
@ -258,6 +261,10 @@ namespace AsbCloudWebApi.Controllers
|
||||
if (!idUser.HasValue)
|
||||
return false;
|
||||
|
||||
var idCompany = User.GetCompanyId();
|
||||
if (!idCompany.HasValue || !await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token))
|
||||
return false;
|
||||
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
|
||||
if (well is null)
|
||||
|
@ -0,0 +1,96 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.ProcessMap;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Проработка скважины
|
||||
/// </summary>
|
||||
public class ProcessMapWellboreDevelopmentController : CrudWellRelatedController<ProcessMapWellboreDevelopmentDto,
|
||||
IProcessMapWellboreDevelopmentRepository>
|
||||
{
|
||||
private readonly IUserRepository userRepository;
|
||||
private readonly IProcessMapWellboreDevelopmentService processMapWellboreDevelopmentService;
|
||||
|
||||
public ProcessMapWellboreDevelopmentController(IWellService wellService,
|
||||
IProcessMapWellboreDevelopmentRepository processMapWellboreDevelopmentRepository,
|
||||
IUserRepository userRepository,
|
||||
IProcessMapWellboreDevelopmentService processMapWellboreDevelopmentService)
|
||||
: base(wellService, processMapWellboreDevelopmentRepository)
|
||||
{
|
||||
this.userRepository = userRepository;
|
||||
this.processMapWellboreDevelopmentService = processMapWellboreDevelopmentService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавить запись проработки
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ForbidException"></exception>
|
||||
public override async Task<ActionResult<int>> InsertAsync(ProcessMapWellboreDevelopmentDto value, CancellationToken token)
|
||||
{
|
||||
value.IdUser = User.GetUserId()
|
||||
?? throw new ForbidException("Неизвестный пользователь");
|
||||
|
||||
await AssertUserHasAccessToProcessMapWellboreDevelopmentAsync(value.IdWell, value.IdUser, token);
|
||||
|
||||
return await processMapWellboreDevelopmentService.InsertAsync(value, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновить запись проработки
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<ActionResult<int>> UpdateAsync(ProcessMapWellboreDevelopmentDto value, CancellationToken token)
|
||||
{
|
||||
value.IdUser = User.GetUserId()
|
||||
?? throw new ForbidException("Неизвестный пользователь");
|
||||
|
||||
await AssertUserHasAccessToProcessMapWellboreDevelopmentAsync(value.IdWell, value.IdUser, token);
|
||||
|
||||
return await processMapWellboreDevelopmentService.UpdateAsync(value, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает проработки по uid телеметрии
|
||||
/// </summary>
|
||||
/// <param name="uid">Уникальный ключ телеметрии</param>
|
||||
/// <param name="updateFrom">Необязательный параметр. Начальная дата</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("telemetry/{uid}")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(IEnumerable<ProcessMapWellboreDevelopmentDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetByUidAsync(string uid, DateTime updateFrom, CancellationToken cancellationToken)
|
||||
{
|
||||
var dto = await processMapWellboreDevelopmentService.GetByTelemetryAsync(uid, updateFrom,
|
||||
cancellationToken);
|
||||
|
||||
return Ok(dto);
|
||||
}
|
||||
|
||||
private async Task AssertUserHasAccessToProcessMapWellboreDevelopmentAsync(int idUser, int idWell, CancellationToken cancellationToken)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
|
||||
?? throw new ForbidException($"Скважины с {idWell} не существует");
|
||||
|
||||
var idCompany = User.GetCompanyId();
|
||||
if (!idCompany.HasValue || !await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, cancellationToken))
|
||||
throw new ForbidException("Нет доступа к скважине");
|
||||
|
||||
if (well.IdState == 2 && !userRepository.HasPermission(idUser, "ProcessMap.editCompletedWell"))
|
||||
throw new ForbidException("Недостаточно прав для редактирования РТК завершённой скважины");
|
||||
}
|
||||
}
|
@ -59,10 +59,11 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <returns></returns>
|
||||
[HttpGet("schema/{typeName}")]
|
||||
[ProducesResponseType(typeof(IEnumerable<string>), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public IActionResult GetSchema(string typeName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
return BadRequest("require typeName");
|
||||
return this.ValidationBadRequest(nameof(typeName), "require typeName");
|
||||
|
||||
var type = RuntimeTypeModel.Default
|
||||
.GetTypes()
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user