From 5fb9375955fc6522fd5a711a7f91c4ccf5df28e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Sat, 16 Dec 2023 13:22:23 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=80=D0=B0?= =?UTF-8?q?=D1=81=D1=87=D0=B5=D1=82=D1=8B=20=D0=BD=D0=B0=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B8=20=D0=BF=D0=BE=D0=B4=D1=81=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Subsystems/SubsystemActiveWellStatDto.cs | 50 +-- .../Subsystems/SubsystemOperationTimeDto.cs | 38 -- ...TimeRequest.cs => SubsystemTimeRequest.cs} | 37 +- AsbCloudApp/Services/ISubsystemService.cs | 40 ++ .../ISubsystemOperationTimeService.cs | 68 --- .../Model/DefaultData/DefaultContextData.cs | 2 +- .../WorkSubsystemAbfOperationTimeCalc.cs | 127 ------ .../WorkSubsystemOperationTimeCalcAbstract.cs | 102 ----- ...rkSubsystemOscillationOperationTimeCalc.cs | 186 -------- AsbCloudInfrastructure/DependencyInjection.cs | 4 +- .../DailyReport/DailyReportService.cs | 23 +- .../SubsystemOperationTimeService.cs | 397 ------------------ .../Services/Subsystems/SubsystemService.cs | 218 ++++++++++ .../Services/Subsystems/SybsystemDetector.cs | 56 --- .../Services/WellInfoService.cs | 8 +- AsbCloudInfrastructure/Startup.cs | 2 - .../Services/DailyReportServiceTest.cs | 11 +- .../Subsystems/SubsystemController.cs | 92 ++++ .../SubsystemOperationTimeController.cs | 162 ------- 19 files changed, 401 insertions(+), 1222 deletions(-) delete mode 100644 AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs rename AsbCloudApp/Requests/{SubsystemOperationTimeRequest.cs => SubsystemTimeRequest.cs} (56%) create mode 100644 AsbCloudApp/Services/ISubsystemService.cs delete mode 100644 AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs delete mode 100644 AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemAbfOperationTimeCalc.cs delete mode 100644 AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOperationTimeCalcAbstract.cs delete mode 100644 AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOscillationOperationTimeCalc.cs delete mode 100644 AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs create mode 100644 AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs delete mode 100644 AsbCloudInfrastructure/Services/Subsystems/SybsystemDetector.cs create mode 100644 AsbCloudWebApi/Controllers/Subsystems/SubsystemController.cs delete mode 100644 AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs diff --git a/AsbCloudApp/Data/Subsystems/SubsystemActiveWellStatDto.cs b/AsbCloudApp/Data/Subsystems/SubsystemActiveWellStatDto.cs index 4032358f..8636c252 100644 --- a/AsbCloudApp/Data/Subsystems/SubsystemActiveWellStatDto.cs +++ b/AsbCloudApp/Data/Subsystems/SubsystemActiveWellStatDto.cs @@ -1,30 +1,24 @@ -using System.Collections.Generic; -namespace AsbCloudApp.Data.Subsystems +namespace AsbCloudApp.Data.Subsystems; + +/// +/// Статистика наработки подсистем по активным скважинам +/// +public class SubsystemActiveWellStatDto { - /// - /// Статистика наработки подсистем по активным скважинам - /// - public class SubsystemActiveWellStatDto - { - /// - /// Активная скважина - /// - public WellInfoDto Well { get; set; } = null!; - /// - /// Наработки подсистемы АКБ - /// - public SubsystemStatDto? SubsystemAKB { get; set; } - /// - /// Наработки подсистемы МСЕ - /// - public SubsystemStatDto? SubsystemMSE { get; set; } - /// - /// Наработки подсистемы СПИН - /// - public SubsystemStatDto? SubsystemSpinMaster { get; set; } - /// - /// Наработки подсистемы ТОРК - /// - public SubsystemStatDto? SubsystemTorqueMaster { get; set; } - } + /// + /// Активная скважина + /// + public WellInfoDto Well { get; set; } = null!; + /// + /// Наработки подсистемы АПД + /// + public SubsystemStatDto? SubsystemAPD { get; set; } + /// + /// Наработки подсистемы СПИН + /// + public SubsystemStatDto? SubsystemSpinMaster { get; set; } + /// + /// Наработки подсистемы ТОРК + /// + public SubsystemStatDto? SubsystemTorqueMaster { get; set; } } \ No newline at end of file diff --git a/AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs b/AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs deleted file mode 100644 index 50a373d0..00000000 --- a/AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -namespace AsbCloudApp.Data.Subsystems -{ - /// - /// Модель информации о работе подсистемы - /// - public class SubsystemOperationTimeDto:IId - { - /// - /// Идентификатор - /// - public int Id { get; set; } - /// - /// идентификатор подсистемы - /// - public int IdSubsystem { get; set; } - /// - /// Название подсистемы - /// - public string SubsystemName { get; set; } = null!; - /// - /// дата/время включения подсистемы - /// - public DateTime DateStart { get; set; } - /// - /// дата/время выключения подсистемы - /// - public DateTime DateEnd { get; set; } - /// - /// глубина забоя на момент включения подсистемы - /// - public double DepthStart { get; set; } - /// - /// глубина забоя на момент выключения подсистемы - /// - public double DepthEnd { get; set; } - } -} diff --git a/AsbCloudApp/Requests/SubsystemOperationTimeRequest.cs b/AsbCloudApp/Requests/SubsystemTimeRequest.cs similarity index 56% rename from AsbCloudApp/Requests/SubsystemOperationTimeRequest.cs rename to AsbCloudApp/Requests/SubsystemTimeRequest.cs index 26aae17a..6f0cf8f9 100644 --- a/AsbCloudApp/Requests/SubsystemOperationTimeRequest.cs +++ b/AsbCloudApp/Requests/SubsystemTimeRequest.cs @@ -8,7 +8,7 @@ namespace AsbCloudApp.Requests /// /// класс с фильтрами для запроса /// - public class SubsystemOperationTimeRequest: RequestBase, IValidatableObject + public class SubsystemTimeRequest: RequestBase, IValidatableObject { private static readonly DateTime validationMinDate = new DateTime(2020,01,01,0,0,0,DateTimeKind.Utc); @@ -26,7 +26,7 @@ namespace AsbCloudApp.Requests /// /// Больше или равно дате /// - public DateTime? GtDate { get; set; }//TODO: its Ge* + public DateTime? GeDate { get; set; } /// /// Меньше или равно дате @@ -43,41 +43,20 @@ namespace AsbCloudApp.Requests /// public double? LtDepth { get; set; } - //TODO: Replace modes by DateTimeOffset LeDateStart, LeDateEnd - /// - /// информация попадает в выборку, если интервал выборки частично или полностью пересекается с запрашиваемым интервалом - /// - public const int SelectModeOuter = 0; - - /// - /// информация попадает в выборку, если интервал выборки строго полностью пересекается с запрашиваемым интервалом. - /// - public const int SelectModeInner = 1; - - /// - /// аналогично outer, но интервалы в частично пересекающиеся укорачиваются по границам интервала выборки. - /// - public const int SelectModeTrim = 2; - - /// - /// Режим выборки элементов - /// - public int SelectMode { get; set; } = SelectModeOuter; - /// public IEnumerable Validate(ValidationContext validationContext) { - if (GtDate.HasValue && GtDate < validationMinDate) + if (GeDate.HasValue && GeDate < validationMinDate) yield return new ValidationResult( $"Должно быть больше {validationMinDate:O})", - new[] { nameof(GtDate) }); + new[] { nameof(GeDate) }); - if (LtDate.HasValue && GtDate.HasValue) + if (LtDate.HasValue && GeDate.HasValue) { - if (LtDate < GtDate) + if (LtDate < GeDate) yield return new ValidationResult( - $"{nameof(LtDate)} должно быть больше {nameof(GtDate)}. ({LtDate:O} < {GtDate:O})", - new[] { nameof(LtDate), nameof(GtDate) }); + $"{nameof(LtDate)} должно быть больше {nameof(GeDate)}. ({LtDate:O} < {GeDate:O})", + new[] { nameof(LtDate), nameof(GeDate) }); } if (LtDepth.HasValue && GtDepth.HasValue) diff --git a/AsbCloudApp/Services/ISubsystemService.cs b/AsbCloudApp/Services/ISubsystemService.cs new file mode 100644 index 00000000..bbc9dcd4 --- /dev/null +++ b/AsbCloudApp/Services/ISubsystemService.cs @@ -0,0 +1,40 @@ +using AsbCloudApp.Data.Subsystems; +using AsbCloudApp.Requests; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudApp.Services; + +/// +/// Получение инфо о наработке подсистем +/// +public interface ISubsystemService +{ + /// + /// Статистика о наработке подсистем + /// + /// + /// + /// + Task> GetStatAsync(SubsystemTimeRequest request, CancellationToken token); + + /// + /// Получение статистики по наработке подсистем по активным скважинам + /// + /// + /// + /// + /// + /// + Task> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token); + + /// + /// Получение статистики по наработке подсистем по активным скважинам + /// + /// + /// + /// + Task> GetStatByActiveWells(IEnumerable wellIds, CancellationToken token); +} \ No newline at end of file diff --git a/AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs b/AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs deleted file mode 100644 index 67b29673..00000000 --- a/AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs +++ /dev/null @@ -1,68 +0,0 @@ -using AsbCloudApp.Data; -using AsbCloudApp.Data.Subsystems; -using AsbCloudApp.Requests; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudApp.Services.Subsystems -{ - /// - /// Получение инфо о наработке подсистем - /// - public interface ISubsystemOperationTimeService - { - /// - /// Статистика о наработке подсистем - /// - /// - /// - /// - Task> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token); - - /// - /// Удаление наработки по подсистемам. - /// Если удаляется конец, то фоновый сервис подсчета наработки восстановит эти данные. - /// Может потребоваться для запуска повторного расчета по новому алгоритму. - /// - /// - /// - /// - Task DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token); - - /// - /// Интервалы работы подсистем - /// - /// - /// - /// - Task> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token); - - /// - /// Временной диапазон за который есть статистика работы подсистем - /// - /// - /// - /// - Task GetDateRangeOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token); - - /// - /// Получение статистики по наработке подсистем по активным скважинам - /// - /// - /// - /// - /// - /// - Task> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token); - - /// - /// Получение статистики по наработке подсистем по активным скважинам - /// - /// - /// - /// - Task> GetStatByActiveWells(IEnumerable wellIds, CancellationToken token); - } -} diff --git a/AsbCloudDb/Model/DefaultData/DefaultContextData.cs b/AsbCloudDb/Model/DefaultData/DefaultContextData.cs index d749fc59..48d5a5cf 100644 --- a/AsbCloudDb/Model/DefaultData/DefaultContextData.cs +++ b/AsbCloudDb/Model/DefaultData/DefaultContextData.cs @@ -24,7 +24,7 @@ namespace AsbCloudDb.Model.DefaultData { typeof(WellType), new EntityFillerWellType()}, { typeof(MeasureCategory), new EntityFillerMeasureCategory()}, { typeof(CompanyType), new EntityFillerCompanyType()}, - { typeof(Subsystems.Subsystem), new EntityFillerSubsystem() }, + { typeof(Subsystem), new EntityFillerSubsystem() }, { typeof(NotificationCategory), new EntityNotificationCategory()}, }; return fillers; diff --git a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemAbfOperationTimeCalc.cs b/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemAbfOperationTimeCalc.cs deleted file mode 100644 index fb16781d..00000000 --- a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemAbfOperationTimeCalc.cs +++ /dev/null @@ -1,127 +0,0 @@ -using AsbCloudDb.Model; -using AsbCloudDb.Model.Subsystems; -using AsbCloudInfrastructure.Services.Subsystems; -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudInfrastructure.Background.PeriodicWorks; - -public class WorkSubsystemAbfOperationTimeCalc : WorkSubsystemOperationTimeCalcAbstract -{ - public WorkSubsystemAbfOperationTimeCalc() - : base("Subsystem automated bit feeding operation time calc") - { - Timeout = TimeSpan.FromMinutes(30); - } - - protected override async Task> OperationTimeAsync(int idTelemetry, DateTimeOffset geDate, IAsbCloudDbContext db, CancellationToken token) - { - static bool isSubsytemAkbRotor(short? mode) => mode == 1; - - static bool isSubsytemAkbSlide(short? mode) => mode == 3; - - static bool IsSubsystemMse(short? state) => (state & 1) > 0; - - var query = - $"select tt.date, tt.mode, tt.well_depth, tt.mse_state " + - $"from ( " + - $" select " + - $" date, " + - $" mode, " + - $" mse_state, " + - $" well_depth, " + - $" lag(mode,1) over (order by date) as mode_lag, " + - $" lead(mode,1) over (order by date) as mode_lead " + - $" from t_telemetry_data_saub " + - $" where id_telemetry = {idTelemetry} and well_depth is not null and well_depth > 0 " + - $" order by date ) as tt " + - $"where (tt.mode_lag is null or (tt.mode != tt.mode_lag and tt.mode_lead != tt.mode_lag)) and tt.date >= '{geDate:u}' " + - $"order by tt.date;"; - - using var result = await ExecuteReaderAsync(db, query, token); - - var subsystemsOperationTimes = new List(); - var detectorRotor = new SubsystemDetector(idTelemetry, idSubsystemAPDRotor, isSubsytemAkbRotor, IsValid); - var detectorSlide = new SubsystemDetector(idTelemetry, idSubsystemAPDSlide, isSubsytemAkbSlide, IsValid); - var detectorMse = new SubsystemDetector(idTelemetry, idSubsystemMse, IsSubsystemMse, IsValid); - - while (result.Read()) - { - var mode = result.GetFieldValue(1); - var state = result.GetFieldValue(3); - - var isAkbRotorEnable = isSubsytemAkbRotor(mode); - var isAkbSlideEnable = isSubsytemAkbSlide(mode); - var isMseEnable = IsSubsystemMse(state); - var date = result.GetFieldValue(0); - var depth = result.GetFieldValue(2); - - if (detectorRotor.TryDetect(mode, date, depth, out var detectedRotor)) - subsystemsOperationTimes.Add(detectedRotor!); - - if (detectorSlide.TryDetect(mode, date, depth, out var detectedSlide)) - subsystemsOperationTimes.Add(detectedSlide!); - - if (detectorMse.TryDetect(mode, date, depth, out var detectedMse)) - subsystemsOperationTimes.Add(detectedMse!); - } - - return subsystemsOperationTimes; - } - - private static async Task ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token) - { - var connection = db.Database.GetDbConnection(); - if ( - connection?.State is null || - connection.State == ConnectionState.Broken || - connection.State == ConnectionState.Closed) - { - await db.Database.OpenConnectionAsync(token); - connection = db.Database.GetDbConnection(); - } - using var command = connection.CreateCommand(); - command.CommandText = query; - - var result = await command.ExecuteReaderAsync(token); - return result; - } - - private static bool IsValid(SubsystemOperationTime item) - { - var validateCode = GetValidateErrorCode(item); - if (validateCode != 0) - { - var str = System.Text.Json.JsonSerializer.Serialize(item); - Trace.TraceWarning($"Wrong({validateCode}) SubsystemOperationTime: {str}"); - } - return validateCode == 0; - } - - private static int GetValidateErrorCode(SubsystemOperationTime item) - { - if (item.DateStart > item.DateEnd) - return -1; - if ((item.DateEnd - item.DateStart).TotalHours > 48) - return -2; - if (item.DepthEnd < item.DepthStart) - return -3; - if (item.DepthEnd - item.DepthStart > 2000d) - return -4; - if (item.DepthEnd < 0d) - return -5; - if (item.DepthStart < 0d) - return -6; - if (item.DepthEnd > 24_0000d) - return -7; - if (item.DepthStart > 24_0000d) - return -8; - return 0; - } -} diff --git a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOperationTimeCalcAbstract.cs b/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOperationTimeCalcAbstract.cs deleted file mode 100644 index b9fb6d23..00000000 --- a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOperationTimeCalcAbstract.cs +++ /dev/null @@ -1,102 +0,0 @@ -using AsbCloudApp.Data.SAUB; -using AsbCloudApp.Repositories; -using AsbCloudDb.Model; -using AsbCloudDb.Model.Subsystems; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudInfrastructure.Background.PeriodicWorks; - -public abstract class WorkSubsystemOperationTimeCalcAbstract : Work -{ - protected const int idSubsystemTorqueMaster = 65537; - protected const int idSubsystemSpinMaster = 65536; - protected const int idSubsystemAPDRotor = 11; - protected const int idSubsystemAPDSlide = 12; - protected const int idSubsystemMse = 2; - - private static TimeSpan obsoleteTime = TimeSpan.FromDays(365 * 100); - - public WorkSubsystemOperationTimeCalcAbstract(string workId) - : base(workId) - { - Timeout = TimeSpan.FromMinutes(30); - } - - protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) - { - var db = services.GetRequiredService(); - db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5)); - - var telemetryLastDetectedDates = await GetTelemetryLastDetectedDates(services, db, token); - - var count = telemetryLastDetectedDates.Count(); - var i = 0d; - - foreach (var item in telemetryLastDetectedDates) - { - onProgressCallback($"Start handling telemetry: {item.IdTelemetry} from {item.DateDetectedLast}", i++ / count); - var newOperationsSaub = await OperationTimeAsync(item.IdTelemetry, item.DateDetectedLast, db, token); - if (newOperationsSaub.Any()) - { - db.SubsystemOperationTimes.AddRange(newOperationsSaub); - await db.SaveChangesAsync(token); - } - } - - obsoleteTime = TimeSpan.FromDays(3); - } - - protected abstract Task> OperationTimeAsync(int idTelemetry, DateTimeOffset geDate, IAsbCloudDbContext db, CancellationToken token); - - private static async Task> GetTelemetryLastDetectedDates(IServiceProvider services, IAsbCloudDbContext db, CancellationToken token) - { - var telemetryDataCache = services.GetRequiredService>(); - - var updatingTelemetries = telemetryDataCache.GetStat() - .Where(tstat => (DateTimeOffset.Now - tstat.DateLast) < obsoleteTime); - - var telemetryIds = updatingTelemetries - .Select(t => t.IdTelemetry) - .ToArray(); - - IEnumerable lastDetectedDates = await GetLastSubsystemOperationTimeAsync(db, token); - lastDetectedDates = lastDetectedDates - .Where(s => telemetryIds.Contains(s.IdTelemetry)); - - var result = updatingTelemetries.Select(tstat => new TelemetryDateLast - { - IdTelemetry = tstat.IdTelemetry, - DateDetectedLast = lastDetectedDates.FirstOrDefault(ldd => ldd.IdTelemetry == tstat.IdTelemetry)?.DateDetectedLast - ?? DateTimeOffset.UnixEpoch, - DateTelemetryLast = tstat.DateLast - }); - return result; - } - - private static async Task> GetLastSubsystemOperationTimeAsync(IAsbCloudDbContext db, CancellationToken token) - { - var result = await db.SubsystemOperationTimes - .GroupBy(o => o.IdTelemetry) - .Select(g => new TelemetryDateLast - { - IdTelemetry = g.Key, - DateDetectedLast = g.Max(o => o.DateEnd) - }) - .ToArrayAsync(token); - return result; - } - - protected class TelemetryDateLast - { - public int IdTelemetry { get; set; } - public DateTimeOffset DateDetectedLast { get; set; } - public DateTimeOffset DateTelemetryLast { get; internal set; } - } -} diff --git a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOscillationOperationTimeCalc.cs b/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOscillationOperationTimeCalc.cs deleted file mode 100644 index b2a6800f..00000000 --- a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkSubsystemOscillationOperationTimeCalc.cs +++ /dev/null @@ -1,186 +0,0 @@ -using AsbCloudDb.Model; -using AsbCloudDb.Model.Subsystems; -using AsbCloudInfrastructure.Background; -using AsbCloudInfrastructure.Services.Subsystems; -using AsbCloudInfrastructure.Services.Subsystems.Utils; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudInfrastructure.Background.PeriodicWorks; - -public class WorkSubsystemOscillationOperationTimeCalc : WorkSubsystemOperationTimeCalcAbstract -{ - public WorkSubsystemOscillationOperationTimeCalc() - : base("Subsystem operation time calc") - { - Timeout = TimeSpan.FromMinutes(30); - } - - protected override async Task> OperationTimeAsync(int idTelemetry, DateTimeOffset geDate, IAsbCloudDbContext db, CancellationToken token) - { - static int? GetSubsytemId(short? mode, int? state) - { - // При изменении следующего кода сообщи в Vladimir.Sobolev@nedra.digital - if (state == 7 && (mode & 2) > 0) - return idSubsystemTorqueMaster;// демпфер - - if (state != 0 && state != 5 && state != 6 && state != 7) - return idSubsystemSpinMaster;// осцилляция - - return null; - } - - var querySpin = - $"select " + - $" tspin.date, " + - $" tspin.mode, " + - $" tspin.state " + - $"from ( " + - $" select " + - $" date, " + - $" mode, " + - $" lag(mode, 1) over (order by date) as mode_lag, " + - $" lead(mode, 1) over (order by date) as mode_lead, " + - $" state, " + - $" lag(state, 1) over (order by date) as state_lag " + - $" from t_telemetry_data_spin " + - $" where id_telemetry = {idTelemetry} and date >= '{geDate:u}'" + - $" order by date ) as tspin " + - $"where mode_lag is null or state_lag is null or (mode != mode_lag and mode_lead != mode_lag) or state != state_lag " + - $"order by date;"; - - var rows = new List<(int? IdSubsystem, DateTimeOffset Date)>(32); - - using var resultSpin = await ExecuteReaderAsync(db, querySpin, token); - int? idSubsystemLast = null; - while (resultSpin.Read()) - { - var mode = resultSpin.GetFieldValue(1); - var state = resultSpin.GetFieldValue(2); - var idSubsystem = GetSubsytemId(mode, state); - if (idSubsystemLast != idSubsystem) - { - idSubsystemLast = idSubsystem; - var date = resultSpin.GetFieldValue(0); - rows.Add((idSubsystem, date)); - } - } - await resultSpin.DisposeAsync(); - - if (rows.Count < 2) - return Enumerable.Empty(); - - var minSpinDate = rows.Min(i => i.Date); - var maxSpinDate = rows.Max(i => i.Date); - var depthInterpolation = await GetInterpolation(db, idTelemetry, minSpinDate, maxSpinDate, token); - - if (depthInterpolation is null) - return Enumerable.Empty(); - - var subsystemsOperationTimes = new List(32); - - for (int i = 1; i < rows.Count; i++) - { - var r0 = rows[i - 1]; - var r1 = rows[i]; - if (r0.IdSubsystem is not null && r0.IdSubsystem != r1.IdSubsystem) - { - var subsystemOperationTime = new SubsystemOperationTime() - { - IdTelemetry = idTelemetry, - IdSubsystem = r0.IdSubsystem.Value, - DateStart = r0.Date, - DateEnd = r1.Date, - DepthStart = depthInterpolation.GetDepth(r0.Date), - DepthEnd = depthInterpolation.GetDepth(r1.Date), - }; - - if (IsValid(subsystemOperationTime)) - subsystemsOperationTimes.Add(subsystemOperationTime); - } - } - - return subsystemsOperationTimes; - } - - private static async Task ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token) - { - var connection = db.Database.GetDbConnection(); - if ( - connection?.State is null || - connection.State == ConnectionState.Broken || - connection.State == ConnectionState.Closed) - { - await db.Database.OpenConnectionAsync(token); - connection = db.Database.GetDbConnection(); - } - using var command = connection.CreateCommand(); - command.CommandText = query; - - var result = await command.ExecuteReaderAsync(token); - return result; - } - - private static bool IsValid(SubsystemOperationTime item) - { - var validateCode = GetValidateErrorCode(item); - if (validateCode != 0) - { - var str = System.Text.Json.JsonSerializer.Serialize(item); - Trace.TraceWarning($"Wrong({validateCode}) SubsystemOperationTime: {str}"); - } - return validateCode == 0; - } - - private static int GetValidateErrorCode(SubsystemOperationTime item) - { - if (item.DateStart > item.DateEnd) - return -1; - if ((item.DateEnd - item.DateStart).TotalHours > 48) - return -2; - if (item.DepthEnd < item.DepthStart) - return -3; - if (item.DepthEnd - item.DepthStart > 2000d) - return -4; - if (item.DepthEnd < 0d) - return -5; - if (item.DepthStart < 0d) - return -6; - if (item.DepthEnd > 24_0000d) - return -7; - if (item.DepthStart > 24_0000d) - return -8; - return 0; - } - - private static async Task GetInterpolation(IAsbCloudDbContext db, int idTelemetry, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token) - { - var dataDepthFromSaub = await db.TelemetryDataSaub - .Where(d => d.IdTelemetry == idTelemetry) - .Where(d => d.DateTime >= dateBegin) - .Where(d => d.DateTime <= dateEnd) - .Where(d => d.WellDepth > 0) - .GroupBy(d => Math.Ceiling(d.WellDepth * 10)) - .Select(g => new - { - DateMin = g.Min(d => d.DateTime), - DepthMin = g.Min(d => d.WellDepth), - }) - .OrderBy(i => i.DateMin) - .ToArrayAsync(token); - - if (!dataDepthFromSaub.Any()) - return null; - - var depthInterpolation = new DepthInterpolation(dataDepthFromSaub.Select(i => (i.DateMin, i.DepthMin))); - return depthInterpolation; - } -} diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 4e7c8ee6..78d39f71 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -12,12 +12,10 @@ using AsbCloudApp.Services; using AsbCloudApp.Services.Notifications; using AsbCloudApp.Services.ProcessMaps; using AsbCloudApp.Services.ProcessMaps.WellDrilling; -using AsbCloudApp.Services.Subsystems; using AsbCloudApp.Services.WellOperationImport; using AsbCloudDb.Model; using AsbCloudDb.Model.Manuals; using AsbCloudDb.Model.ProcessMaps; -using AsbCloudDb.Model.Subsystems; using AsbCloudDb.Model.Trajectory; using AsbCloudInfrastructure.Background; using AsbCloudInfrastructure.Repository; @@ -209,7 +207,7 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient, CrudWellRelatedRepositoryBase>(); services.AddTransient(); diff --git a/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs b/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs index 9765c3e9..cbe64e03 100644 --- a/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs +++ b/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs @@ -16,7 +16,6 @@ using AsbCloudApp.Data.DailyReport.Blocks.WellOperation; using AsbCloudApp.Requests; using AsbCloudApp.Services.DailyReport; using AsbCloudApp.Services.ProcessMaps.WellDrilling; -using AsbCloudApp.Services.Subsystems; using AsbCloudDb.Model; using Mapster; @@ -29,7 +28,7 @@ public class DailyReportService : IDailyReportService private readonly IDailyReportRepository dailyReportRepository; private readonly IScheduleRepository scheduleRepository; private readonly IWellOperationRepository wellOperationRepository; - private readonly ISubsystemOperationTimeService subsystemOperationTimeService; + private readonly ISubsystemService subsystemService; private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingService; private readonly IDetectedOperationService detectedOperationService; @@ -38,7 +37,7 @@ public class DailyReportService : IDailyReportService IDailyReportRepository dailyReportRepository, IScheduleRepository scheduleRepository, IWellOperationRepository wellOperationRepository, - ISubsystemOperationTimeService subsystemOperationTimeService, + ISubsystemService subsystemService, IProcessMapReportWellDrillingService processMapReportWellDrillingService, IDetectedOperationService detectedOperationService) { @@ -47,7 +46,7 @@ public class DailyReportService : IDailyReportService this.dailyReportRepository = dailyReportRepository; this.scheduleRepository = scheduleRepository; this.wellOperationRepository = wellOperationRepository; - this.subsystemOperationTimeService = subsystemOperationTimeService; + this.subsystemService = subsystemService; this.processMapReportWellDrillingService = processMapReportWellDrillingService; this.detectedOperationService = detectedOperationService; } @@ -311,24 +310,24 @@ public class DailyReportService : IDailyReportService async Task> GetSubsystemsAsync() { - var subsystemOperationTimesPerWell = await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest + var subsystemsStatPerWell = await subsystemService.GetStatAsync(new SubsystemTimeRequest { IdWell = dailyReport.IdWell }, cancellationToken); - var subsystemOperationTimesPerDay = await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest + var subsystemsStatPerDay = await subsystemService.GetStatAsync(new SubsystemTimeRequest { IdWell = dailyReport.IdWell, - GtDate = dailyReport.Date, + GeDate = dailyReport.Date, LtDate = dailyReport.Date.AddHours(24) }, cancellationToken); - var subsystems = subsystemOperationTimesPerWell - .Select(subsystemOperationTime => new SubsystemRecordDto + var subsystems = subsystemsStatPerWell + .Select(subsystemStatPerWell => new SubsystemRecordDto { - Name = subsystemOperationTime.SubsystemName, - UsagePerDay = subsystemOperationTimesPerDay.FirstOrDefault(s => s.IdSubsystem == subsystemOperationTime.IdSubsystem)?.Adapt(), - UsagePerWell = subsystemOperationTime.Adapt() + Name = subsystemStatPerWell.SubsystemName, + UsagePerDay = subsystemsStatPerDay.FirstOrDefault(s => s.IdSubsystem == subsystemStatPerWell.IdSubsystem)?.Adapt(), + UsagePerWell = subsystemStatPerWell.Adapt() }).ToList(); if (dailyReport.SubsystemBlock?.Subsystems != null && dailyReport.SubsystemBlock.Subsystems.Any()) diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs deleted file mode 100644 index fc2d8f71..00000000 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs +++ /dev/null @@ -1,397 +0,0 @@ -using AsbCloudApp.Data; -using AsbCloudApp.Data.DetectedOperation; -using AsbCloudApp.Data.Subsystems; -using AsbCloudApp.Exceptions; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using AsbCloudApp.Services.Subsystems; -using AsbCloudDb; -using AsbCloudDb.Model; -using AsbCloudDb.Model.Subsystems; -using Mapster; -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudInfrastructure.Services.Subsystems; - -/// Todo: Выделить репозиторий -internal class SubsystemOperationTimeService : ISubsystemOperationTimeService -{ - private readonly IAsbCloudDbContext db; - private readonly IWellService wellService; - private readonly ICrudRepository subsystemService; - private readonly IDetectedOperationService detectedOperationService; - public const int IdSubsystemAKB = 1; - public const int IdSubsystemAKBRotor = 11; - public const int IdSubsystemAKBSlide = 12; - public const int IdSubsystemMSE = 2; - public const int IdSubsystemSpin = 65536; - public const int IdSubsystemTorque = 65537; - - public SubsystemOperationTimeService(IAsbCloudDbContext db, IWellService wellService, ICrudRepository subsystemService, IDetectedOperationService detectedOperationService) - { - this.db = db; - this.wellService = wellService; - this.subsystemService = subsystemService; - this.detectedOperationService = detectedOperationService; - } - - /// - public async Task DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token) - { - var well = await wellService.GetOrDefaultAsync(request.IdWell, token) - ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); - - var query = BuildQuery(request, well); - db.SubsystemOperationTimes.RemoveRange(query); - return await db.SaveChangesAsync(token); - } - - /// - public async Task> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token) - { - var well = await wellService.GetOrDefaultAsync(request.IdWell, token) - ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); - - var dtos = await GetOperationTimeAsync(request, well, token); - return dtos; - } - - private async Task> GetOperationTimeAsync(SubsystemOperationTimeRequest request, WellDto well, CancellationToken token) - { - var query = BuildQuery(request, well); - IEnumerable data = await query.ToListAsync(token); - - if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeInner) - { - if (request.GtDate is not null) - data = data.Where(o => o.DateStart >= request.GtDate.Value); - - if (request.LtDate is not null) - data = data.Where(o => o.DateEnd <= request.LtDate.Value); - } - else if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeTrim) - { - var begin = request.GtDate?.ToUtcDateTimeOffset(well.Timezone.Hours); - var end = request.LtDate?.ToUtcDateTimeOffset(well.Timezone.Hours); - data = TrimOperation(data, begin, end); - } - - var dtos = data.Select(o => Convert(o, well.Timezone.Hours)); - return dtos; - } - - /// - public async Task> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token) - { - var well = await wellService.GetOrDefaultAsync(request.IdWell, token) - ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); - - request.SelectMode = SubsystemOperationTimeRequest.SelectModeTrim; - var subsystemsTimes = await GetOperationTimeAsync(request, well, token); - if (subsystemsTimes is null) - return Enumerable.Empty(); - - var detectedOperationSummaryRequest = new DetectedOperationSummaryRequest() - { - IdsTelemetries = new[] {well.IdTelemetry!.Value}, - IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, - - GeDateStart = request.GtDate, - LeDateStart = request.LtDate, - - GeDepthStart = request.GtDepth, - LeDepthStart = request.LtDepth, - }; - var operationsSummaries = await detectedOperationService.GetOperationSummaryAsync(detectedOperationSummaryRequest, token); - if(!operationsSummaries.Any()) - return Enumerable.Empty(); - - var statList = CalcStat(subsystemsTimes, operationsSummaries); - return statList; - } - - private static IEnumerable TrimOperation(IEnumerable data, DateTimeOffset? gtDate, DateTimeOffset? ltDate) - { - if (!ltDate.HasValue && !gtDate.HasValue) - return data.Select(d => d.Adapt()); - - var items = data.Select((item) => - { - var operationTime = item.Adapt(); - if (!(item.DepthStart.HasValue && item.DepthEnd.HasValue)) - return operationTime; - - var dateDiff = (item.DateEnd - item.DateStart).TotalSeconds; - var depthDiff = item.DepthEnd.Value - item.DepthStart.Value; - var a = depthDiff / dateDiff; - var b = item.DepthStart.Value; - - if (gtDate.HasValue && item.DateStart < gtDate.Value) - { - operationTime.DateStart = gtDate.Value; - var x = (gtDate.Value - item.DateStart).TotalSeconds; - operationTime.DepthStart = (float)(a * x + b); - } - if (ltDate.HasValue && item.DateEnd > ltDate.Value) - { - operationTime.DateEnd = ltDate.Value; - var x = (ltDate.Value - item.DateStart).TotalSeconds; - operationTime.DepthEnd = (float)(a * x + b); - } - return operationTime; - }); - - return items; - } - - private IEnumerable CalcStat( - IEnumerable subsystemsTimes, - IEnumerable operationsSummaries) - { - var groupedSubsystemsTimes = subsystemsTimes - .OrderBy(o => o.Id) - .GroupBy(o => o.IdSubsystem); - - var result = groupedSubsystemsTimes.Select(g => - { - var periodGroup = g.Sum(o => (o.DateEnd - o.DateStart).TotalHours); - var periodGroupDepth = g.Sum(o => o.DepthEnd - o.DepthStart); - var (sumOprationsDepth, sumOprationsDurationHours) = AggregateOperationsSummaries(g.Key, operationsSummaries); - var subsystemStat = new SubsystemStatDto() - { - IdSubsystem = g.Key, - SubsystemName = subsystemService.GetOrDefault(g.Key)?.Name ?? "unknown", - UsedTimeHours = periodGroup, - SumOperationDepthInterval = sumOprationsDepth, - SumOperationDurationHours = sumOprationsDurationHours, - SumDepthInterval = periodGroupDepth, - KUsage = periodGroupDepth / sumOprationsDepth, - OperationCount = g.Count(), - }; - if (subsystemStat.KUsage > 1) - subsystemStat.KUsage = 1; - return subsystemStat; - }); - - var apdParts = result.Where(x => x.IdSubsystem == 11 || x.IdSubsystem == 12); - if (apdParts.Any()) - { - var apdSum = new SubsystemStatDto() - { - IdSubsystem = IdSubsystemAKB, - SubsystemName = "АПД", - UsedTimeHours = apdParts.Sum(part => part.UsedTimeHours), - SumOperationDepthInterval = apdParts.Sum(part => part.SumOperationDepthInterval), - SumOperationDurationHours = apdParts.Sum(part => part.SumOperationDurationHours), - SumDepthInterval = apdParts.Sum(part => part.SumDepthInterval), - OperationCount = apdParts.Sum(part => part.OperationCount), - }; - - operationsSummaries = operationsSummaries.Where(o => o.EnabledSubsystems == 1); - - var (_, sumOprationsDurationHours) = AggregateOperationsSummaries(IdSubsystemAKBRotor, operationsSummaries); - apdSum.KUsage = sumOprationsDurationHours / apdSum.SumOperationDurationHours; - if (apdSum.KUsage > 1) - apdSum.KUsage = 1; - result = result.Append(apdSum).OrderBy(m => m.IdSubsystem); - } - - return result; - } - - private static (double SumDepth, double SumDurationHours) AggregateOperationsSummaries(int idSubsystem, IEnumerable operationsSummaries) - => idSubsystem switch - { - IdSubsystemAKBRotor or IdSubsystemTorque => CalcOperationSummariesByCategories(operationsSummaries, WellOperationCategory.IdRotor), - IdSubsystemAKBSlide or IdSubsystemSpin => CalcOperationSummariesByCategories(operationsSummaries, WellOperationCategory.IdSlide), - IdSubsystemAKB or IdSubsystemMSE => CalcOperationSummariesByCategories(operationsSummaries, WellOperationCategory.IdRotor, WellOperationCategory.IdSlide), - _ => throw new ArgumentException($"idSubsystem: {idSubsystem} does not supported in this method", nameof(idSubsystem)), - }; - - private static (double SumDepth, double SumDurationHours) CalcOperationSummariesByCategories( - IEnumerable operationsSummaries, - params int[] idsOperationCategories) - { - var filtered = operationsSummaries.Where(sum => idsOperationCategories.Contains(sum.IdCategory)); - var sumDepth = filtered.Sum(summ => summ.SumDepthIntervals); - var sumDurationHours = filtered.Sum(summ => summ.SumDurationHours); - return (sumDepth, sumDurationHours); - } - - /// - public async Task> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token) - { - var activeWells = await wellService.GetAsync(new() { IdCompany = idCompany, IdState = 1 }, token); - var result = await GetStatAsync(activeWells, gtDate, ltDate, token); - return result; - } - - /// - public async Task> GetStatByActiveWells(IEnumerable wellIds, CancellationToken token) - { - var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token); - var result = await GetStatAsync(activeWells, null, null, token); - return result; - } - - private async Task> GetStatAsync(IEnumerable wells, DateTime? gtDate, DateTime? ltDate, CancellationToken token) - { - if (!wells.Any()) - return Enumerable.Empty(); - - var hoursOffset = wells - .FirstOrDefault(well => well.Timezone is not null) - ?.Timezone.Hours - ?? 5d; - - var beginUTC = gtDate.HasValue - ? gtDate.Value.ToUtcDateTimeOffset(hoursOffset) - : db.SubsystemOperationTimes.Min(s => s.DateStart) - .DateTime - .ToUtcDateTimeOffset(hoursOffset); - - var endUTC = ltDate.HasValue - ? ltDate.Value.ToUtcDateTimeOffset(hoursOffset) - : db.SubsystemOperationTimes.Max(s => s.DateEnd) - .DateTime - .ToUtcDateTimeOffset(hoursOffset); - - IEnumerable idsTelemetries = wells - .Where(w => w.IdTelemetry is not null) - .Select(w => w.IdTelemetry!.Value) - .Distinct(); - - var query = db.SubsystemOperationTimes - .Where(o => idsTelemetries.Contains(o.IdTelemetry) && - o.DateStart >= beginUTC && - o.DateEnd <= endUTC) - .AsNoTracking(); - - var subsystemsOperationTime = await query.ToArrayAsync(token); - - var operationSummaries = await detectedOperationService - .GetOperationSummaryAsync(new () - { - IdsTelemetries = idsTelemetries, - IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, - GeDateStart = beginUTC, - LeDateEnd = endUTC, - }, token); - - var result = wells - .Select(well => { - var dtos = subsystemsOperationTime - .Where(s => s.IdTelemetry == well.IdTelemetry) - .Select(s => Convert(s, well.Timezone.Hours)); - - var wellStat = new SubsystemActiveWellStatDto{ Well = well }; - - var telemetryOperationSummaries = operationSummaries.Where(summ => summ.IdTelemetry == well.IdTelemetry); - if (telemetryOperationSummaries.Any()) - { - var subsystemStat = CalcStat(dtos, telemetryOperationSummaries); - if (subsystemStat.Any()) - { - wellStat.SubsystemAKB = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAKB); - wellStat.SubsystemMSE = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemMSE); - wellStat.SubsystemSpinMaster = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemSpin); - wellStat.SubsystemTorqueMaster = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemTorque); - } - } - - return wellStat; - }); - - return result; - } - - /// - public async Task GetDateRangeOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token) - { - var well = await wellService.GetOrDefaultAsync(request.IdWell, token) - ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); - - var query = BuildQuery(request, well); - if (query is null) - { - return null; - } - var result = await query - .GroupBy(o => o.IdTelemetry) - .Select(g => new DatesRangeDto - { - From = g.Min(o => o.DateStart).DateTime, - To = g.Max(o => o.DateEnd).DateTime - }) - .FirstOrDefaultAsync(token); - return result; - } - - private IQueryable BuildQuery(SubsystemOperationTimeRequest request, WellDto well) - { - var idTelemetry = well.IdTelemetry - ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} has no telemetry"); - - var query = db.SubsystemOperationTimes - .Include(o => o.Subsystem) - .Where(o => o.IdTelemetry == idTelemetry) - .AsNoTracking(); - - if (request.IdsSubsystems.Any()) - query = query.Where(o => request.IdsSubsystems.Contains(o.IdSubsystem)); - - // # Dates range condition - // [GtDate LtDate] - // [DateStart DateEnd] [DateStart DateEnd] - if (request.GtDate.HasValue) - { - DateTimeOffset gtDate = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - query = query.Where(o => o.DateEnd >= gtDate); - } - - if (request.LtDate.HasValue) - { - DateTimeOffset ltDate = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - query = query.Where(o => o.DateStart <= ltDate); - } - - if (request.GtDepth.HasValue) - query = query.Where(o => o.DepthEnd >= request.GtDepth.Value); - - if (request.LtDepth.HasValue) - query = query.Where(o => o.DepthStart <= request.LtDepth.Value); - - if (request?.SortFields?.Any() == true) - { - query = query.SortBy(request.SortFields); - } - else - { - query = query - .OrderBy(o => o.DateStart) - .ThenBy(o => o.DepthStart); - } - - if (request?.Skip > 0) - query = query.Skip((int)request.Skip); - - if (request?.Take > 0) - query = query.Take((int)request.Take); - - return query; - } - - private static SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, double? timezoneHours = null) - { - var dto = operationTime.Adapt(); - var hours = timezoneHours ?? operationTime.Telemetry.TimeZone.Hours; - dto.DateStart = operationTime.DateStart.ToRemoteDateTime(hours); - dto.DateEnd = operationTime.DateEnd.ToRemoteDateTime(hours); - return dto; - } -} diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs new file mode 100644 index 00000000..e678aadd --- /dev/null +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs @@ -0,0 +1,218 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.DetectedOperation; +using AsbCloudApp.Data.Subsystems; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudDb.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Services.Subsystems; + +internal class SubsystemService : ISubsystemService +{ + private const int IdEnabledSubsystemSpinMaster = 128; + + private const int IdSubsystemAPD = 1; + private const int IdSubsystemAPDRotor = 11; + private const int IdSubsystemAPDSlide = 12; + private const int IdSubsystemSpinMaster = 65536; + + private readonly ICrudRepository subsystemRepository; + + private readonly IWellService wellService; + private readonly IDetectedOperationService detectedOperationService; + private readonly ITelemetryDataSaubService telemetryDataSaubService; + + public SubsystemService(ICrudRepository subsystemRepository, + IWellService wellService, + IDetectedOperationService detectedOperationService, + ITelemetryDataSaubService telemetryDataSaubService) + { + this.wellService = wellService; + this.subsystemRepository = subsystemRepository; + this.detectedOperationService = detectedOperationService; + this.telemetryDataSaubService = telemetryDataSaubService; + } + + public async Task> GetStatAsync(SubsystemTimeRequest request, CancellationToken token) + { + var well = await wellService.GetOrDefaultAsync(request.IdWell, token) + ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); + + var detectedOperationSummaryRequest = new DetectedOperationSummaryRequest + { + IdsTelemetries = new[] { well.IdTelemetry!.Value }, + IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, + + GeDateStart = request.GeDate, + LeDateStart = request.LtDate, + + GeDepthStart = request.GtDepth, + LeDepthStart = request.LtDepth, + }; + + var operations = await detectedOperationService.GetOperationSummaryAsync(detectedOperationSummaryRequest, + token); + + if (!operations.Any()) + return Enumerable.Empty(); + + var stat = await CalcStatAsync(operations, token); + return stat; + } + + public async Task> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, + CancellationToken token) + { + var activeWells = await wellService.GetAsync(new() { IdCompany = idCompany, IdState = 1 }, token); + var result = await GetStatAsync(activeWells, gtDate, ltDate, token); + return result; + } + + public async Task> GetStatByActiveWells(IEnumerable wellIds, CancellationToken token) + { + var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token); + var result = await GetStatAsync(activeWells, null, null, token); + return result; + } + + private async Task> CalcStatAsync(IEnumerable operations, CancellationToken token) + { + var subsystems = await subsystemRepository.GetAllAsync(token); + + var groupedOperations = operations + .GroupBy(o => o.IdCategory); + + var stat = groupedOperations.Select(groupOperations => + { + var idSubsystem = groupOperations.Key switch + { + WellOperationCategory.IdRotor => IdSubsystemAPDRotor, + WellOperationCategory.IdSlide => IdSubsystemAPDSlide, + _ => throw new ArgumentException($"IdCategory: {groupOperations.Key} does not supported in this method", + nameof(groupOperations.Key)), + }; + + var operationsWithEnableSubsystems = groupOperations.Where(o => o.EnabledSubsystems >= 1); + + var subsystemStat = new SubsystemStatDto + { + IdSubsystem = idSubsystem, + SubsystemName = subsystems.FirstOrDefault(s => s.Id == idSubsystem)?.Name ?? "unknown", + UsedTimeHours = operationsWithEnableSubsystems.Sum(o => o.SumDurationHours), + SumOperationDepthInterval = groupOperations.Sum(o => o.SumDepthIntervals), + SumOperationDurationHours = groupOperations.Sum(o => o.SumDurationHours), + SumDepthInterval = operationsWithEnableSubsystems.Sum(o => o.SumDepthIntervals), + OperationCount = operationsWithEnableSubsystems.Sum(o => o.Count), + }; + + subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval; + + return subsystemStat; + }); + + var apdSlidePart = stat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPDSlide); + + if (apdSlidePart is not null) + { + var operationsWithSpinMaster = operations.Where(s => s.EnabledSubsystems == IdEnabledSubsystemSpinMaster); + + var spin = new SubsystemStatDto + { + IdSubsystem = IdSubsystemSpinMaster, + SubsystemName = subsystems.FirstOrDefault(s => s.Id == IdSubsystemSpinMaster)?.Name ?? "unknown", + UsedTimeHours = operationsWithSpinMaster.Sum(o => o.SumDurationHours), + SumOperationDepthInterval = apdSlidePart.SumOperationDepthInterval, + SumOperationDurationHours = apdSlidePart.SumOperationDurationHours, + SumDepthInterval = operationsWithSpinMaster.Sum(o => o.SumDepthIntervals), + OperationCount = operationsWithSpinMaster.Sum(s => s.Count) + }; + + spin.KUsage = spin.SumDepthInterval / spin.SumOperationDepthInterval; + + stat = stat.Append(spin); + } + + var apdParts = stat.Where(s => s.IdSubsystem is IdSubsystemAPDRotor or IdSubsystemAPDSlide); + + if (!apdParts.Any()) + return stat; + + var apdSum = new SubsystemStatDto + { + IdSubsystem = IdSubsystemAPD, + SubsystemName = "АПД", + UsedTimeHours = apdParts.Sum(part => part.UsedTimeHours), + SumOperationDepthInterval = apdParts.Sum(part => part.SumOperationDepthInterval), + SumOperationDurationHours = apdParts.Sum(part => part.SumOperationDurationHours), + SumDepthInterval = apdParts.Sum(part => part.SumDepthInterval), + OperationCount = apdParts.Sum(part => part.OperationCount), + }; + + apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval; + + stat = stat.Append(apdSum).OrderBy(m => m.IdSubsystem); + + return stat; + } + + private async Task> GetStatAsync(IEnumerable wells, DateTime? gtDate, DateTime? ltDate, + CancellationToken token) + { + if (!wells.Any()) + return Enumerable.Empty(); + + var idsTelemetries = wells + .Where(w => w.IdTelemetry is not null) + .Select(w => w.IdTelemetry!.Value) + .Distinct(); + + var wellsStat = new List(); + + foreach (var well in wells) + { + var hoursOffset = well.Timezone.Hours; + + var dateRange = telemetryDataSaubService.GetRange(well.Id); + + var beginUTC = gtDate.HasValue + ? gtDate.Value.ToUtcDateTimeOffset(hoursOffset) + : dateRange.From.ToUtcDateTimeOffset(hoursOffset); + + var endUTC = ltDate.HasValue + ? ltDate.Value.ToUtcDateTimeOffset(hoursOffset) + : dateRange.To.ToUtcDateTimeOffset(hoursOffset); + + var operations = await detectedOperationService + .GetOperationSummaryAsync(new() + { + IdsTelemetries = idsTelemetries, + IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, + GeDateStart = beginUTC, + LeDateEnd = endUTC, + }, token); + + var wellStat = new SubsystemActiveWellStatDto { Well = well }; + + var telemetryOperations = operations.Where(o => o.IdTelemetry == well.IdTelemetry); + + if (!telemetryOperations.Any()) + continue; + + var subsystemStat = await CalcStatAsync(telemetryOperations, token); + + if (!subsystemStat.Any()) + continue; + + wellStat.SubsystemAPD = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPD); + wellStat.SubsystemSpinMaster = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemSpinMaster); + } + + return wellsStat; + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Subsystems/SybsystemDetector.cs b/AsbCloudInfrastructure/Services/Subsystems/SybsystemDetector.cs deleted file mode 100644 index 5444d045..00000000 --- a/AsbCloudInfrastructure/Services/Subsystems/SybsystemDetector.cs +++ /dev/null @@ -1,56 +0,0 @@ -using AsbCloudDb.Model.Subsystems; -using System; - -namespace AsbCloudInfrastructure.Services.Subsystems -{ - public class SubsystemDetector - { - private readonly int idTelemetry; - private readonly int idSubsystem; - private readonly Func isEnable; - private readonly Func isValid; - (bool isEnable, DateTimeOffset date, float depth) pre = default; - - public SubsystemDetector( - int idTelemetry, - int idSubsystem, - Func isEnable, - Func isValid) - { - this.idTelemetry = idTelemetry; - this.idSubsystem = idSubsystem; - this.isEnable = isEnable; - this.isValid = isValid; - } - - public bool TryDetect(short? mode, DateTimeOffset date, float depth, out SubsystemOperationTime? subsystemOperationTime) - { - var isEnable = this.isEnable(mode); - - if (!pre.isEnable && isEnable) - { - pre = (true, date, depth); - } - else if (pre.isEnable && !isEnable) - { - var detected = new SubsystemOperationTime - { - IdTelemetry = idTelemetry, - IdSubsystem = idSubsystem, - DateStart = pre.date, - DateEnd = date, - DepthStart = pre.depth, - DepthEnd = depth, - }; - pre.isEnable = false; - if (isValid(detected)) - { - subsystemOperationTime = detected; - return true; - } - } - subsystemOperationTime = null; - return false; - } - } -} diff --git a/AsbCloudInfrastructure/Services/WellInfoService.cs b/AsbCloudInfrastructure/Services/WellInfoService.cs index 0bf2fd0c..6caa2c08 100644 --- a/AsbCloudInfrastructure/Services/WellInfoService.cs +++ b/AsbCloudInfrastructure/Services/WellInfoService.cs @@ -4,9 +4,7 @@ using AsbCloudApp.Data.WITS; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; -using AsbCloudApp.Services.Subsystems; using AsbCloudInfrastructure.Background; -using AsbCloudInfrastructure.Services.SAUB; using Mapster; using Microsoft.Extensions.DependencyInjection; using System; @@ -35,7 +33,7 @@ public class WellInfoService var wellService = services.GetRequiredService(); var operationsStatService = services.GetRequiredService(); var processMapPlanWellDrillingRepository = services.GetRequiredService>(); - var subsystemOperationTimeService = services.GetRequiredService(); + var subsystemService = services.GetRequiredService(); var telemetryDataSaubCache = services.GetRequiredService>(); var messageHub = services.GetRequiredService>(); @@ -57,7 +55,7 @@ public class WellInfoService var operationsStat = await operationsStatService.GetWellsStatAsync(wellsIds, token); - var subsystemStat = await subsystemOperationTimeService + var subsystemStat = await subsystemService .GetStatByActiveWells(wellsIds, token); subsystemStat = subsystemStat.ToArray(); @@ -157,7 +155,7 @@ public class WellInfoService }; var wellSubsystemStat = subsystemStat.FirstOrDefault(s => s.Well.Id == well.Id); - wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAKB?.KUsage ?? 0d; + wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAPD?.KUsage ?? 0d; wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemSpinMaster?.KUsage ?? 0d; wellMapInfo.TorqueKUsage = wellSubsystemStat?.SubsystemTorqueMaster?.KUsage ?? 0d; wellMapInfo.TvdLagDays = wellOperationsStat?.TvdLagDays; diff --git a/AsbCloudInfrastructure/Startup.cs b/AsbCloudInfrastructure/Startup.cs index 3af21638..cfb2a9e7 100644 --- a/AsbCloudInfrastructure/Startup.cs +++ b/AsbCloudInfrastructure/Startup.cs @@ -32,8 +32,6 @@ namespace AsbCloudInfrastructure backgroundWorker.Add(TimeSpan.FromDays(1)); backgroundWorker.Add(TimeSpan.FromMinutes(30)); backgroundWorker.Add(TimeSpan.FromMinutes(15)); - backgroundWorker.Add(TimeSpan.FromMinutes(30)); - backgroundWorker.Add(TimeSpan.FromMinutes(30)); backgroundWorker.Add(TimeSpan.FromMinutes(30)); backgroundWorker.Add(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1)); diff --git a/AsbCloudWebApi.Tests/UnitTests/Services/DailyReportServiceTest.cs b/AsbCloudWebApi.Tests/UnitTests/Services/DailyReportServiceTest.cs index 496ae9e4..934fe8e5 100644 --- a/AsbCloudWebApi.Tests/UnitTests/Services/DailyReportServiceTest.cs +++ b/AsbCloudWebApi.Tests/UnitTests/Services/DailyReportServiceTest.cs @@ -17,7 +17,6 @@ using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.ProcessMaps.WellDrilling; -using AsbCloudApp.Services.Subsystems; using AsbCloudInfrastructure.Services.DailyReport; using NSubstitute; using Xunit; @@ -191,7 +190,7 @@ public class DailyReportServiceTest } }; - private readonly SubsystemStatDto fakeStatSubsystemOperationTime = new() + private readonly SubsystemStatDto fakeSubsystemsStat = new() { SubsystemName = "АПД", SumDepthInterval = 250, @@ -204,7 +203,7 @@ public class DailyReportServiceTest private readonly IDailyReportRepository dailyReportRepositoryMock = Substitute.For(); private readonly IScheduleRepository scheduleRepositoryMock = Substitute.For(); private readonly IWellOperationRepository wellOperationRepositoryMock = Substitute.For(); - private readonly ISubsystemOperationTimeService subsystemOperationTimeServiceMock = Substitute.For(); + private readonly ISubsystemService subsystemServiceMock = Substitute.For(); private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingServiceMock = Substitute.For(); private readonly IDetectedOperationService detectedOperationServiceMock = Substitute.For(); @@ -245,7 +244,7 @@ public class DailyReportServiceTest dailyReportRepositoryMock, scheduleRepositoryMock, wellOperationRepositoryMock, - subsystemOperationTimeServiceMock, + subsystemServiceMock, processMapReportWellDrillingServiceMock, detectedOperationServiceMock); @@ -276,8 +275,8 @@ public class DailyReportServiceTest detectedOperationServiceMock.GetAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(fakeWellOperationSlipsTime); - subsystemOperationTimeServiceMock.GetStatAsync(Arg.Any(), Arg.Any()) - .ReturnsForAnyArgs(new[] { fakeStatSubsystemOperationTime }); + subsystemServiceMock.GetStatAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(new[] { fakeSubsystemsStat }); scheduleRepositoryMock.GetAsync(idWell, dateDailyReport, Arg.Any()) .ReturnsForAnyArgs(new[] { fakeShedule }); diff --git a/AsbCloudWebApi/Controllers/Subsystems/SubsystemController.cs b/AsbCloudWebApi/Controllers/Subsystems/SubsystemController.cs new file mode 100644 index 00000000..87e8fb88 --- /dev/null +++ b/AsbCloudWebApi/Controllers/Subsystems/SubsystemController.cs @@ -0,0 +1,92 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.Subsystems; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudWebApi.Controllers.Subsystems +{ + /// + /// Наработка подсистем + /// + [Route("api/[controller]")] + [ApiController] + [Authorize] + public class SubsystemController : ControllerBase + { + private readonly ISubsystemService subsystemService; + private readonly ITelemetryDataSaubService telemetryDataSaubService; + private readonly IWellService wellService; + + public SubsystemController( + ISubsystemService subsystemService, + IWellService wellService, + ITelemetryDataSaubService telemetryDataSaubService) + { + this.subsystemService = subsystemService; + this.wellService = wellService; + this.telemetryDataSaubService = telemetryDataSaubService; + } + /// + /// получить статистику + /// + [HttpGet("stat")] + [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] + [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)] + public async Task GetStatAsync([FromQuery] SubsystemTimeRequest request, CancellationToken token) + { + if (!await UserHasAccessToWellAsync(request.IdWell, token)) + return Forbid(); + var subsystemResult = await subsystemService.GetStatAsync(request, token); + return Ok(subsystemResult); + } + + /// + /// получить период, за который будет рассчитываться статистика + /// + [HttpGet("operationsPeriod/{idWell}")] + [ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)] + public async Task GetStatDateRangeAsync([FromRoute] int idWell, CancellationToken token) + { + if (!await UserHasAccessToWellAsync(idWell, token)) + return Forbid(); + + var dateRange = telemetryDataSaubService.GetRange(idWell); + + return Ok(dateRange); + } + + /// + /// получить статистику по активным скважинам + /// + /// Больше или равно дате + /// Меньше или равно дате + /// Токен + /// + [HttpGet("statByActiveWell")] + [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] + public async Task GetStatByWellAsync(DateTime? gtDate, DateTime? ltDate, CancellationToken token) + { + var idCompany = User.GetCompanyId(); + if (!idCompany.HasValue) + return Forbid(); + var subsystemResult = await subsystemService.GetStatByActiveWells(idCompany.Value, gtDate, ltDate, token); + return Ok(subsystemResult); + } + + private async Task UserHasAccessToWellAsync(int idWell, CancellationToken token) + { + var idCompany = User.GetCompanyId(); + if (idCompany is not null && + await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token) + .ConfigureAwait(false)) + return true; + return false; + } + } +} diff --git a/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs b/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs deleted file mode 100644 index 47ce3630..00000000 --- a/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs +++ /dev/null @@ -1,162 +0,0 @@ -using AsbCloudApp.Data; -using AsbCloudApp.Data.Subsystems; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using AsbCloudApp.Services.Subsystems; -using AsbCloudDb.Model; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudWebApi.Controllers.Subsystems -{ - /// - /// Наработка подсистем - /// - [Route("api/[controller]")] - [ApiController] - [Authorize] - public class SubsystemOperationTimeController : ControllerBase - { - private readonly ISubsystemOperationTimeService subsystemOperationTimeService; - private readonly ITelemetryDataSaubService telemetryDataSaubService; - private readonly IWellService wellService; - - private readonly Dictionary subsystemNames = new() - { - { 1, "SAUB" }, - { 65537, "Torque Master" }, - { 65536, "Spin Master" } - }; - - public SubsystemOperationTimeController( - ISubsystemOperationTimeService subsystemOperationTimeService, - IWellService wellService, - ITelemetryDataSaubService telemetryDataSaubService) - { - this.subsystemOperationTimeService = subsystemOperationTimeService; - this.wellService = wellService; - this.telemetryDataSaubService = telemetryDataSaubService; - } - /// - /// получить статистику - /// - [HttpGet("stat")] - [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] - [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)] - public async Task GetStatAsync([FromQuery] SubsystemOperationTimeRequest request, CancellationToken token) - { - if (!await UserHasAccessToWellAsync(request.IdWell, token)) - return Forbid(); - var subsystemResult = await subsystemOperationTimeService.GetStatAsync(request, token); - return Ok(subsystemResult); - } - - /// - /// получить период, за который будет рассчитываться статистика - /// - [HttpGet("operationsPeriod/{idWell}")] - [ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)] - public async Task GetStatDateRangeAsync([FromRoute] int idWell, CancellationToken token) - { - if (!await UserHasAccessToWellAsync(idWell, token)) - return Forbid(); - - var dateRange = telemetryDataSaubService.GetRange(idWell); - - return Ok(dateRange); - } - - /// - /// получить статистику по активным скважинам - /// - /// Больше или равно дате - /// Меньше или равно дате - /// Токен - /// - [HttpGet("statByActiveWell")] - [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] - public async Task GetStatByWellAsync(DateTime? GtDate, DateTime? LtDate, CancellationToken token) - { - var idCompany = User.GetCompanyId(); - if (!idCompany.HasValue) - return Forbid(); - var subsystemResult = await subsystemOperationTimeService.GetStatByActiveWells(idCompany.Value, GtDate, LtDate, token); - return Ok(subsystemResult); - } - - /// - /// получить доступный диапазон дат наработки подсистемы. - /// - [HttpGet("datesRange")] - [ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)] - public async Task GetDateRangeOperationTimeAsync([FromQuery] SubsystemOperationTimeRequest request, CancellationToken token) - { - if (!await UserHasAccessToWellAsync(request.IdWell, token)) - return Forbid(); - var result = await subsystemOperationTimeService.GetDateRangeOperationTimeAsync(request, token); - return Ok(result); - } - - /// - /// получить список наработок подсистем - /// - [HttpGet("operationTime")] - [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] - [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)] - public async Task GetOperationTimeAsync( - [FromQuery] SubsystemOperationTimeRequest request, - CancellationToken token) - { - if (!await UserHasAccessToWellAsync(request.IdWell, token)) - return Forbid(); - - var result = await subsystemOperationTimeService.GetOperationTimeAsync(request, token); - return Ok(result); - } - - /// - /// Удалить наработки. - /// - /// - /// - /// - [HttpDelete] - [Permission] - [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)] - [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)] - public async Task DeleteAsync( - [FromQuery] SubsystemOperationTimeRequest request, - CancellationToken token) - { - if (!await UserHasAccessToWellAsync(request.IdWell, token)) - return Forbid(); - var result = await subsystemOperationTimeService.DeleteAsync(request, token); - return Ok(result); - } - - /// - /// Получение словаря названий подсистем - /// - /// - [HttpGet("names")] - [ProducesResponseType(typeof(Dictionary), (int)System.Net.HttpStatusCode.OK)] - public IActionResult GetSubsystemsNames() - { - return Ok(subsystemNames); - } - - protected async Task UserHasAccessToWellAsync(int idWell, CancellationToken token) - { - var idCompany = User.GetCompanyId(); - if (idCompany is not null && - await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token) - .ConfigureAwait(false)) - return true; - return false; - } - } -}