diff --git a/AsbCloudApp/Data/LimitingParameterDataDto.cs b/AsbCloudApp/Data/LimitingParameterDataDto.cs index ee957947..83db213b 100644 --- a/AsbCloudApp/Data/LimitingParameterDataDto.cs +++ b/AsbCloudApp/Data/LimitingParameterDataDto.cs @@ -21,12 +21,12 @@ namespace AsbCloudApp.Data /// /// Дата начала ограничения /// - public DateTimeOffset DateStart { get; set; } + public DateTime DateStart { get; set; } /// /// Дата окончания ограничения /// - public DateTimeOffset DateEnd { get; set; } + public DateTime DateEnd { get; set; } /// /// Глубина начала ограничения diff --git a/AsbCloudApp/Data/ProcessMapDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapDto.cs similarity index 98% rename from AsbCloudApp/Data/ProcessMapDto.cs rename to AsbCloudApp/Data/ProcessMap/ProcessMapDto.cs index 72990b03..9a460acb 100644 --- a/AsbCloudApp/Data/ProcessMapDto.cs +++ b/AsbCloudApp/Data/ProcessMap/ProcessMapDto.cs @@ -1,6 +1,6 @@ using System; -namespace AsbCloudApp.Data +namespace AsbCloudApp.Data.ProcessMap { #nullable enable /// diff --git a/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs new file mode 100644 index 00000000..514de0f9 --- /dev/null +++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs @@ -0,0 +1,58 @@ +using System; + +namespace AsbCloudApp.Data.ProcessMap +{ +#nullable enable + /// + /// Модель РТК + /// + public class ProcessMapReportDto + { + /// + /// Идентификатор скважины + /// + public int IdWell { get; set; } + + /// + /// Глубина по стволу, м + /// + /// на начало интервала + /// + /// + public double DepthStart { get; set; } + + /// + /// Дата/ время + /// + /// на начало интервала + /// + /// + public DateTime DateStart { get; set; } + + /// + /// Время мех бурения, ч + /// + public double MechDrillingHours { get; set; } + + /// + /// Слайд + /// + public ProcessMapReportRowDto Slide { get; set; } = null!; + + /// + /// Ротор + /// + public ProcessMapReportRowDto Rotor { get; set; } = null!; + + /// + /// название секции скважины + /// + public int IdWellSectionType { get; set; } + + /// + /// название секции скважины + /// + public string WellSectionTypeName { get; set; } = null!; + } +#nullable disable +} diff --git a/AsbCloudApp/Data/ProcessMap/ProcessMapReportParamsDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapReportParamsDto.cs new file mode 100644 index 00000000..cf180f07 --- /dev/null +++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportParamsDto.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AsbCloudApp.Data.ProcessMap +{ +#nullable enable + /// + /// Параметры РТК + /// + public class ProcessMapReportParamsDto + { + /// + /// Уставка план + /// + public double? SetpointPlan { get; set; } + + /// + /// Уставка факт + /// + public double? SetpointFact { get; set; } + + /// + /// Факт + /// + public double? Fact { get; set; } + + /// + /// Ограничение + /// + public double? Limit { get; set; } + + /// + /// Процент бурения по уставке ,% + /// + public double? PercDrillingSetpoint { get; set; } + } +#nullable disable +} diff --git a/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs new file mode 100644 index 00000000..737f73ea --- /dev/null +++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs @@ -0,0 +1,45 @@ +namespace AsbCloudApp.Data.ProcessMap +{ +#nullable enable + /// + /// Строки РТК + /// + public class ProcessMapReportRowDto + { + /// + /// Проходка, м + /// + public double? DeltaDepth { get; set; } + + /// + /// Перепад давления, атм + /// + public ProcessMapReportParamsDto PressureDiff { get; set; } = new(); + + /// + /// Нагрузка, т + /// + public ProcessMapReportParamsDto AxialLoad { get; set; } = new(); + + /// + /// Момент на ВСП, кНхМ + /// + public ProcessMapReportParamsDto TopDriveTorque { get; set; } = new(); + + /// + /// Ограничение скорости, м/ч + /// + public ProcessMapReportParamsDto SpeedL​imit { get; set; } = new(); + + /// + /// Процент использования системы АПД, % + /// + public double Usage { get; set; } + + /// + /// Фактическая механическая скорость, м/ч + /// + public double Rop { get; set; } + } +#nullable disable +} diff --git a/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs b/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs new file mode 100644 index 00000000..90bbd5f0 --- /dev/null +++ b/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs @@ -0,0 +1,117 @@ +using System; + +namespace AsbCloudApp.Data.SAUB +{ +#nullable enable + /// + /// Статистика телеметрии САУБ (усредненные значения) по интервалам глубины + /// + public class TelemetryDataSaubStatDto + { + /// + /// Кол-во записей в интервале + /// + public int Count { get; set; } + + /// + /// Дата начала интервала + /// + public DateTime DateMin { get; set; } + + /// + /// Дата окончания интервала + /// + public DateTime DateMax { get; set; } + + /// + /// Глубина начала интервала + /// + public float WellDepthMin { get; set; } + + /// + /// Глубина окончания интервала + /// + public float WellDepthMax { get; set; } + + /// + /// Давление + /// + public float Pressure { get; set; } + + /// + /// действующее задание давления + /// + public float PressureSp { get; set; } + + /// + /// Давление при холостом ходе. + /// + public float PressureIdle { get; set; } + + /// + /// задание давления для роторного режима + /// + public float PressureSpRotor { get; set; } + + /// + /// задание давления для режима слайда + /// + public float PressureSpSlide { get; set; } + + /// + /// ограничение макс перепада давления + /// + public float PressureDeltaLimitMax { get; set; } + + /// + /// осевая нагрузка + /// + public float AxialLoad { get; set; } + + /// + /// задание осевой нагрузки + /// + public float AxialLoadSp { get; set; } + + /// + /// ограничение макс. осевой нагрузки + /// + public float AxialLoadLimitMax { get; set; } + + /// + /// момент ротора + /// + public float RotorTorque { get; set; } + + /// + /// задание момента ротора + /// + public float RotorTorqueSp { get; set; } + + /// + /// момент ротора на х.х. + /// + public float RotorTorqueLimitMax { get; set; } + + /// + /// Талевый блок. Скорость + /// + public float BlockSpeed { get; set; } + + /// + /// Талевый блок. Задание скорости + /// + public float BlockSpeedSp { get; set; } + + /// + /// Талевый блок. Задание скорости для роторного бурения + /// + public float BlockSpeedSpRotor { get; set; } + + /// + /// Талевый блок. Задание скорости для режима слайда + /// + public float BlockSpeedSpSlide { get; set; } + } +#nullable disable +} diff --git a/AsbCloudApp/Repositories/ILimitingParameterRepository.cs b/AsbCloudApp/Repositories/ILimitingParameterRepository.cs index 507270ef..a9b61823 100644 --- a/AsbCloudApp/Repositories/ILimitingParameterRepository.cs +++ b/AsbCloudApp/Repositories/ILimitingParameterRepository.cs @@ -20,6 +20,16 @@ namespace AsbCloudApp.Repositories /// /// Task> GetLimitingParametersAsync(LimitingParameterRequest request, WellDto wellDto, CancellationToken token); + + /// + /// Получение списка ограничивающих параметров по идентификатору скважины + /// + /// + /// + /// + /// + /// + Task> GetLimitingParametersAsync(LimitingParameterRequest request, int idTelemetry, double timezoneHours, CancellationToken token); } #nullable disable } diff --git a/AsbCloudApp/Services/IWellOperationService.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs similarity index 75% rename from AsbCloudApp/Services/IWellOperationService.cs rename to AsbCloudApp/Repositories/IWellOperationRepository.cs index 61b9b4b0..4075445f 100644 --- a/AsbCloudApp/Services/IWellOperationService.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -5,13 +5,13 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace AsbCloudApp.Services +namespace AsbCloudApp.Repositories { #nullable enable /// /// сервис операций по скважине /// - public interface IWellOperationService + public interface IWellOperationRepository { /// /// список названий операций @@ -19,61 +19,6 @@ namespace AsbCloudApp.Services /// IEnumerable GetCategories(); - // TODO: объединить параметры в объект запроса - /// - /// Получить список операций - /// - /// - /// - /// - Task> GetOperationsAsync( - WellOperationRequest request, - CancellationToken token); - - /// - /// Получить статистику операции по скважине с группировкой по категориям - /// - /// - /// - /// - Task> GetGroupOperationsStatAsync( - WellOperationRequest request, - CancellationToken token); - - /// - /// Получить операцию по id - /// - /// - /// - /// - Task GetOrDefaultAsync(int id, CancellationToken token); - - /// - /// Добавить несколько операций за один раз - /// - /// - /// - /// - Task InsertRangeAsync( - IEnumerable wellOperationDtos, CancellationToken token); - - /// - /// Обновить существующую операцию - /// - /// - /// - /// - Task UpdateAsync(WellOperationDto item, - CancellationToken token); - - /// - /// Удалить операции по id - /// - /// - /// - /// - Task DeleteAsync(IEnumerable ids, CancellationToken token); - /// /// Список секций /// @@ -86,6 +31,64 @@ namespace AsbCloudApp.Services /// /// DateTimeOffset? FirstOperationDate(int idWell); + + /// + /// Получить страницу списка операций + /// + /// + /// + /// + Task> GetAsync(WellOperationRequest request, CancellationToken token); + + /// + /// Получить страницу списка операций + /// + /// + /// + /// + Task> GetPageAsync(WellOperationRequest request, CancellationToken token); + + /// + /// Получить операцию по id + /// + /// + /// + /// + Task GetOrDefaultAsync(int id, CancellationToken token); + + /// + /// Получить статистику операции по скважине с группировкой по категориям + /// + /// + /// + /// + Task> GetGroupOperationsStatAsync( + WellOperationRequest request, + CancellationToken token); + + /// + /// Добавить несколько операций за один раз + /// + /// + /// + /// + Task InsertRangeAsync(IEnumerable wellOperationDtos, CancellationToken token); + + /// + /// Обновить существующую операцию + /// + /// + /// + /// + Task UpdateAsync(WellOperationDto dto, CancellationToken token); + + /// + /// Удалить операции по id + /// + /// + /// + /// + Task DeleteAsync(IEnumerable ids, CancellationToken token); } #nullable disable -} +} \ No newline at end of file diff --git a/AsbCloudApp/Services/IProcessMapReportService.cs b/AsbCloudApp/Services/IProcessMapReportService.cs new file mode 100644 index 00000000..a4bf783b --- /dev/null +++ b/AsbCloudApp/Services/IProcessMapReportService.cs @@ -0,0 +1,20 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudApp.Services +{ + /// + /// Сервис формирования РТК. + /// + public interface IProcessMapReportService + { + /// + /// Сформировать. + /// + /// + /// + /// + Task MakeReportAsync(int idWell, CancellationToken token = default); + } +} diff --git a/AsbCloudApp/Services/IProcessMapRepository.cs b/AsbCloudApp/Services/IProcessMapRepository.cs index a898fa4a..8c9ab6f0 100644 --- a/AsbCloudApp/Services/IProcessMapRepository.cs +++ b/AsbCloudApp/Services/IProcessMapRepository.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; using System; using System.Collections.Generic; using System.Threading; diff --git a/AsbCloudApp/Services/IProcessMapService.cs b/AsbCloudApp/Services/IProcessMapService.cs new file mode 100644 index 00000000..3d2eeff4 --- /dev/null +++ b/AsbCloudApp/Services/IProcessMapService.cs @@ -0,0 +1,24 @@ +using AsbCloudApp.Data.ProcessMap; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudApp.Services +{ +#nullable enable + /// + /// Сервис формирования РТК + /// + public interface IProcessMapService + { + /// + /// Получение моделей РТК + /// + /// + /// + /// + Task> GetProcessMapAsync(int idWell, CancellationToken token); + } +#nullable disable +} diff --git a/AsbCloudApp/Services/ITelemetryDataSaubService.cs b/AsbCloudApp/Services/ITelemetryDataSaubService.cs new file mode 100644 index 00000000..d6bdcb6f --- /dev/null +++ b/AsbCloudApp/Services/ITelemetryDataSaubService.cs @@ -0,0 +1,26 @@ +using AsbCloudApp.Data.SAUB; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable +namespace AsbCloudApp.Services +{ + /// + /// Телеметрия САУБ + /// + public interface ITelemetryDataSaubService : ITelemetryDataService + { + /// + /// усредненная статистика по 1м за весь период + /// + /// МЕДЛЕННЫЙ ЗАПРОС + /// + /// + /// + /// + /// + Task> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token); + } +} +#nullable disable \ No newline at end of file diff --git a/AsbCloudApp/Services/ITelemetryDataService.cs b/AsbCloudApp/Services/ITelemetryDataService.cs index 8efc74ae..585843ff 100644 --- a/AsbCloudApp/Services/ITelemetryDataService.cs +++ b/AsbCloudApp/Services/ITelemetryDataService.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; + #nullable enable namespace AsbCloudApp.Services { @@ -33,7 +34,7 @@ namespace AsbCloudApp.Services /// /// /// - Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token = default); + Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token); } } #nullable disable \ No newline at end of file diff --git a/AsbCloudDb/Model/WellOperation.cs b/AsbCloudDb/Model/WellOperation.cs index 8ef65c91..4abe21fb 100644 --- a/AsbCloudDb/Model/WellOperation.cs +++ b/AsbCloudDb/Model/WellOperation.cs @@ -10,6 +10,9 @@ namespace AsbCloudDb.Model [Table("t_well_operation"), Comment("Данные по операциям на скважине")] public class WellOperation : IId { + public const int IdOperationTypePlan = 0; + public const int IdOperationTypeFact = 1; + [Key] [Column("id")] public int Id { get; set; } @@ -23,6 +26,9 @@ namespace AsbCloudDb.Model [Column("id_category"), Comment("Id категории операции")] public int IdCategory { get; set; } + /// + /// Тип 0 = План или 1 = Факт + /// [Column("id_type"), Comment("0 = План или 1 = Факт")] public int IdType { get; set; } diff --git a/AsbCloudDb/Model/WellOperationCategory.cs b/AsbCloudDb/Model/WellOperationCategory.cs index 4cafa51e..3781a9e6 100644 --- a/AsbCloudDb/Model/WellOperationCategory.cs +++ b/AsbCloudDb/Model/WellOperationCategory.cs @@ -2,7 +2,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; -using System; namespace AsbCloudDb.Model { diff --git a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj index c9f3963d..1a8e2432 100644 --- a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj +++ b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj @@ -13,6 +13,7 @@ + @@ -30,6 +31,7 @@ + diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index b2625b8d..1b7b05d1 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -13,6 +13,7 @@ using AsbCloudInfrastructure.Services.DailyReport; using AsbCloudInfrastructure.Services.DetectOperations; using AsbCloudInfrastructure.Services.DrillingProgram; using AsbCloudInfrastructure.Services.PlannedTrajectory; +using AsbCloudInfrastructure.Services.ProcessMap; using AsbCloudInfrastructure.Services.SAUB; using AsbCloudInfrastructure.Services.Subsystems; using AsbCloudInfrastructure.Services.WellOperationService; @@ -124,9 +125,9 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -137,6 +138,8 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); // admin crud services: services.AddTransient, CrudCacheRepositoryBase>(s => @@ -181,7 +184,7 @@ namespace AsbCloudInfrastructure services.AddTransient, CrudCacheRepositoryBase>(); // TelemetryData services - services.AddTransient, TelemetryDataSaubService>(); + services.AddTransient(); services.AddTransient, TelemetryDataSpinService>(); // Wits diff --git a/AsbCloudInfrastructure/Repository/LimitingParameterRepository.cs b/AsbCloudInfrastructure/Repository/LimitingParameterRepository.cs index 88c5f869..9c05d743 100644 --- a/AsbCloudInfrastructure/Repository/LimitingParameterRepository.cs +++ b/AsbCloudInfrastructure/Repository/LimitingParameterRepository.cs @@ -3,6 +3,7 @@ using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudDb.Model; using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -19,41 +20,49 @@ namespace AsbCloudInfrastructure.Repository { this.context = context; } + public async Task> GetLimitingParametersAsync(LimitingParameterRequest request, WellDto wellDto, CancellationToken token) { - var query = BuildQuery(request, wellDto); + var timezoneOffset = wellDto.Timezone.Hours; + var IdTelemetry = wellDto.IdTelemetry!.Value; + return await GetLimitingParametersAsync(request, IdTelemetry, timezoneOffset, token); + } + + public async Task> GetLimitingParametersAsync(LimitingParameterRequest request, int idTelemetry, double timezoneHours, CancellationToken token) + { + var timezoneSpan = TimeSpan.FromHours(timezoneHours); + var query = BuildQuery(request, idTelemetry, timezoneHours); var data = (await query.ToListAsync(token)) .Select(x => new LimitingParameterDataDto { - IdWell = wellDto.Id, + IdWell = request.IdWell, IdTelemetry = x.IdTelemetry, IdFeedRegulator = x.IdFeedRegulator, - DateStart = x.DateStart, - DateEnd = x.DateEnd, + DateStart = DateTime.SpecifyKind(x.DateStart.UtcDateTime + timezoneSpan, DateTimeKind.Unspecified), + DateEnd = DateTime.SpecifyKind(x.DateEnd.UtcDateTime + timezoneSpan, DateTimeKind.Unspecified), DepthStart = x.DepthStart, DepthEnd = x.DepthEnd }); - return data; } - private IQueryable BuildQuery(LimitingParameterRequest request, WellDto wellDto) + private IQueryable BuildQuery(LimitingParameterRequest request, int idTelemetry, double timezoneHours) { var query = context.LimitingParameter .OrderBy(x => x.Id) - .Where(x => x.IdTelemetry == wellDto.IdTelemetry) + .Where(x => x.IdTelemetry == idTelemetry) .AsNoTracking(); if (request.GtDate.HasValue) { - var gtDate = request.GtDate.Value.ToUtcDateTimeOffset(wellDto.Timezone.Hours); + var gtDate = request.GtDate.Value.ToUtcDateTimeOffset(timezoneHours); query = query.Where(x => x.DateEnd >= gtDate); } if (request.LtDate.HasValue) { - var ltDate = request.LtDate.Value.ToUtcDateTimeOffset(wellDto.Timezone.Hours); + var ltDate = request.LtDate.Value.ToUtcDateTimeOffset(timezoneHours); query = query.Where(x => x.DateStart <= ltDate); } diff --git a/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs b/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs index eb2eadac..f24ce61d 100644 --- a/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs +++ b/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; diff --git a/AsbCloudInfrastructure/Repository/TelemetryWirelineRunOutRepository.cs b/AsbCloudInfrastructure/Repository/TelemetryWirelineRunOutRepository.cs index 134a1ac8..325bb2b4 100644 --- a/AsbCloudInfrastructure/Repository/TelemetryWirelineRunOutRepository.cs +++ b/AsbCloudInfrastructure/Repository/TelemetryWirelineRunOutRepository.cs @@ -2,9 +2,7 @@ using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; using AsbCloudApp.Services; -using AsbCloudDb; using AsbCloudDb.Model; -using AsbCloudInfrastructure.Services.SAUB; using Mapster; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs similarity index 71% rename from AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs rename to AsbCloudInfrastructure/Repository/WellOperationRepository.cs index 54e559ba..e47a9460 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -9,35 +9,31 @@ using Microsoft.Extensions.Caching.Memory; using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Threading.Tasks; +using System.Threading; +using AsbCloudApp.Repositories; -namespace AsbCloudInfrastructure.Services.WellOperationService +namespace AsbCloudInfrastructure.Repository { #nullable enable - public class WellOperationService : IWellOperationService + /// + /// репозиторий операций по скважине + /// + public class WellOperationRepository : IWellOperationRepository { private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; private readonly IWellService wellService; + private static Dictionary? firstOperationsCache = null; - private Dictionary? firstOperationsCache = null; - - public const int idOperationTypePlan = 0; - public const int idOperationTypeFact = 1; - - public WellOperationService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService) + public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService) { this.db = db; this.memoryCache = memoryCache; this.wellService = wellService; } - public IDictionary GetSectionTypes() - => memoryCache - .GetOrCreateBasic(db) - .ToDictionary(s => s.Id, s => s.Caption); - + /// public IEnumerable GetCategories() { var allCategories = memoryCache @@ -56,6 +52,13 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return result; } + /// + public IDictionary GetSectionTypes() + => memoryCache + .GetOrCreateBasic(db) + .ToDictionary(s => s.Id, s => s.Caption); + + /// public DateTimeOffset? FirstOperationDate(int idWell) { if (firstOperationsCache is null) @@ -65,8 +68,8 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .Select(g => new Tuple ( g.Key, - g.Where(o => o.IdType == idOperationTypePlan).Min(o => o.DateStart), - g.Where(o => o.IdType == idOperationTypeFact).Min(o => o.DateStart) + g.Where(o => o.IdType == WellOperation.IdOperationTypePlan).Min(o => o.DateStart), + g.Where(o => o.IdType == WellOperation.IdOperationTypeFact).Min(o => o.DateStart) )); firstOperationsCache = query @@ -76,13 +79,24 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return firstOperationsCache?.GetValueOrDefault(idWell); } - public async Task> GetOperationsAsync( + /// + public async Task> GetAsync( WellOperationRequest request, CancellationToken token) { - var timezone = wellService.GetTimezone(request.IdWell); + var query = BuildQuery(request) + .AsNoTracking(); + var result = await query.ToArrayAsync(token); + return result; + } - var query = BuildQuery(request); + /// + public async Task> GetPageAsync( + WellOperationRequest request, + CancellationToken token) + { + var query = BuildQuery(request) + .AsNoTracking(); var result = new PaginationContainer { @@ -91,44 +105,45 @@ namespace AsbCloudInfrastructure.Services.WellOperationService Count = await query.CountAsync(token).ConfigureAwait(false), }; - if (result.Skip > 0) - query = query.Skip(result.Skip!); - - var entities = await query.Take(result.Take).AsNoTracking() - .ToListAsync(token).ConfigureAwait(false); - - if (!entities.Any()) - return result; - - var nptHours = 0d; - - var dateStart = query.Min(o => o.DateStart); - foreach (var entity in entities) - { - var dto = entity.Adapt(); - dto.Day = (entity.DateStart - dateStart).TotalDays; - dto.WellSectionTypeName = entity.WellSectionType.Caption; - dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours); - dto.CategoryName = entity.OperationCategory.Name; - if (entity.IdType == idOperationTypeFact) - { - if (WellOperationCategory.NonProductiveTimeSubIds.Contains(entity.IdCategory)) - nptHours += entity.DurationHours; - dto.NptHours = nptHours; - } - result.Items.Add(dto); - } + query = query + .Skip(result.Skip) + .Take(result.Take); + result.Items = await query.ToListAsync(token); return result; } + /// + public async Task GetOrDefaultAsync(int id, + CancellationToken token) + { + var entity = await db.WellOperations + .Include(s => s.WellSectionType) + .Include(s => s.OperationCategory) + .FirstOrDefaultAsync(e => e.Id == id, token) + .ConfigureAwait(false); + + if (entity is null) + return null; + + var timezone = wellService.GetTimezone(entity.IdWell); + + var dto = entity.Adapt(); + dto.WellSectionTypeName = entity.WellSectionType.Caption; + dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours); + dto.CategoryName = entity.OperationCategory.Name; + return dto; + } + + /// public async Task> GetGroupOperationsStatAsync( WellOperationRequest request, CancellationToken token) { - var query = BuildQuery(request); + var query = BuildQuery(request); var entities = await query - .Select(o => new { + .Select(o => new + { o.IdCategory, DurationMinutes = o.DurationHours * 60, DurationDepth = o.DepthEnd - o.DepthStart @@ -163,7 +178,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .GroupBy(o => o.IdParent) .Select(g => new WellGroupOpertionDto { - IdCategory = g.Key.HasValue ? g.Key.Value : defaultId, + IdCategory = g.Key ?? defaultId, Category = g.Key.HasValue ? parentRelationDictionary[g.Key.Value].Name : "unknown", Count = g.Sum(o => o.Count), DeltaDepth = g.Sum(o => o.DeltaDepth), @@ -175,27 +190,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return dtos; } - public async Task GetOrDefaultAsync(int id, - CancellationToken token) - { - var entity = await db.WellOperations - .Include(s => s.WellSectionType) - .Include(s => s.OperationCategory) - .FirstOrDefaultAsync(e => e.Id == id, token) - .ConfigureAwait(false); - - if (entity is null) - return null; - - var timezone = wellService.GetTimezone(entity.IdWell); - - var dto = entity.Adapt(); - dto.WellSectionTypeName = entity.WellSectionType.Caption; - dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours); - dto.CategoryName = entity.OperationCategory.Name; - return dto; - } - + /// public async Task InsertRangeAsync( IEnumerable wellOperationDtos, CancellationToken token) @@ -221,6 +216,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .ConfigureAwait(false); } + /// public async Task UpdateAsync( WellOperationDto dto, CancellationToken token) { @@ -232,6 +228,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .ConfigureAwait(false); } + /// public async Task DeleteAsync(IEnumerable ids, CancellationToken token) { @@ -241,14 +238,53 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .ConfigureAwait(false); } - private IQueryable BuildQuery(WellOperationRequest request) + /// + /// В результате попрежнему требуется конвертировать дату + /// + /// + /// + private IQueryable BuildQuery(WellOperationRequest request) { var timezone = wellService.GetTimezone(request.IdWell); + var timeZoneOffset = TimeSpan.FromHours(timezone.Hours); var query = db.WellOperations .Include(s => s.WellSectionType) .Include(s => s.OperationCategory) - .Where(s => s.IdWell == request.IdWell); + .Where(o => o.IdWell == request.IdWell) + .Select(o => new WellOperationDto + { + Id = o.Id, + IdType = o.IdType, + IdWell = o.IdWell, + IdWellSectionType = o.IdWellSectionType, + IdCategory = o.IdCategory, + + CategoryName = o.WellSectionType.Caption, + WellSectionTypeName = o.WellSectionType.Caption, + + DateStart = DateTime.SpecifyKind( o.DateStart.UtcDateTime + timeZoneOffset, DateTimeKind.Unspecified), + DepthStart = o.DepthStart, + DepthEnd = o.DepthEnd, + DurationHours = o.DurationHours, + CategoryInfo = o.CategoryInfo, + Comment = o.Comment, + + NptHours = db.WellOperations + .Where(subOp => subOp.IdWell == request.IdWell) + .Where(subOp => subOp.IdType == 1) + .Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory)) + .Where(subOp => subOp.DateStart <= o.DateStart) + .Select(subOp => subOp.DurationHours) + .Sum(), + + Day = (o.DateStart - db.WellOperations + .Where(subOp => subOp.IdWell == request.IdWell) + .Where(subOp => subOp.IdType == o.IdType) + .Where(subOp => subOp.DateStart <= o.DateStart) + .Min(subOp => subOp.DateStart)) + .TotalHours, + }); if (request.OperationType.HasValue) query = query.Where(e => e.IdType == request.OperationType.Value); diff --git a/AsbCloudInfrastructure/Services/LimitingParameterService.cs b/AsbCloudInfrastructure/Services/LimitingParameterService.cs index 0a609507..848fbdf2 100644 --- a/AsbCloudInfrastructure/Services/LimitingParameterService.cs +++ b/AsbCloudInfrastructure/Services/LimitingParameterService.cs @@ -40,7 +40,6 @@ namespace AsbCloudInfrastructure.Services var data = (await limitingParameterRepository.GetLimitingParametersAsync(request, well, token)) .GroupBy(x => x.IdFeedRegulator); - List result = new List(data.Count()); foreach (var item in data) { @@ -107,7 +106,7 @@ namespace AsbCloudInfrastructure.Services return (float)result; } - private DateTimeOffset GetDate(double depth, LimitingParameterDataDto dto) + private DateTime GetDate(double depth, LimitingParameterDataDto dto) { var a = depth - dto.DepthStart; var b = dto.DepthEnd - dto.DepthStart; diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs new file mode 100644 index 00000000..da7f3f79 --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs @@ -0,0 +1,203 @@ +using AsbCloudApp.Data.ProcessMap; +using AsbCloudApp.Services; +using ClosedXML.Excel; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Services.ProcessMap +{ +#nullable enable + public class ProcessMapReportService : IProcessMapReportService + { + const int firstColumn = 2; + const int lastColumn = 27; + + const int headerRowsCount = 3; + + private readonly IProcessMapService processMapService; + + public ProcessMapReportService(IProcessMapService processMapService) + { + this.processMapService = processMapService; + } + + public async Task MakeReportAsync(int idWell, CancellationToken token) + { + var stream = GetExcelTemplateStream(); + using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); + + var data = await processMapService.GetProcessMapAsync(idWell, token); + + FillProcessMapToWorkbook(workbook, data); + + MemoryStream memoryStream = new MemoryStream(); + workbook.SaveAs(memoryStream, new SaveOptions { }); + memoryStream.Seek(0, SeekOrigin.Begin); + return memoryStream; + } + + private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable data) + { + var sheet = workbook.Worksheets.FirstOrDefault(); + if (sheet is null) + return; + var dataBySections = data.GroupBy(p => p.IdWellSectionType); + FillSheet(sheet, dataBySections); + } + + private static void FillSheet(IXLWorksheet sheet, IEnumerable> dataBySections) + { + var startRow = headerRowsCount + 1; + foreach (var sectionData in dataBySections) + { + if(sectionData.Any()) + startRow = FillSection(sheet, sectionData, startRow); + } + } + + private static int FillSection(IXLWorksheet sheet, IGrouping sectionData, int row) + { + var rowStart = row; + + var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName + ?? sectionData.Key.ToString(); + + sheet.Range(row, firstColumn, row, lastColumn) + .Merge() + .FirstCell() + .SetVal(sectionName); + + row++; + + foreach (var interval in sectionData) + row = FillIntervalData(sheet, interval, row); + + var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style; + SetBorders(sectionStyle); + return row; + } + + private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row) + { + const int columnDepth = firstColumn; + const int columnDate = firstColumn + 1; + const int columnRopTime = firstColumn + 2; + const int columnMode = firstColumn + 3; + + int rowRotor = row; + int rowSlide = row + 1; + + sheet.Range(rowRotor, columnDepth, rowSlide, columnDepth) + .Merge().FirstCell() + .SetVal(interval.DepthStart, "0.0"); + + sheet.Range(rowRotor, columnDate, rowSlide, columnDate) + .Merge().FirstCell() + .SetVal(interval.DateStart); + + sheet.Range(rowRotor, columnRopTime, rowSlide, columnRopTime) + .Merge().FirstCell() + .SetVal(interval.MechDrillingHours); + + row = FillIntervalModeData(sheet, "Ротор", interval.Rotor, columnMode, row); + row = FillIntervalModeData(sheet, "Слайд", interval.Rotor, columnMode, row); + + return row; + } + + private static int FillIntervalModeData(IXLWorksheet sheet, string modeName, ProcessMapReportRowDto modeData, int column, int row) + { + int columnDeltaDepth = column + 1; + int columnPressure = columnDeltaDepth + 1; + int columnLoad = columnPressure + 5; + int columnTorque = columnLoad + 5; + int columnSpeed = columnTorque + 5; + int columnUsage = columnSpeed + 4; + int columnRop = columnUsage + 1; + + sheet.Cell(row, column) + .SetVal(modeName); + + sheet.Cell(row, columnDeltaDepth) + .SetVal(modeData.DeltaDepth); + + FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row); + FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row); + FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row); + FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row); + + sheet.Cell(row, columnUsage) + .SetVal(modeData.Usage); + + sheet.Cell(row, columnRop) + .SetVal(modeData.Rop); + + return row + 1; + } + + private static void FillIntervalModeDataParam(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetLimit = 3; + const int columnOffsetPercent = 4; + + sheet.Cell(row, column + columnOffsetSpPlan) + .SetVal(dataParam.SetpointPlan); + + sheet.Cell(row, column + columnOffsetSpFact) + .SetVal(dataParam.SetpointFact); + + sheet.Cell(row, column + columnOffsetFact) + .SetVal(dataParam.Fact); + + sheet.Cell(row, column + columnOffsetLimit) + .SetVal(dataParam.Limit); + + sheet.Cell(row, column + columnOffsetPercent) + .SetVal(dataParam.PercDrillingSetpoint); + } + + private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetPercent = 3; + + sheet.Cell(row, column + columnOffsetSpPlan) + .SetVal(dataParam.SetpointPlan); + + sheet.Cell(row, column + columnOffsetSpFact) + .SetVal(dataParam.SetpointFact); + + sheet.Cell(row, column + columnOffsetFact) + .SetVal(dataParam.Fact); + + sheet.Cell(row, column + columnOffsetPercent) + .SetVal(dataParam.PercDrillingSetpoint); + } + + private static Stream GetExcelTemplateStream() + { + var stream = System.Reflection.Assembly.GetExecutingAssembly() + .GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx"); + return stream!; + } + + private static IXLStyle SetBorders(IXLStyle style) + { + style.Border.RightBorder = XLBorderStyleValues.Thin ; + style.Border.LeftBorder = XLBorderStyleValues.Thin; + style.Border.TopBorder = XLBorderStyleValues.Thin ; + style.Border.BottomBorder = XLBorderStyleValues.Thin ; + style.Border.InsideBorder = XLBorderStyleValues.Thin ; + return style; + } + } +#nullable disable +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportTemplate.xlsx b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportTemplate.xlsx new file mode 100644 index 00000000..64b328cd Binary files /dev/null and b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportTemplate.xlsx differ diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs new file mode 100644 index 00000000..0884896d --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs @@ -0,0 +1,346 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; +using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudApp.Services.Subsystems; +using AsbCloudDb.Model; +using AsbCloudApp.Data.Subsystems; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudInfrastructure.Services.Subsystems; + +namespace AsbCloudInfrastructure.Services.ProcessMap +{ +#nullable enable + public partial class ProcessMapService : IProcessMapService + { + private readonly IWellService wellService; + private readonly IWellOperationRepository wellOperationRepository; + private readonly IProcessMapRepository processMapRepository; + private readonly ITelemetryDataSaubService telemetryDataSaubService; + private readonly ILimitingParameterRepository limitingParameterRepository; + private readonly ISubsystemOperationTimeService subsystemOperationTimeService; + + public ProcessMapService( + IWellService wellService, + IWellOperationRepository wellOperationService, + IProcessMapRepository processMapRepository, + ITelemetryDataSaubService telemetryDataSaubService, + ILimitingParameterRepository limitingParameterRepository, + ISubsystemOperationTimeService subsystemOperationTimeService) + { + this.wellService = wellService; + this.wellOperationRepository = wellOperationService; + this.processMapRepository = processMapRepository; + this.telemetryDataSaubService = telemetryDataSaubService; + this.limitingParameterRepository = limitingParameterRepository; + this.subsystemOperationTimeService = subsystemOperationTimeService; + } + + public async Task> GetProcessMapAsync(int idWell, CancellationToken token) + { + var well = wellService.GetOrDefault(idWell) + ?? throw new ArgumentInvalidException("idWell not found", nameof(idWell)); + var idTelemetry = well.IdTelemetry + ?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell)); + + var processMap = (await processMapRepository.GetByIdWellAsync(idWell, token))!; + var factDrillingOperations = await GetFactDrillingOperationsAsync(idWell, token); + var telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token); + var limitingParameters = await limitingParameterRepository.GetLimitingParametersAsync(new(), well, token); + var subsystemsOperationTime = await GetOperationTimeAsync(idWell, token); + + var result = factDrillingOperations + .GroupBy(o => o.IdWellSectionType) + .SelectMany(sectionOperations => + { + var sectionProcessMap = processMap.Where(p => p.IdWellSectionType == sectionOperations.Key); + return HandleSection(sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime!); + }) + .ToList(); + + return result; + } + + private Task?> GetOperationTimeAsync(int idWell, CancellationToken token) + { + var request = new SubsystemOperationTimeRequest + { + IdWell = idWell, + IdsSubsystems = new int[] { SubsystemOperationTimeService.IdSubsystemAKB, SubsystemOperationTimeService.IdSubsystemSpin }, + }; + return subsystemOperationTimeService.GetOperationTimeAsync(request, token); + } + + private async Task> GetFactDrillingOperationsAsync(int idWell, CancellationToken token) + { + var operationsRequest = new WellOperationRequest + { + IdWell = idWell, + OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds, + OperationType = WellOperation.IdOperationTypeFact, + SortFields = new[] { nameof(WellOperation.DateStart) } + }; + + var allFactDrillingOperations = await wellOperationRepository.GetAsync(operationsRequest, token); + var factDrillingOperations = allFactDrillingOperations.Where(o => o.DepthEnd > o.DepthStart); + return factDrillingOperations; + } + + private static IEnumerable HandleSection( + IEnumerable sectionOperations, + IEnumerable sectionProcessMap, + IEnumerable telemetryDataStat, + IEnumerable limitingParameters, + IEnumerable subsystemsOperationTime) + { + var minDepth = sectionOperations.Min(o => o.DepthStart); + var maxDepth = sectionOperations.Max(o => o.DepthEnd); + + var depthIntervals = SplitByIntervals(minDepth, maxDepth).ToArray(); + var result = new ProcessMapReportDto[depthIntervals.Length]; + + for (var i = 0; i < depthIntervals.Length; i++ ) + result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime); + + return result; + } + + private static ProcessMapReportDto MakeProcessMapReportDto( + (double min, double max) depthInterval, + IEnumerable sectionOperations, + IEnumerable sectionProcessMap, + IEnumerable telemetryDataStat, + IEnumerable limitingParameters, + IEnumerable subsystemsOperationTime) + { + var dto = new ProcessMapReportDto{ + DepthStart = depthInterval.min + }; + + // TODO: trim items by detpth intervals. Use linear interpolation. + var intervalOperations = sectionOperations.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max); + var intervalProcessMap = sectionProcessMap.Where(map => map.DepthEnd >= depthInterval.min && map.DepthStart <= depthInterval.max); + var intervalTelemetryDataStat = CalcIntervalTelemetryDataStat(depthInterval, telemetryDataStat); + var intervalLimitingParametrs = limitingParameters.Where(l => l.DepthEnd >= depthInterval.min && l.DepthStart <= depthInterval.max); + var intervalSubsystemsOperationTime = subsystemsOperationTime.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max); + + var firstIntervalOperation = intervalOperations.FirstOrDefault(); + if (firstIntervalOperation is not null) + { + dto.DateStart = GetInterpolatedDate(firstIntervalOperation, depthInterval.min); + dto.IdWell = firstIntervalOperation.IdWell; + dto.IdWellSectionType = firstIntervalOperation.IdWellSectionType; + dto.WellSectionTypeName = firstIntervalOperation.WellSectionTypeName; + dto.MechDrillingHours = CalcHours(depthInterval, intervalOperations); + } + + // TODO: Разделить интервальные коллекции на ротор и слайд. Пока нет готовой методики. + var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide); + var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor); + + dto.Slide = CalcDrillModeStat(depthInterval, slideOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime); + dto.Rotor = CalcDrillModeStat(depthInterval, rotorOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime); + + return dto; + } + + private static TelemetryDataSaubStatDto? CalcIntervalTelemetryDataStat((double min, double max) depthInterval, IEnumerable telemetryDataStat) + { + TelemetryDataSaubStatDto[] data = telemetryDataStat + .Where(d => d.WellDepthMin <= depthInterval.max && d.WellDepthMax >= depthInterval.min) + .ToArray(); + + if (!data.Any()) + return null; + + if (data.Length == 1) + return data.First(); + + var result = new TelemetryDataSaubStatDto + { + WellDepthMin = data.Min(d => d.WellDepthMin), + WellDepthMax = data.Max(d => d.WellDepthMax), + DateMin = data.Min(d => d.DateMin), + DateMax = data.Max(d => d.DateMax), + }; + + var intervalDeltaDepth = result.WellDepthMax - result.WellDepthMin; + + foreach (var item in data) + { + var itemWeight = (item.WellDepthMax - item.WellDepthMin) / intervalDeltaDepth; + + result.Pressure += item.Pressure * itemWeight; + result.PressureSp += item.PressureSp * itemWeight; + result.PressureSpRotor += item.PressureSpSlide * itemWeight; + result.PressureIdle += item.PressureIdle * itemWeight; + + result.AxialLoad += item.AxialLoad * itemWeight; + result.AxialLoadSp += item.AxialLoadSp * itemWeight; + result.AxialLoadLimitMax += item.AxialLoadLimitMax * itemWeight; + + result.RotorTorque += item.RotorTorque * itemWeight; + result.RotorTorqueSp += item.RotorTorqueSp * itemWeight; + result.RotorTorqueLimitMax += item.RotorTorqueLimitMax * itemWeight; + + result.BlockSpeed += item.BlockSpeed * itemWeight; + result.BlockSpeedSp += item.BlockSpeedSp * itemWeight; + result.BlockSpeedSpRotor += item.BlockSpeedSpRotor * itemWeight; + result.BlockSpeedSpSlide += item.BlockSpeedSpSlide * itemWeight; + } + + return result; + } + + private static ProcessMapReportRowDto CalcDrillModeStat( + (double min, double max) depthInterval, + IEnumerable intervalModeOperations, + IEnumerable intervalProcessMap, + TelemetryDataSaubStatDto? telemetryDataStat, + IEnumerable intervalLimitingParametrs, + IEnumerable intervalSubsystemsOperationTime) + { + var dto = new ProcessMapReportRowDto(); + if (intervalModeOperations.Any()) + { + var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations); + dto.DeltaDepth = deltaDepth; + dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations); + }; + + if (intervalProcessMap.Any()) + { + var processMapFirst = intervalProcessMap.First(); + dto.PressureDiff.SetpointPlan = processMapFirst.Pressure.Plan; + dto.AxialLoad.SetpointPlan = processMapFirst.AxialLoad.Plan; + dto.TopDriveTorque.SetpointPlan = processMapFirst.TopDriveTorque.Plan; + //dto.SpeedLimit.SetpointPlan = null; + } + + if (telemetryDataStat is not null) + { + dto.PressureDiff.SetpointFact = telemetryDataStat.PressureSp; + dto.PressureDiff.Fact = telemetryDataStat.Pressure; + dto.PressureDiff.Limit = telemetryDataStat.PressureDeltaLimitMax; + + dto.AxialLoad.SetpointFact = telemetryDataStat.AxialLoadSp; + dto.AxialLoad.Fact = telemetryDataStat.AxialLoad; + dto.AxialLoad.Limit = telemetryDataStat.AxialLoadLimitMax; + + dto.TopDriveTorque.SetpointFact = telemetryDataStat.RotorTorqueSp; + dto.TopDriveTorque.Fact = telemetryDataStat.RotorTorque; + dto.TopDriveTorque.Limit = telemetryDataStat.RotorTorqueLimitMax; + + dto.SpeedLimit.SetpointFact = telemetryDataStat.BlockSpeedSp; + dto.SpeedLimit.Fact = telemetryDataStat.BlockSpeed; + //dto.SpeedLimit.Limit = mull; + } + + if(intervalLimitingParametrs.Any()) + { + const int idLimParamRop = 1; + const int idLimParamPressure = 2; + const int idLimParamAxialLoad = 3; + const int idLimParamTorque = 4; + + var intervalLimitingParametrsStat = intervalLimitingParametrs + .GroupBy(p => p.IdFeedRegulator) + .Select(g => new + { + IdLimParam = g.Key, + SumDepth = g.Sum(p => p.DepthEnd - p.DepthStart), + }); + + var totalDepth = intervalLimitingParametrsStat + .Sum(s => s.SumDepth); + + if (totalDepth > 0) + { + dto.AxialLoad.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamAxialLoad)?.SumDepth / totalDepth; + + dto.PressureDiff.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamPressure)?.SumDepth / totalDepth; + + dto.TopDriveTorque.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamTorque)?.SumDepth / totalDepth; + + dto.SpeedLimit.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamRop)?.SumDepth / totalDepth; + } + } + + if (intervalSubsystemsOperationTime.Any() && dto.DeltaDepth > 0) + { + dto.Usage = intervalSubsystemsOperationTime.Sum(t => t.DepthEnd - t.DepthStart) / dto.DeltaDepth.Value; + } + + return dto; + } + + private static double CalcDeltaDepth((double min, double max) depthInterval, IEnumerable intervalOperations) + { + var ddepth = 0d; + foreach (var operation in intervalOperations) + { + var depthStart = operation.DepthStart > depthInterval.min + ? operation.DepthStart + : depthInterval.min; + + var depthEnd = operation.DepthEnd < depthInterval.max + ? operation.DepthEnd + : depthInterval.max; + + ddepth += (depthEnd - depthEnd); + } + return ddepth; + } + + private static double CalcHours((double min, double max) depthInterval, IEnumerable intervalOperations) + { + var hours = 0d; + foreach (var operation in intervalOperations) + { + var dateStart = operation.DepthStart > depthInterval.min + ? operation.DateStart + : GetInterpolatedDate(operation, depthInterval.min); + + var dateEnd = operation.DepthEnd < depthInterval.max + ? operation.DateStart + TimeSpan.FromHours(operation.DurationHours) + : GetInterpolatedDate(operation, depthInterval.max); + + hours += (dateEnd - dateStart).TotalHours; + } + return hours; + } + + private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth) + { + var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart); + var deltaHours = operation.DurationHours * ratio; + var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours); + return interpolatedDate; + } + + private static IEnumerable<(double min, double max)> SplitByIntervals(double min, double max) + { + const double step = 100; + var iMin = min; + var iMax = (1 + (int)(min / step)) * step; + for (; iMax < max; iMax += step) + { + yield return (iMin, iMax); + iMin = iMax; + } + yield return (iMin, max); + } + } +#nullable disable +} diff --git a/AsbCloudInfrastructure/Services/ProcessMap/XLExtentions.cs b/AsbCloudInfrastructure/Services/ProcessMap/XLExtentions.cs new file mode 100644 index 00000000..7117e1cf --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMap/XLExtentions.cs @@ -0,0 +1,63 @@ +using ClosedXML.Excel; +using System; + +namespace AsbCloudInfrastructure.Services.ProcessMap; + +internal static class XLExtentions +{ + public static IXLCell SetVal(this IXLCell cell, object value) + { + switch (value) + { + case DateTime dateTime: + cell.SetVal(dateTime); + break; + case IFormattable formattable: + cell.SetVal(formattable); + break; + case string valueString: + cell.SetVal(valueString); + break; + default: + cell.Value = value; + break; + } + + return cell; + } + + public static IXLCell SetVal(this IXLCell cell, string value, bool adaptRowHeight = false) + { + cell.Value = value; + if (adaptRowHeight) + { + var colWidth = cell.WorksheetColumn().Width; + var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize); + if (value.Length > maxCharsToWrap) + { + var row = cell.WorksheetRow(); + var baseHeight = row.Height; + row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap); + } + } + + return cell; + } + + public static IXLCell SetVal(this IXLCell cell, DateTime value, string dateFormat = "DD.MM.YYYY HH:MM:SS") + { + cell.Value = value; + cell.DataType = XLDataType.DateTime; + cell.Style.DateFormat.Format = dateFormat; + + return cell; + } + + public static IXLCell SetVal(this IXLCell cell, IFormattable value, string format = "0.00") + { + cell.Value = value; + cell.DataType = XLDataType.Number; + cell.Style.NumberFormat.Format = format; + return cell; + } +} diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 941bc012..d8f7736c 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -17,8 +17,8 @@ namespace AsbCloudInfrastructure.Services.SAUB where TEntity : class, ITelemetryData { protected readonly IAsbCloudDbContext db; - private readonly ITelemetryService telemetryService; - private readonly TelemetryDataCache telemetryDataCache; + protected readonly ITelemetryService telemetryService; + protected readonly TelemetryDataCache telemetryDataCache; public TelemetryDataBaseService( IAsbCloudDbContext db, diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index 9d666c1c..8ec8cb10 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -2,12 +2,17 @@ using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.SAUB { #nullable enable - public class TelemetryDataSaubService : TelemetryDataBaseService + public class TelemetryDataSaubService : TelemetryDataBaseService, ITelemetryDataSaubService { private readonly ITelemetryUserService telemetryUserService; @@ -21,6 +26,54 @@ namespace AsbCloudInfrastructure.Services.SAUB this.telemetryUserService = telemetryUserService; } + public async Task> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token) + { + var timezone = telemetryService.GetTimezone(idTelemetry); + var timezoneOffset = TimeSpan.FromHours(timezone.Hours); + + var query = db.Set() + .Where(t => t.IdTelemetry == idTelemetry) + .Where(t => t.BlockPosition > 0.0001) + .Where(t => t.WellDepth > 0.0001) + .Where(t => t.WellDepth - t.BitDepth < 0.01) + .GroupBy(t => new { H = t.DateTime.Hour, W = Math.Truncate(t.WellDepth!.Value) }) + .Select(g => new TelemetryDataSaubStatDto + { + Count = g.Count(), + + DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), + DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), + + WellDepthMin = g.Min(t => t.WellDepth!.Value), + WellDepthMax = g.Max(t => t.WellDepth!.Value), + + Pressure = g.Average(t => t.Pressure!.Value), + PressureSp = g.Average(t => t.PressureSp!.Value), + PressureSpRotor = g.Average(t => t.PressureSpRotor!.Value), + PressureSpSlide = g.Average(t => t.PressureSpSlide!.Value), + PressureIdle = g.Average(t => t.PressureIdle!.Value), + PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value), + + AxialLoad = g.Average(t => t.AxialLoad!.Value), + AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value), + AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value), + + RotorTorque = g.Average(t => t.RotorTorque!.Value), + RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value), + RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value), + + BlockSpeed = g.Average(t => t.BlockSpeed!.Value), + BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value), + BlockSpeedSpRotor = g.Average(t => t.BlockSpeedSpRotor!.Value), + BlockSpeedSpSlide = g.Average(t => t.BlockSpeedSpSlide!.Value), + }) + .Where(s => s.WellDepthMin != s.WellDepthMax) + .Where(s => s.Count > 3) + .OrderBy(t => t.DateMin); + + return await query.ToArrayAsync(token); + } + public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset) { var entity = src.Adapt(); diff --git a/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs b/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs index 818eef38..4ffaa620 100644 --- a/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs +++ b/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs @@ -204,7 +204,7 @@ namespace AsbCloudInfrastructure.Services })); if(!docs.Any()) - throw new Exception("Нет такой категории, или в нее уже загружен документ"); + throw new ArgumentInvalidException("Нет такой категории, или в нее уже загружен документ", nameof(idCategory)); var message = requester.MakeDisplayName() + " ожидает от Вас загрузку на портал документа «{{0}}»"; await GenerateMessageAsync(docs, message, token); diff --git a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs index 116b23de..b9daba10 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs @@ -134,7 +134,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService var wellType = (await memoryCache .GetOrCreateBasicAsync(db, token)) .FirstOrDefault(t => t.Id == well.IdWellType); - var statWellDto = new StatWellDto() + var statWellDto = new StatWellDto { Id = well.Id, Caption = well.Caption, @@ -142,10 +142,9 @@ namespace AsbCloudInfrastructure.Services.WellOperationService IdState = well.IdState, State = wellService.GetStateText(well.IdState), LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id).DateTime, + Companies = await wellService.GetCompaniesAsync(well.Id, token) }; - statWellDto.Companies = await wellService.GetCompaniesAsync(well.Id, token); - if (well.WellOperations is null) return statWellDto; @@ -175,8 +174,8 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .ToDictionary(s => s.Id); var sections = new List(sectionTypes.Count); - var operationsPlan = operations.Where(o => o.IdType == WellOperationService.idOperationTypePlan); - var operationsFact = operations.Where(o => o.IdType == WellOperationService.idOperationTypeFact); + var operationsPlan = operations.Where(o => o.IdType == WellOperation.IdOperationTypePlan); + var operationsFact = operations.Where(o => o.IdType == WellOperation.IdOperationTypeFact); foreach ((var id, var sectionType) in sectionTypes) { @@ -195,8 +194,8 @@ namespace AsbCloudInfrastructure.Services.WellOperationService private static PlanFactBase GetStatTotal(IEnumerable operations, int idWellState, double timezoneOffsetH) { - var operationsPlan = operations.Where(o => o.IdType == WellOperationService.idOperationTypePlan); - var operationsFact = operations.Where(o => o.IdType == WellOperationService.idOperationTypeFact); + var operationsPlan = operations.Where(o => o.IdType == WellOperation.IdOperationTypePlan); + var operationsFact = operations.Where(o => o.IdType == WellOperation.IdOperationTypeFact); var factEnd = CalcStat(operationsFact, timezoneOffsetH); if (factEnd is not null && idWellState != 2) factEnd.End = null; @@ -369,12 +368,12 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .ConfigureAwait(false); var wellOperationsPlan = wellOperations - .Where(o => o.IdType == WellOperationService.idOperationTypePlan) + .Where(o => o.IdType == WellOperation.IdOperationTypePlan) .OrderBy(o => o.DateStart) .ThenBy(o => o.DepthEnd); var wellOperationsFact = wellOperations - .Where(o => o.IdType == WellOperationService.idOperationTypeFact) + .Where(o => o.IdType == WellOperation.IdOperationTypeFact) .OrderBy(o => o.DateStart) .ThenBy(o => o.DepthEnd); diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs index 81771165..e9ed3d11 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs @@ -65,6 +65,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService } } + // TODO: use WellOperationRepository instead of DB public WellOperationImportService(IAsbCloudDbContext db, IWellService wellService) { this.db = db; diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationRepository.cs b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationRepository.cs deleted file mode 100644 index 6251bae9..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationRepository.cs +++ /dev/null @@ -1,242 +0,0 @@ -using AsbCloudApp.Data; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using AsbCloudDb; -using AsbCloudDb.Model; -using Mapster; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Caching.Memory; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Threading; -using System.Collections; - -namespace AsbCloudInfrastructure.Services.WellOperationService -{ -#nullable enable - - - /* - var opsQuery = db.WellOperations - .Where( o => o.IdWell == idWell ) - .Where( o => o.IdType == idType ) - .Select( o => new { - o.Id, - o.IdType, - o.IdWell, - o.IdWellSectionType, - o.IdCategory, - - o.Well, - o.WellSectionType, - o.OperationCategory, - - o.DateStart, - o.DepthStart, - o.DepthEnd, - o.DurationHours, - o.CategoryInfo, - o.Comment, - - nptHours = db.WellOperations - .Where(subOp => subOp.IdWell == idWell) - .Where(subOp => subOp.IdType == idType) - .Where(subOp => nptCats.Contains( subOp.IdCategory )) - .Where(subOp => subOp.DateStart <= o.DateStart) - .Select(subOp => subOp.DurationHours) - .Sum(), - Day = o.DateStart - db.WellOperations - .Where(subOp => subOp.IdWell == idWell) - .Where(subOp => subOp.IdType == idType) - .Where(subOp => subOp.DateStart <= o.DateStart) - .Min(subOp => subOp.DateStart), - }) - .OrderBy(o => o.DateStart); - */ - public class WellOperationRepository - { - private readonly IAsbCloudDbContext db; - private readonly IMemoryCache memoryCache; - private readonly IWellService wellService; - private static Dictionary? firstOperationsCache = null; - - public const int idOperationTypePlan = 0; - public const int idOperationTypeFact = 1; - - public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService) - { - this.db = db; - this.memoryCache = memoryCache; - this.wellService = wellService; - } - - public IDictionary GetSectionTypes() - => memoryCache - .GetOrCreateBasic(db) - .ToDictionary(s => s.Id, s => s.Caption); - - public IEnumerable GetCategories() - { - var allCategories = memoryCache - .GetOrCreateBasic(db); - - var parentIds = allCategories - .Select(o => o.IdParent) - .Distinct(); - - var operationCategories = allCategories - .Where(o => !parentIds.Contains(o.Id)) - .OrderBy(o => o.IdParent) - .ThenBy(o => o.Name); - - var result = operationCategories.Adapt>(); - return result; - } - - public DateTimeOffset? FirstOperationDate(int idWell) - { - if (firstOperationsCache is null) - { - var query = db.WellOperations - .GroupBy(o => o.IdWell) - .Select(g => new Tuple - ( - g.Key, - g.Where(o => o.IdType == idOperationTypePlan).Min(o => o.DateStart), - g.Where(o => o.IdType == idOperationTypeFact).Min(o => o.DateStart) - )); - - firstOperationsCache = query - .ToDictionary(f => f.Item1, f => f.Item3 ?? f.Item2); - } - - return firstOperationsCache?.GetValueOrDefault(idWell); - } - - public async Task GetOrDefaultAsync(int id, - CancellationToken token) - { - var entity = await db.WellOperations - .Include(s => s.WellSectionType) - .Include(s => s.OperationCategory) - .FirstOrDefaultAsync(e => e.Id == id, token) - .ConfigureAwait(false); - - if (entity is null) - return null; - - var timezone = wellService.GetTimezone(entity.IdWell); - - var dto = entity.Adapt(); - dto.WellSectionTypeName = entity.WellSectionType.Caption; - dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours); - dto.CategoryName = entity.OperationCategory.Name; - return dto; - } - - public Task> GetAsync(WellOperationRequest request, - CancellationToken token) - { - return Task.FromResult(Enumerable.Empty()); - } - - public async Task InsertRangeAsync( - IEnumerable wellOperationDtos, - CancellationToken token) - { - var firstOperation = wellOperationDtos - .FirstOrDefault(); - if (firstOperation is null) - return 0; - - var idWell = firstOperation.IdWell; - - var timezone = wellService.GetTimezone(idWell); - foreach (var dto in wellOperationDtos) - { - var entity = dto.Adapt(); - entity.Id = default; - entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours); - entity.IdWell = idWell; - db.WellOperations.Add(entity); - } - - return await db.SaveChangesAsync(token) - .ConfigureAwait(false); - } - - public async Task UpdateAsync( - WellOperationDto dto, CancellationToken token) - { - var timezone = wellService.GetTimezone(dto.IdWell); - var entity = dto.Adapt(); - entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours); - db.WellOperations.Update(entity); - return await db.SaveChangesAsync(token) - .ConfigureAwait(false); - } - - public async Task DeleteAsync(IEnumerable ids, - CancellationToken token) - { - var query = db.WellOperations.Where(e => ids.Contains(e.Id)); - db.WellOperations.RemoveRange(query); - return await db.SaveChangesAsync(token) - .ConfigureAwait(false); - } - - private IQueryable BuildQuery(WellOperationRequest request) - { - var timezone = wellService.GetTimezone(request.IdWell); - - var query = db.WellOperations - .Include(s => s.WellSectionType) - .Include(s => s.OperationCategory) - .Where(s => s.IdWell == request.IdWell); - - if (request.OperationType.HasValue) - query = query.Where(e => e.IdType == request.OperationType.Value); - - if (request.SectionTypeIds?.Any() == true) - query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType)); - - if (request.OperationCategoryIds?.Any() == true) - query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory)); - - if (request.GeDepth.HasValue) - query = query.Where(e => e.DepthEnd >= request.GeDepth.Value); - - if (request.LeDepth.HasValue) - query = query.Where(e => e.DepthEnd <= request.LeDepth.Value); - - if (request.GeDate.HasValue) - { - var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timezone.Hours); - query = query.Where(e => e.DateStart >= geDateOffset); - } - - if (request.LeDate.HasValue) - { - var leDateOffset = request.LeDate.Value.ToUtcDateTimeOffset(timezone.Hours); - query = query.Where(e => e.DateStart <= leDateOffset); - } - - if (request.SortFields?.Any() == true) - { - query = query.SortBy(request.SortFields); - } - else - { - query = query - .OrderBy(e => e.DateStart) - .ThenBy(e => e.DepthEnd) - .ThenBy(e => e.Id); - } - - return query; - } - } -#nullable disable -} diff --git a/AsbCloudInfrastructure/Services/WellService.cs b/AsbCloudInfrastructure/Services/WellService.cs index 3d73dbe4..967c44ca 100644 --- a/AsbCloudInfrastructure/Services/WellService.cs +++ b/AsbCloudInfrastructure/Services/WellService.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.EfCache; @@ -23,7 +24,7 @@ namespace AsbCloudInfrastructure.Services private readonly ITelemetryService telemetryService; private readonly ICrudRepository companyTypesService; private readonly ITimezoneService timezoneService; - private readonly IWellOperationService wellOperationService; + private readonly IWellOperationRepository wellOperationRepository; public ITelemetryService TelemetryService => telemetryService; @@ -42,7 +43,7 @@ namespace AsbCloudInfrastructure.Services this.telemetryService = telemetryService; this.timezoneService = timezoneService; - this.wellOperationService = new WellOperationService.WellOperationService(db, memoryCache, this); + this.wellOperationRepository = new WellOperationRepository(db, memoryCache, this); companyTypesService = new CrudCacheRepositoryBase(dbContext, memoryCache); } @@ -216,7 +217,7 @@ namespace AsbCloudInfrastructure.Services if (entity.Timezone is null) dto.Timezone = GetTimezone(entity.Id); - dto.StartDate = wellOperationService.FirstOperationDate(entity.Id)?.ToRemoteDateTime(dto.Timezone.Hours); + dto.StartDate = wellOperationRepository.FirstOperationDate(entity.Id)?.ToRemoteDateTime(dto.Timezone.Hours); dto.WellType = entity.WellType?.Caption; dto.Cluster = entity.Cluster?.Caption; dto.Deposit = entity.Cluster?.Deposit?.Caption; diff --git a/AsbCloudInfrastructure/Validators/ProcessMapValidator.cs b/AsbCloudInfrastructure/Validators/ProcessMapValidator.cs index 22de04ad..661d01be 100644 --- a/AsbCloudInfrastructure/Validators/ProcessMapValidator.cs +++ b/AsbCloudInfrastructure/Validators/ProcessMapValidator.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; using FluentValidation; namespace AsbCloudInfrastructure.Validators diff --git a/AsbCloudWebApi/Controllers/ProcessMapController.cs b/AsbCloudWebApi/Controllers/ProcessMapController.cs index 6d4681ed..f5c955aa 100644 --- a/AsbCloudWebApi/Controllers/ProcessMapController.cs +++ b/AsbCloudWebApi/Controllers/ProcessMapController.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -20,12 +20,14 @@ namespace AsbCloudWebApi.Controllers public class ProcessMapController : CrudWellRelatedController { private readonly ITelemetryService telemetryService; + private readonly IProcessMapReportService processMapReportService; - public ProcessMapController(IWellService wellService, IProcessMapRepository service, + public ProcessMapController(IWellService wellService, IProcessMapRepository repository, IProcessMapReportService processMapReportService, ITelemetryService telemetryService) - : base(wellService, service) + : base(wellService, repository) { this.telemetryService = telemetryService; + this.processMapReportService = processMapReportService; } /// @@ -77,14 +79,28 @@ namespace AsbCloudWebApi.Controllers /// Выгрузка расширенной РТК /// /// + /// /// /// /// [HttpGet] [Route("getReportFile/{wellId}")] [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)] - public Task GetReportFileAsync(int wellId) + public async Task GetReportFileAsync(int wellId, CancellationToken token) { - throw new NotImplementedException(); + var stream = await processMapReportService.MakeReportAsync(wellId, token); + if (stream != null) + { + var well = await wellService.GetOrDefaultAsync(wellId, token); + if (well is null) + return NoContent(); + else + { + var fileName = $"РТК по скважине {well.Caption} куст {well.Cluster}.xlsx"; + return File(stream, "application/octet-stream", fileName); + } + } + else + return NoContent(); } /// diff --git a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataSaubController.cs b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataSaubController.cs index b9ff1d88..4248778b 100644 --- a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataSaubController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataSaubController.cs @@ -15,7 +15,7 @@ namespace AsbCloudWebApi.Controllers.SAUB { public TelemetryDataSaubController( ITelemetryService telemetryService, - ITelemetryDataService telemetryDataService, + ITelemetryDataSaubService telemetryDataService, IWellService wellService, IHubContext telemetryHubContext) : base( diff --git a/AsbCloudWebApi/Controllers/SAUB/TelemetryWirelineRunOutController.cs b/AsbCloudWebApi/Controllers/SAUB/TelemetryWirelineRunOutController.cs index c32fd408..c7829193 100644 --- a/AsbCloudWebApi/Controllers/SAUB/TelemetryWirelineRunOutController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/TelemetryWirelineRunOutController.cs @@ -24,7 +24,7 @@ namespace AsbCloudWebApi.Controllers.SAUB private readonly IWellService wellService; private readonly IHubContext telemetryHubContext; private readonly ITelemetryWirelineRunOutRepository repository; - private string SirnalRMethodGetDataName => "ReceiveWirelineRunOut"; + private static string SirnalRMethodGetDataName => "ReceiveWirelineRunOut"; public TelemetryWirelineRunOutController( ITelemetryService telemetryService, diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index 2fc8a757..46ce1683 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; @@ -20,13 +21,13 @@ namespace AsbCloudWebApi.Controllers [Authorize] public class WellOperationController : ControllerBase { - private readonly IWellOperationService operationService; + private readonly IWellOperationRepository operationRepository; private readonly IWellService wellService; private readonly IWellOperationImportService wellOperationImportService; - public WellOperationController(IWellOperationService operationService, IWellService wellService, IWellOperationImportService wellOperationImportService) + public WellOperationController(IWellOperationRepository operationService, IWellService wellService, IWellOperationImportService wellOperationImportService) { - this.operationService = operationService; + this.operationRepository = operationService; this.wellService = wellService; this.wellOperationImportService = wellOperationImportService; } @@ -41,7 +42,7 @@ namespace AsbCloudWebApi.Controllers [ProducesResponseType(typeof(IDictionary), (int)System.Net.HttpStatusCode.OK)] public IActionResult GetSectionTypes() { - var result = operationService.GetSectionTypes(); + var result = operationRepository.GetSectionTypes(); return Ok(result); } @@ -55,7 +56,7 @@ namespace AsbCloudWebApi.Controllers [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] public IActionResult GetCategories() { - var result = operationService.GetCategories(); + var result = operationRepository.GetCategories(); return Ok(result); } @@ -78,7 +79,7 @@ namespace AsbCloudWebApi.Controllers return Forbid(); var requestToService = new WellOperationRequest(request, idWell); - var result = await operationService.GetOperationsAsync( + var result = await operationRepository.GetPageAsync( requestToService, token) .ConfigureAwait(false); @@ -105,7 +106,7 @@ namespace AsbCloudWebApi.Controllers return Forbid(); var requestToService = new WellOperationRequest(request, idWell); - var result = await operationService.GetGroupOperationsStatAsync( + var result = await operationRepository.GetGroupOperationsStatAsync( requestToService, token) .ConfigureAwait(false); @@ -129,7 +130,7 @@ namespace AsbCloudWebApi.Controllers if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) return Forbid(); - var result = await operationService.GetOrDefaultAsync(idOperation, token).ConfigureAwait(false); + var result = await operationRepository.GetOrDefaultAsync(idOperation, token).ConfigureAwait(false); return Ok(result); } @@ -152,7 +153,7 @@ namespace AsbCloudWebApi.Controllers foreach(var value in values) value.IdWell= idWell; - var result = await operationService.InsertRangeAsync(values, token) + var result = await operationRepository.InsertRangeAsync(values, token) .ConfigureAwait(false); return Ok(result); @@ -178,7 +179,7 @@ namespace AsbCloudWebApi.Controllers value.IdWell= idWell; value.Id = idOperation; - var result = await operationService.UpdateAsync(value, token) + var result = await operationRepository.UpdateAsync(value, token) .ConfigureAwait(false); return Ok(result); } @@ -199,7 +200,7 @@ namespace AsbCloudWebApi.Controllers token).ConfigureAwait(false)) return Forbid(); - var result = await operationService.DeleteAsync(new int[] { idOperation }, token) + var result = await operationRepository.DeleteAsync(new int[] { idOperation }, token) .ConfigureAwait(false); return Ok(result); diff --git a/ConsoleApp1/ServiceFactory.cs b/ConsoleApp1/ServiceFactory.cs index bf7c9a42..eceb5f9b 100644 --- a/ConsoleApp1/ServiceFactory.cs +++ b/ConsoleApp1/ServiceFactory.cs @@ -1,4 +1,5 @@ using AsbCloudDb.Model; +using AsbCloudInfrastructure.Repository; using AsbCloudInfrastructure.Services; using AsbCloudInfrastructure.Services.SAUB; using AsbCloudInfrastructure.Services.WellOperationService; @@ -71,7 +72,7 @@ namespace ConsoleApp1 public static WellService MakeWellService() => new (Context, memoryCache, MakeTelemetryService(), TimezoneService); - public static WellOperationService MakeWellOperationsService() + public static WellOperationRepository MakeWellOperationRepository() => new (Context, memoryCache, MakeWellService()); public static OperationsStatService MakeOperationsStatService()