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..51e77911 --- /dev/null +++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs @@ -0,0 +1,62 @@ +using System; + +namespace AsbCloudApp.Data.ProcessMap +{ +#nullable enable + /// + /// Модель РТК + /// + public class ProcessMapReportDto + { + /// + /// Идентификатор скважины + /// + public int IdWell { get; set; } + + /// + /// Глубина по стволу, м + /// + public double Depth { get; set; } + + /// + /// Дата/ время + /// + public DateTimeOffset Date { get; set; } + + /// + /// Т мех бурения, ч + /// + public double MechDrillingTime { get; set; } + + /// + /// Слайд + /// + public ProcessMapReportRowDto Slide { get; set; } = null!; + + /// + /// Ротор + /// + public ProcessMapReportRowDto Rotor { get; set; } = null!; + + /// + /// название секции скважины + /// + public string? WellSectionTypeName { get; set; } + + /// + /// название секции скважины + /// + public int? IdWellSectionType { get; set; } + + /// + /// Категория + /// + public string? Category { get; set; } + + /// + /// Идентификатор категории + /// + public int? IdCategory { get; set; } + } +#nullable disable +} diff --git a/AsbCloudApp/Data/ProcessMap/ProcessMapReportParamsDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapReportParamsDto.cs new file mode 100644 index 00000000..6136d144 --- /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..6b4e942d --- /dev/null +++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AsbCloudApp.Data.ProcessMap +{ +#nullable enable + /// + /// Строки РТК + /// + public class ProcessMapReportRowDto + { + /// + /// Перепад давления, атм + /// + public ProcessMapReportParamsDto PressureDrop { get; set; } = null!; + + /// + /// Нагрузка, т + /// + public ProcessMapReportParamsDto Load { get; set; } = null!; + + /// + /// Момент на ВСП, кНхМ + /// + public ProcessMapReportParamsDto TopDriveTorque { get; set; } = null!; + + /// + /// Ограничение скорости, м/ч + /// + public ProcessMapReportParamsDto SpeedL​imit { get; set; } = null!; + + /// + /// Процент использования системы АПД, % + /// + public double PercentageADFSystemUsage { get; set; } + + /// + /// Фактическая механическая скорость, м/ч + /// + public double ActualMechanicalSpeed { get; set; } + + /// + /// Проходка, м + /// + public double? SectionPenetration { get; set; } + } +#nullable disable +} 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/IWellOperationService.cs b/AsbCloudApp/Services/IWellOperationService.cs index ea1aa9b0..b4ac83d4 100644 --- a/AsbCloudApp/Services/IWellOperationService.cs +++ b/AsbCloudApp/Services/IWellOperationService.cs @@ -121,5 +121,13 @@ namespace AsbCloudApp.Services /// /// DateTimeOffset? FirstOperationDate(int idWell); + + /// + /// Получение операций по идентификатору скважины + /// + /// + /// + /// + Task> GetOperationsByIdWellAsync(int idWell, CancellationToken token); } } 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/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 905dbb0e..c9fe96ea 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -136,6 +136,7 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); // admin crud services: services.AddTransient, CrudCacheRepositoryBase>(s => 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/Services/ProcessMap/.~lock.ProcessMapReportTemplate.xlsx# b/AsbCloudInfrastructure/Services/ProcessMap/.~lock.ProcessMapReportTemplate.xlsx# new file mode 100644 index 00000000..8c2b057a --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMap/.~lock.ProcessMapReportTemplate.xlsx# @@ -0,0 +1 @@ +,ASB/andas,asb,19.12.2022 11:39,file:///C:/Users/andas/AppData/Roaming/LibreOffice/4; \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs index 4f371642..fa80efe4 100644 --- a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs @@ -1,6 +1,7 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; using AsbCloudApp.Services; using AsbCloudDb.Model; +using AsbCloudInfrastructure.Services.DailyReport; using ClosedXML.Excel; using System.Collections.Generic; using System.IO; @@ -10,25 +11,35 @@ using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.ProcessMap { +#nullable enable public class ProcessMapReportService : IProcessMapReportService { private readonly IAsbCloudDbContext context; private readonly IProcessMapRepository processMapRepository; + private readonly IProcessMapService processMapService; - public ProcessMapReportService(IAsbCloudDbContext context, IProcessMapRepository processMapRepository) + public ProcessMapReportService(IAsbCloudDbContext context, IProcessMapRepository processMapRepository, IProcessMapService processMapService) { this.context = context; this.processMapRepository = processMapRepository; + this.processMapService = processMapService; } public async Task MakeReportAsync(int idWell, CancellationToken token) { - var dtos = (await processMapRepository.GetByIdWellAsync(idWell, token)) - .GroupBy(x => x.IdWellSectionType); var stream = GetExcelTemplateStream(); using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); - FillProcessMapToWorkbook(workbook, dtos); + var data = processMapService.GetProcessMapAsync(idWell, token); + + //var dtos = await processMapRepository.GetByIdWellAsync(idWell, token).ConfigureAwait(false); + //if (dtos is not null) + //{ + // var processMapReportDto = await processMapService.GetProcessMapAsync(dtos, token).ConfigureAwait(false); + // FillProcessMapToWorkbook(workbook, processMapReportDto); + //} + + FillProcessMapToWorkbook(workbook, new List()); MemoryStream memoryStream = new MemoryStream(); workbook.SaveAs(memoryStream, new SaveOptions { }); @@ -36,20 +47,44 @@ namespace AsbCloudInfrastructure.Services.ProcessMap return memoryStream; } - private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable> dto) + private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable dto) { + var rowsCount = 4; + var columnCount = 2; + var countMerge = 27; + var sheet = workbook.Worksheets.FirstOrDefault(); if (sheet is null) return; + sheet.Row(rowsCount).Cell(columnCount).Value = "saddadasdasdasds"; + sheet.Range(rowsCount, columnCount, rowsCount, countMerge).Row(1).Merge(); + SetBorder(sheet.Row(rowsCount).Cell(columnCount).Style); + + rowsCount++; + sheet.Row(rowsCount).Cell(columnCount).Value = 2; + sheet.Row(rowsCount).Cell(columnCount).Value = 3; + columnCount++; + sheet.Row(rowsCount).Cell(columnCount).Value = 4; } private Stream GetExcelTemplateStream() { var stream = System.Reflection.Assembly.GetExecutingAssembly() .GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx"); - return stream; + return stream!; + } + + private static IXLStyle SetBorder(IXLStyle style) + { + style.Border.RightBorder = XLBorderStyleValues.Medium; + style.Border.LeftBorder = XLBorderStyleValues.Medium; + style.Border.TopBorder = XLBorderStyleValues.Medium; + style.Border.BottomBorder = XLBorderStyleValues.Medium; + style.Border.InsideBorder = XLBorderStyleValues.Medium; + return style; } } +#nullable disable } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs new file mode 100644 index 00000000..180b6ba1 --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs @@ -0,0 +1,159 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; +using AsbCloudApp.Services; +using AsbCloudDb.Model; +using DocumentFormat.OpenXml.Bibliography; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Services.ProcessMap +{ +#nullable enable + public class ProcessMapService : IProcessMapService + { + private readonly IWellOperationService wellOperationService; + private readonly IProcessMapRepository processMapRepository; + + public ProcessMapService(IWellOperationService wellOperationService, + IProcessMapRepository processMapRepository) + { + this.wellOperationService = wellOperationService; + this.processMapRepository = processMapRepository; + } + + public async Task> GetProcessMapAsync(int idWell, CancellationToken token) + { + var categoryIds = new int[] { WellOperationCategory.IdSlide, WellOperationCategory.IdRotor }; + var allOperations = (await wellOperationService.GetOperationsByIdWellAsync(idWell, token).ConfigureAwait(false)) + .Where(x => categoryIds.Contains(x.IdCategory)) + .Where(x => x.IdType == 1) + .OrderBy(x => x.IdWellSectionType) + .ThenBy(x => x.DateStart) + .ToList(); + var processMapDtos = await processMapRepository.GetByIdWellAsync(idWell, token).ConfigureAwait(false); + + var result = allOperations + .GroupBy(x => x.IdWellSectionType) + .SelectMany(x => handleSections(allOperations, processMapDtos!, x)) + .ToList(); + + return result; + } + + private static List handleSections(IEnumerable allWellOperation, IEnumerable processMap, IEnumerable wellOperation) + { + var result = new List(); + var minDepth = wellOperation.Min(o => o.DepthStart); + var maxDepth = wellOperation.Max(o => o.DepthEnd); + + for (var depth = minDepth; depth <= maxDepth; depth += 100) + { + var currentDepth = result.Count() > 0 ? depth + (100 - depth % 100) : depth; + var operation = allWellOperation.First(x => x.DepthEnd >= currentDepth); + var minDate = operation.DateStart; + var maxDate = operation.DateStart.AddHours(operation.DurationHours); + var currentDate = GetDate(currentDepth, minDepth, maxDepth, minDate, maxDate); + var currentHours = GetHourse(currentDepth, minDepth, maxDepth, operation.DurationHours); + var processMapData = processMap.FirstOrDefault(x => x.IdWellSectionType == operation.IdWellSectionType); + + var dto = GetRecord(currentDepth, currentDate, currentHours, operation, processMap); + + if (operation.DepthStart < currentDepth) + { + var prevOperation = allWellOperation.FirstOrDefault(x => x.DepthEnd == operation.DepthStart); + if (prevOperation is not null) + { + var prevDepth = currentDepth - prevOperation.DepthEnd; + var prevMinDate = prevOperation.DateStart; + var prevMaxDate = operation.DateStart.AddHours(operation.DurationHours); + var prevDate = GetDate(prevDepth, prevOperation.DepthStart, prevOperation.DepthEnd, minDate, maxDate); + var prevHours = GetHourse(currentDepth, prevOperation.DepthStart, prevOperation.DepthEnd, prevOperation.DurationHours); + + if (dto.IdCategory != prevOperation.IdCategory) + FillRecordRow(prevDepth, prevHours, dto, prevOperation.IdCategory, processMap); + + dto.MechDrillingTime = currentHours + prevHours; + } + } + + result.Add(dto); + } + + return result; + } + + private static ProcessMapReportDto GetRecord(double depth, DateTimeOffset sate, double hours, WellOperationDto operation, IEnumerable processMap) + { + var dto = new ProcessMapReportDto + { + IdWell = operation.IdWell, + Depth = depth, + Date = sate, + MechDrillingTime = hours, + Category = operation.IdCategory == WellOperationCategory.IdSlide ? "Слайд" : "Ротор", + IdCategory = operation.IdCategory, + IdWellSectionType = operation.IdWellSectionType, + WellSectionTypeName = operation.WellSectionTypeName + }; + FillRecordRow(depth, hours, dto, operation.IdCategory, processMap); + + return dto; + } + + private static void FillRecordRow(double depth, double hours, ProcessMapReportDto dto, int idCategory, IEnumerable processMap) + { + var row = new ProcessMapReportRowDto { + SectionPenetration = depth, + ActualMechanicalSpeed = depth / hours, + PercentageADFSystemUsage = dto.Depth / depth * 100 + }; + + var processMapData = processMap.FirstOrDefault(x => x.IdWell == dto.IdWell && x.IdWellSectionType == dto.IdWellSectionType); + if (processMapData is not null) + { + row.PressureDrop = new ProcessMapReportParamsDto + { + SetPointPlan = processMapData.Pressure.Plan + }; + row.Load = new ProcessMapReportParamsDto + { + SetPointPlan = processMapData.AxialLoad.Plan + }; + row.TopDriveTorque = new ProcessMapReportParamsDto + { + SetPointPlan = processMapData.TopDriveTorque.Plan + }; + row.SpeedL​imit = new ProcessMapReportParamsDto + { + + }; + } + + if (idCategory == WellOperationCategory.IdSlide) + dto.Slide = row; + else + dto.Rotor = row; + } + + private static DateTimeOffset GetDate(double depth, double deptStart, double deptEnd, DateTimeOffset dateStart, DateTimeOffset dateEnd) + { + var a = depth - deptStart; + var b = deptEnd - deptStart; + var c = dateEnd - dateStart; + var result = dateStart + (a / b) * c; + return result; + } + + private static double GetHourse(double depth, double deptStart, double deptEnd, double hourse) + { + var a = depth - deptStart; + var b = deptEnd - deptStart; + var result = 0 + (a / b) * hourse; + return result; + } + } +#nullable disable +} diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs index 6e0d02d6..78870858 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs @@ -139,6 +139,43 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return result; } + public async Task> GetOperationsByIdWellAsync(int idWell, CancellationToken token) + { + var timezone = wellService.GetTimezone(idWell); + var query = BuildQuery(idWell); + var dateStart = query.Min(o => o.DateStart); + + query = query + .OrderBy(e => e.DateStart) + .ThenBy(e => e.DepthEnd) + .ThenBy(e => e.Id); + + var entities = await query.AsNoTracking() + .ToListAsync(token) + .ConfigureAwait(false); + + var nptHours = 0d; + var result = new List(); + + 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.Add(dto); + } + + return result; + } + public async Task> GetGroupOperationsStatAsync( int idWell, int? operationType = default, 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 a80e1758..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;