From 75a0e3fb4bcbfec4593f4657408098afb67580b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Fri, 23 Aug 2024 16:43:09 +0500 Subject: [PATCH 01/13] =?UTF-8?q?=D0=A4=D0=BE=D1=80=D0=BC=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=82=D1=87=D1=91?= =?UTF-8?q?=D1=82=D0=B0=20=D0=BF=D0=BE=20=D1=81=D0=BA=D0=B2=D0=B0=D0=B6?= =?UTF-8?q?=D0=B8=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Data/WellReport/DrillingInfoDto.cs | 16 +++ AsbCloudApp/Data/WellReport/WellReportDto.cs | 18 +++ .../Repositories/IWellOperationRepository.cs | 26 ++-- AsbCloudApp/Services/IWellReportService.cs | 10 ++ .../Repository/WellOperationRepository.cs | 12 +- .../Services/WellReport/WellReportService.cs | 116 ++++++++++++++++++ .../Services/WellService.cs | 2 +- AsbCloudWebApi/Controllers/WellController.cs | 14 +++ 8 files changed, 194 insertions(+), 20 deletions(-) create mode 100644 AsbCloudApp/Data/WellReport/DrillingInfoDto.cs create mode 100644 AsbCloudApp/Data/WellReport/WellReportDto.cs create mode 100644 AsbCloudApp/Services/IWellReportService.cs create mode 100644 AsbCloudInfrastructure/Services/WellReport/WellReportService.cs diff --git a/AsbCloudApp/Data/WellReport/DrillingInfoDto.cs b/AsbCloudApp/Data/WellReport/DrillingInfoDto.cs new file mode 100644 index 00000000..e7f3e4d9 --- /dev/null +++ b/AsbCloudApp/Data/WellReport/DrillingInfoDto.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace AsbCloudApp.Data.WellReport; + +public class DrillingInfoDto +{ + public DatesRangeDto Dates { get; set; } = null!; + + public PlanFactDto Days { get; set; } = null!; + + public PlanFactDto WellBoreDepth { get; set; } + + public PlanFactDto VerticalDepth { get; set; } + + //TODO: Срок строит. без НПВ факт (DE8) +} \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/WellReportDto.cs b/AsbCloudApp/Data/WellReport/WellReportDto.cs new file mode 100644 index 00000000..af2262fe --- /dev/null +++ b/AsbCloudApp/Data/WellReport/WellReportDto.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using AsbCloudApp.Data.User; + +namespace AsbCloudApp.Data.WellReport; + +public class WellReportDto +{ + public WellDto Well { get; set; } + + public DrillingInfoDto DrillingInfo { get; set; } + + public IEnumerable Constacts { get; set; } + + /// + /// Режим работы + /// + public IEnumerable> OperatingMode { get; set; } +} diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs index f80ad02d..26daec7d 100644 --- a/AsbCloudApp/Repositories/IWellOperationRepository.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -62,19 +62,21 @@ public interface IWellOperationRepository Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken); /// - /// Возвращает первую и последнюю фактическую операцию - /// - /// - /// - (WellOperationBaseDto First, WellOperationBaseDto Last)? GetFirstAndLastFact(int idWell); + /// Возвращает первую и последнюю операцию + /// + /// + /// + /// + /// + Task<(WellOperationBaseDto First, WellOperationBaseDto Last)?> GetFirstAndLastAsync(int idWell, int idType, CancellationToken token); - /// - /// Получить список операций по запросу - /// - /// - /// - /// - Task> GetAll(WellOperationRequest request, CancellationToken token); + /// + /// Получить список операций по запросу + /// + /// + /// + /// + Task> GetAll(WellOperationRequest request, CancellationToken token); /// /// Получить список операций по запросу diff --git a/AsbCloudApp/Services/IWellReportService.cs b/AsbCloudApp/Services/IWellReportService.cs new file mode 100644 index 00000000..b69c6383 --- /dev/null +++ b/AsbCloudApp/Services/IWellReportService.cs @@ -0,0 +1,10 @@ +using System.Threading; +using System.Threading.Tasks; +using AsbCloudApp.Data.WellReport; + +namespace AsbCloudApp.Services; + +public interface IWellReportService +{ + Task GetAsync(int idWell, CancellationToken token); +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index f557d106..25033c6d 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -195,13 +195,13 @@ public class WellOperationRepository : CrudRepositoryBase GetFirstAndLastAsync(int idWell, int idType, CancellationToken token) { - var cachedDictionary = memoryCache.GetOrCreate(cacheKeyWellOperations, (entry) => + var cachedDictionary = await memoryCache.GetOrCreateAsync(cacheKeyWellOperations, async (entry) => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5); var query = dbContext.Set() - .Where(o => o.IdType == WellOperation.IdOperationTypeFact) + .Where(o => o.IdType == idType) .GroupBy(o => o.IdWell) .Select(group => new { @@ -210,18 +210,16 @@ public class WellOperationRepository : CrudRepositoryBase o.DateStart).Last(), }); - var entities = query.ToArray(); + var entities = await query.ToArrayAsync(token); var dictionary = entities.ToDictionary(s => s.IdWell, s => (Convert(s.FirstFact), Convert(s.LastFact))); entry.Value = dictionary; return dictionary; - })!; - var firstAndLast = cachedDictionary.GetValueOrDefault(idWell); + var firstAndLast = cachedDictionary?.GetValueOrDefault(idWell); return firstAndLast; - } public override async Task DeleteAsync(int id, CancellationToken token) diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs new file mode 100644 index 00000000..4373026b --- /dev/null +++ b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudApp.Data; +using AsbCloudApp.Data.Trajectory; +using AsbCloudApp.Data.WellOperation; +using AsbCloudApp.Data.WellReport; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudDb.Model; + +namespace AsbCloudInfrastructure.Services.WellReport; + +public class WellReportService : IWellReportService +{ + private readonly IWellService wellService; + private readonly IWellOperationService wellOperationService; + private readonly IWellOperationRepository wellOperationRepository; + private readonly ITrajectoryRepository trajectoryPlanRepository; + private readonly ITrajectoryRepository trajectoryFactRepository; + private readonly IWellContactService wellContactService; + + public WellReportService() + { + } + + public async Task GetAsync(int idWell, CancellationToken token) + { + var wellOperationRequest = new WellOperationRequest(new[] { idWell }) + { + OperationType = WellOperation.IdOperationTypeFact + }; + + var factOperations = (await wellOperationService.GetAsync(wellOperationRequest, token)) + .OrderBy(x => x.DateStart); + + if (!factOperations.Any()) + throw new ArgumentInvalidException(nameof(idWell), "Данные в ГГД факт отсутствуют"); + + wellOperationRequest.OperationType = WellOperation.IdOperationTypePlan; + + var planOperations = (await wellOperationService.GetAsync(wellOperationRequest, token)) + .OrderBy(x => x.DateStart); + + if (!planOperations.Any()) + throw new ArgumentInvalidException(nameof(idWell), "Данные ГГД план отсутствуют"); + + var wellContactRequest = new WellContactRequest() + { + IdsWells = new[] { idWell }, + }; + + var well = await wellService.GetOrDefaultAsync(idWell, token) + ?? throw new ArgumentInvalidException(nameof(idWell), "Скважина не найдена"); + + var drillingInfo = await GetDrillingInfoAsync(idWell, planOperations, factOperations, token); + + var contacts = await wellContactService.GetAllAsync(wellContactRequest, token); + + return new WellReportDto + { + Well = well, + DrillingInfo = drillingInfo, + Constacts = contacts, + }; + } + + private async Task>> GetOperationModeAsync(int idWell, + IEnumerable factWellOperations, CancellationToken token) + { + + } + + private async Task GetDrillingInfoAsync(int idWell, + IEnumerable planOperations, + IEnumerable factOperations, + CancellationToken token) + { + var firstFactOperation = factOperations.First(); + var lastFactOperation = factOperations.Last(); + + var lastPlanOperation = planOperations.Last(); + + var planTrajectories = await trajectoryPlanRepository.GetAsync(idWell, token); + var factTrajectories = await trajectoryFactRepository.GetAsync(idWell, token); + + var drillingInfo = new DrillingInfoDto + { + Dates = new DatesRangeDto + { + From = firstFactOperation.DateStart, + To = lastPlanOperation.DateStart.AddHours(lastPlanOperation.DurationHours), + }, + Days = new PlanFactDto + { + Plan = lastPlanOperation.Day, + Fact = lastFactOperation.Day + }, + WellBoreDepth = new PlanFactDto + { + Plan = planOperations.Max(x => x.DepthEnd), + Fact = factOperations.Max(x => x.DepthEnd) + }, + VerticalDepth = new PlanFactDto + { + Plan = planTrajectories.Max(x => x.VerticalDepth), + Fact = factTrajectories.Max(x => x.VerticalDepth) + }, + }; + + return drillingInfo; + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellService.cs b/AsbCloudInfrastructure/Services/WellService.cs index ba29dc06..fd7d1dd5 100644 --- a/AsbCloudInfrastructure/Services/WellService.cs +++ b/AsbCloudInfrastructure/Services/WellService.cs @@ -274,7 +274,7 @@ public class WellService : CrudCacheRepositoryBase, IWellService dto.Timezone = GetTimezone(entity.Id); dto.StartDate = wellOperationRepository - .GetFirstAndLastFact(entity.Id)?.First?.DateStart; + .GetFirstAndLast(entity.Id)?.First?.DateStart; dto.WellType = entity.WellType.Caption; dto.Cluster = entity.Cluster.Caption; dto.Deposit = entity.Cluster.Deposit.Caption; diff --git a/AsbCloudWebApi/Controllers/WellController.cs b/AsbCloudWebApi/Controllers/WellController.cs index 98e44773..3bdf5819 100644 --- a/AsbCloudWebApi/Controllers/WellController.cs +++ b/AsbCloudWebApi/Controllers/WellController.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; namespace AsbCloudWebApi.Controllers; @@ -149,4 +150,17 @@ public class WellController : ControllerBase return Ok(result); } + + /// + /// Получить отчёт по скважине + /// + /// + /// + /// + [HttpGet("{idWell}/report")] + [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK)] + public Task GetReportAsync(int idWell, CancellationToken token) + { + + } } From 13b4486e3885a3ee04cd93688fa9c459e887fdf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 27 Aug 2024 15:41:17 +0500 Subject: [PATCH 02/13] =?UTF-8?q?=D0=A4=D0=BE=D1=80=D0=BC=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=82=D1=87=D1=91?= =?UTF-8?q?=D1=82=D0=B0=20=D0=BF=D0=BE=20=D1=81=D0=BA=D0=B2=D0=B0=D0=B6?= =?UTF-8?q?=D0=B8=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Data/WellReport/DrillerReportDto.cs | 12 ++ .../Data/WellReport/DrillingBySetpointsDto.cs | 29 +++ .../Data/WellReport/DrillingInfoDto.cs | 16 -- .../Data/WellReport/OperatingModeDto.cs | 78 +++++++ .../Data/WellReport/SectionReportDto.cs | 16 ++ AsbCloudApp/Data/WellReport/WellReportDto.cs | 23 +- .../Services/WellReport/WellReportService.cs | 116 ---------- .../Services/WellReportService.cs | 204 ++++++++++++++++++ 8 files changed, 356 insertions(+), 138 deletions(-) create mode 100644 AsbCloudApp/Data/WellReport/DrillerReportDto.cs create mode 100644 AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs delete mode 100644 AsbCloudApp/Data/WellReport/DrillingInfoDto.cs create mode 100644 AsbCloudApp/Data/WellReport/OperatingModeDto.cs create mode 100644 AsbCloudApp/Data/WellReport/SectionReportDto.cs delete mode 100644 AsbCloudInfrastructure/Services/WellReport/WellReportService.cs create mode 100644 AsbCloudInfrastructure/Services/WellReportService.cs diff --git a/AsbCloudApp/Data/WellReport/DrillerReportDto.cs b/AsbCloudApp/Data/WellReport/DrillerReportDto.cs new file mode 100644 index 00000000..ce2527f3 --- /dev/null +++ b/AsbCloudApp/Data/WellReport/DrillerReportDto.cs @@ -0,0 +1,12 @@ +using AsbCloudApp.Data.Subsystems; +using System.Collections.Generic; + +namespace AsbCloudApp.Data.WellReport; + +//TODO: комментарии +public class DrillerReportDto +{ + public ScheduleDto Shedule { get; set; } + + public IEnumerable SubsystemsStat { get; set; } +} \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs b/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs new file mode 100644 index 00000000..fdb70a6c --- /dev/null +++ b/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AsbCloudApp.Data.ProcessMaps.Report; + +namespace AsbCloudApp.Data.WellReport; + +//TODO: комментарии +public class DrillingBySetpointsDto +{ + public DrillingBySetpointsDto(IEnumerable processMapReport) + { + if (processMapReport.All(x => x.IdWellSectionType != processMapReport.ElementAt(0).IdWellSectionType)) + throw new ArgumentException("Not all entries belong to the same well section", nameof(processMapReport)); + + Pressure = processMapReport.Sum(x => x.DeltaDepth * x.PressureDiff.SetpointUsage / 100), + AxialLoad = processMapReport.Sum(x => x.DeltaDepth * x.AxialLoad.SetpointUsage / 100), + TopDriveTorque = processMapReport.Sum(x => x.DeltaDepth * x.TopDriveTorque.SetpointUsage / 100), + SpeedLimit = processMapReport.Sum(x => x.DeltaDepth * x.SpeedLimit.SetpointUsage / 100) + } + + public double? Pressure { get; set; } + + public double? AxialLoad { get; set; } + + public double? TopDriveTorque { get; set; } + + public double? SpeedLimit { get; set; } +} \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/DrillingInfoDto.cs b/AsbCloudApp/Data/WellReport/DrillingInfoDto.cs deleted file mode 100644 index e7f3e4d9..00000000 --- a/AsbCloudApp/Data/WellReport/DrillingInfoDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; - -namespace AsbCloudApp.Data.WellReport; - -public class DrillingInfoDto -{ - public DatesRangeDto Dates { get; set; } = null!; - - public PlanFactDto Days { get; set; } = null!; - - public PlanFactDto WellBoreDepth { get; set; } - - public PlanFactDto VerticalDepth { get; set; } - - //TODO: Срок строит. без НПВ факт (DE8) -} \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/OperatingModeDto.cs b/AsbCloudApp/Data/WellReport/OperatingModeDto.cs new file mode 100644 index 00000000..d48aba9e --- /dev/null +++ b/AsbCloudApp/Data/WellReport/OperatingModeDto.cs @@ -0,0 +1,78 @@ +using AsbCloudApp.Data.ProcessMaps.Operations; +using System; +using System.Collections.Generic; +using System.Linq; +using AsbCloudApp.Data.WellOperation; + +namespace AsbCloudApp.Data.WellReport; + +//TODO: комментарии +public class OperatingModeDto +{ + public OperatingModeDto(IEnumerable factWellOperations) + { + if (factWellOperations.All(x => x.IdWellSectionType != factWellOperations.ElementAt(0).IdWellSectionType)) + throw new ArgumentException("Not all entries belong to the same well section", nameof(factWellOperations)); + + if (factWellOperations.All(x => x.IdType != 1)) + throw new ArgumentException("Invalid list. There are planned operations", nameof(factWellOperations)); + + DepthStart = factWellOperations.Min(w => w.DepthStart); + DepthEnd = factWellOperations.Max(w => w.DepthEnd); + } + + public OperatingModeDto(IEnumerable processMapPlanRotor) + { + if (processMapPlanRotor.All(x => x.IdWellSectionType != processMapPlanRotor.ElementAt(0).IdWellSectionType)) + throw new ArgumentException("Not all entries belong to the same well section", nameof(processMapPlanRotor)); + + DepthStart = processMapPlanRotor.Min(p => p.DepthStart); + DepthEnd = processMapPlanRotor.Max(p => p.DepthEnd); + RopMin = processMapPlanRotor.Min(p => p.RopMax); + RopMax = processMapPlanRotor.Max(p => p.RopMax); + RopAvg = processMapPlanRotor.Average(p => p.RopMax); + WeightOnBitMin = processMapPlanRotor.Min(p => p.WeightOnBit); + WeightOnBitMax = processMapPlanRotor.Max(p => p.WeightOnBitMax); + WeightOnBitAvg = processMapPlanRotor.Average(p => p.WeightOnBit); + DriveTorqueMin = processMapPlanRotor.Min(p => p.TopDriveTorque); + DriveTorqueMax = processMapPlanRotor.Max(p => p.TopDriveTorqueMax); + DriveTorqueAvg = processMapPlanRotor.Average(p => p.TopDriveTorque); + DifferentialPressureMin = processMapPlanRotor.Min(p => p.DifferentialPressure); + DifferentialPressureMax = processMapPlanRotor.Max(p => p.DifferentialPressureMax); + DifferentialPressureAvg = processMapPlanRotor.Average(p => p.DifferentialPressure); + FrowRateMin = processMapPlanRotor.Min(p => p.FlowRate); + FrowRateMax = processMapPlanRotor.Max(p => p.FlowRateMax); + } + + public double DepthStart { get; set; } + + public double DepthEnd { get; set; } + + public double? RopMin { get; set; } + + public double? RopMax { get; set; } + + public double? RopAvg { get; set; } + + public double? WeightOnBitMin { get; set; } + + public double? WeightOnBitMax { get; set; } + + public double? WeightOnBitAvg { get; set; } + + public double? DriveTorqueMin { get; set; } + + public double? DriveTorqueMax { get; set; } + + public double? DriveTorqueAvg { get; set; } + + public double? DifferentialPressureMin { get; set; } + + public double? DifferentialPressureMax { get; set; } + + public double? DifferentialPressureAvg { get; set; } + + public double? FrowRateMin { get; set; } + + public double? FrowRateMax { get; set; } +} \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/SectionReportDto.cs b/AsbCloudApp/Data/WellReport/SectionReportDto.cs new file mode 100644 index 00000000..a300c6a9 --- /dev/null +++ b/AsbCloudApp/Data/WellReport/SectionReportDto.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using AsbCloudApp.Data.Subsystems; + +namespace AsbCloudApp.Data.WellReport; + +//TODO: комментарии +public class SectionReportDto +{ + public int IdSection { get; set; } + + public IEnumerable SubsystemsStat { get; set; } + + public PlanFactDto? OperatingMode { get; set; } + + public DrillingBySetpointsDto? DrillingBySetpoints { get; set; } +} \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/WellReportDto.cs b/AsbCloudApp/Data/WellReport/WellReportDto.cs index af2262fe..d94a7d0c 100644 --- a/AsbCloudApp/Data/WellReport/WellReportDto.cs +++ b/AsbCloudApp/Data/WellReport/WellReportDto.cs @@ -1,18 +1,29 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using AsbCloudApp.Data.User; namespace AsbCloudApp.Data.WellReport; +//TODO: комментарии public class WellReportDto { public WellDto Well { get; set; } - public DrillingInfoDto DrillingInfo { get; set; } + public DateTimeOffset? DateFrom { get; set; } + + public DateTimeOffset? DateTo { get; set; } + + public PlanFactDto Days { get; set; } = null!; + + public PlanFactDto WellBoreDepth { get; set; } + + public PlanFactDto VerticalDepth { get; set; } + + public double WithoutNtpDays { get; set; } public IEnumerable Constacts { get; set; } - /// - /// Режим работы - /// - public IEnumerable> OperatingMode { get; set; } + public IEnumerable SectionReports { get; set; } + + public IEnumerable DrillerReports { get; set; } } diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs deleted file mode 100644 index 4373026b..00000000 --- a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Data; -using AsbCloudApp.Data.Trajectory; -using AsbCloudApp.Data.WellOperation; -using AsbCloudApp.Data.WellReport; -using AsbCloudApp.Exceptions; -using AsbCloudApp.Repositories; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using AsbCloudDb.Model; - -namespace AsbCloudInfrastructure.Services.WellReport; - -public class WellReportService : IWellReportService -{ - private readonly IWellService wellService; - private readonly IWellOperationService wellOperationService; - private readonly IWellOperationRepository wellOperationRepository; - private readonly ITrajectoryRepository trajectoryPlanRepository; - private readonly ITrajectoryRepository trajectoryFactRepository; - private readonly IWellContactService wellContactService; - - public WellReportService() - { - } - - public async Task GetAsync(int idWell, CancellationToken token) - { - var wellOperationRequest = new WellOperationRequest(new[] { idWell }) - { - OperationType = WellOperation.IdOperationTypeFact - }; - - var factOperations = (await wellOperationService.GetAsync(wellOperationRequest, token)) - .OrderBy(x => x.DateStart); - - if (!factOperations.Any()) - throw new ArgumentInvalidException(nameof(idWell), "Данные в ГГД факт отсутствуют"); - - wellOperationRequest.OperationType = WellOperation.IdOperationTypePlan; - - var planOperations = (await wellOperationService.GetAsync(wellOperationRequest, token)) - .OrderBy(x => x.DateStart); - - if (!planOperations.Any()) - throw new ArgumentInvalidException(nameof(idWell), "Данные ГГД план отсутствуют"); - - var wellContactRequest = new WellContactRequest() - { - IdsWells = new[] { idWell }, - }; - - var well = await wellService.GetOrDefaultAsync(idWell, token) - ?? throw new ArgumentInvalidException(nameof(idWell), "Скважина не найдена"); - - var drillingInfo = await GetDrillingInfoAsync(idWell, planOperations, factOperations, token); - - var contacts = await wellContactService.GetAllAsync(wellContactRequest, token); - - return new WellReportDto - { - Well = well, - DrillingInfo = drillingInfo, - Constacts = contacts, - }; - } - - private async Task>> GetOperationModeAsync(int idWell, - IEnumerable factWellOperations, CancellationToken token) - { - - } - - private async Task GetDrillingInfoAsync(int idWell, - IEnumerable planOperations, - IEnumerable factOperations, - CancellationToken token) - { - var firstFactOperation = factOperations.First(); - var lastFactOperation = factOperations.Last(); - - var lastPlanOperation = planOperations.Last(); - - var planTrajectories = await trajectoryPlanRepository.GetAsync(idWell, token); - var factTrajectories = await trajectoryFactRepository.GetAsync(idWell, token); - - var drillingInfo = new DrillingInfoDto - { - Dates = new DatesRangeDto - { - From = firstFactOperation.DateStart, - To = lastPlanOperation.DateStart.AddHours(lastPlanOperation.DurationHours), - }, - Days = new PlanFactDto - { - Plan = lastPlanOperation.Day, - Fact = lastFactOperation.Day - }, - WellBoreDepth = new PlanFactDto - { - Plan = planOperations.Max(x => x.DepthEnd), - Fact = factOperations.Max(x => x.DepthEnd) - }, - VerticalDepth = new PlanFactDto - { - Plan = planTrajectories.Max(x => x.VerticalDepth), - Fact = factTrajectories.Max(x => x.VerticalDepth) - }, - }; - - return drillingInfo; - } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReportService.cs new file mode 100644 index 00000000..0ea23674 --- /dev/null +++ b/AsbCloudInfrastructure/Services/WellReportService.cs @@ -0,0 +1,204 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMaps.Operations; +using AsbCloudApp.Data.Trajectory; +using AsbCloudApp.Data.WellOperation; +using AsbCloudApp.Data.WellReport; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudApp.Services.ProcessMaps.WellDrilling; +using AsbCloudDb.Model; + +namespace AsbCloudInfrastructure.Services; + +public class WellReportService : IWellReportService +{ + private readonly IWellService wellService; + private readonly IWellOperationService wellOperationService; + private readonly IWellContactService wellContactService; + private readonly IProcessMapReportDrillingService processMapReportDrillingService; + private readonly ISubsystemService subsystemService; + + private readonly ITrajectoryRepository trajectoryPlanRepository; + private readonly ITrajectoryRepository trajectoryFactRepository; + + private readonly IChangeLogRepository + processMapPlanRotorRepository; + + private readonly IScheduleRepository scheduleRepository; + + private IEnumerable factWellOperations; + private IEnumerable planWellOperations; + + public WellReportService(IWellService wellService, IWellOperationService wellOperationService, + IWellContactService wellContactService, IProcessMapReportDrillingService processMapReportDrillingService, + ISubsystemService subsystemService, ITrajectoryRepository trajectoryPlanRepository, + ITrajectoryRepository trajectoryFactRepository, + IChangeLogRepository processMapPlanRotorRepository, + IScheduleRepository scheduleRepository, IEnumerable factWellOperations, + IEnumerable planWellOperations) + { + this.wellService = wellService; + this.wellOperationService = wellOperationService; + this.wellContactService = wellContactService; + this.processMapReportDrillingService = processMapReportDrillingService; + this.subsystemService = subsystemService; + this.trajectoryPlanRepository = trajectoryPlanRepository; + this.trajectoryFactRepository = trajectoryFactRepository; + this.processMapPlanRotorRepository = processMapPlanRotorRepository; + this.scheduleRepository = scheduleRepository; + this.factWellOperations = factWellOperations; + this.planWellOperations = planWellOperations; + } + + public async Task GetAsync(int idWell, CancellationToken token) + { + var well = await wellService.GetOrDefaultAsync(idWell, token) + ?? throw new ArgumentInvalidException(nameof(idWell), "Скважина не найдена"); + + await InitWellOperations(idWell, token); + + var wellContactRequest = new WellContactRequest + { + IdsWells = new[] { idWell }, + }; + + var contacts = await wellContactService.GetAllAsync(wellContactRequest, token); + + var sectionReports = await GetSectionReportsAsync(idWell, token); + var drillerReports = await GetDrillerReportsAsync(idWell, token); + + var firstFactOperation = factWellOperations.MinByOrDefault(x => x.DateStart); + var lastFactOperation = factWellOperations.MaxByOrDefault(x => x.DateStart); + + var lastPlanOperation = planWellOperations.MaxByOrDefault(x => x.DateStart); + + var planTrajectories = await trajectoryPlanRepository.GetAsync(idWell, token); + var factTrajectories = await trajectoryFactRepository.GetAsync(idWell, token); + + var factOperationsWithoutNpt = factWellOperations + .Where(x => x.NptHours == 0); + + return new WellReportDto + { + Well = well, + DateFrom = firstFactOperation?.DateStart, + DateTo = lastPlanOperation?.DateStart.AddHours(lastPlanOperation.DurationHours), + Days = new PlanFactDto + { + Plan = lastPlanOperation?.Day, + Fact = lastFactOperation?.Day + }, + WellBoreDepth = new PlanFactDto + { + Plan = planWellOperations.MaxOrDefault(x => x.DepthEnd), + Fact = factWellOperations.MaxOrDefault(x => x.DepthEnd) + }, + VerticalDepth = new PlanFactDto + { + Plan = planTrajectories.Max(x => x.VerticalDepth), + Fact = factTrajectories.Max(x => x.VerticalDepth) + }, + Constacts = contacts, + SectionReports = sectionReports, + DrillerReports = drillerReports, + WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.Day) + }; + } + + private async Task InitWellOperations(int idWell, CancellationToken token) + { + var request = new WellOperationRequest(new[] { idWell }) + { + OperationType = WellOperation.IdOperationTypeFact + }; + + factWellOperations = await wellOperationService.GetAsync(request, token); + + request.OperationType = WellOperation.IdOperationTypePlan; + + planWellOperations = await wellOperationService.GetAsync(request, token); + } + + private async Task> GetSectionReportsAsync(int idWell, CancellationToken token) + { + var factWellOperationsBySection = factWellOperations.GroupBy(x => x.IdWellSectionType); + + var processMapPlanRequest = new ProcessMapPlanBaseRequestWithWell(idWell); + + var processMapPlanRotorBySection = + (await processMapPlanRotorRepository.GetCurrent(processMapPlanRequest, token)) + .GroupBy(x => x.IdWellSectionType) + .ToDictionary(x => x.Key, x => x.AsEnumerable()); + + var dataSaubStatRequest = new DataSaubStatRequest(); + + var processMapReportBySection = + (await processMapReportDrillingService.GetAsync(idWell, dataSaubStatRequest, token)) + .GroupBy(x => x.IdWellSectionType) + .ToDictionary(x => x.Key, x => x.AsEnumerable()); + + var sectionReports = new List(); + + foreach (var group in factWellOperationsBySection) + { + var subsystemRequest = new SubsystemRequest + { + IdWell = idWell, + GeDepth = group.Min(y => y.DepthStart), + LeDepth = group.Max(y => y.DepthEnd) + }; + + var sectionReport = new SectionReportDto + { + IdSection = group.Key, + SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token), + OperatingMode = new PlanFactDto + { + Fact = new OperatingModeDto(factWellOperations), + } + }; + + if (processMapPlanRotorBySection.TryGetValue(group.Key, out var processMapPlanRotor)) + sectionReport.OperatingMode.Plan = new OperatingModeDto(processMapPlanRotor); + + if (processMapReportBySection.TryGetValue(group.Key, out var processMapReport)) + sectionReport.DrillingBySetpoints = new DrillingBySetpointsDto(processMapReport); + + sectionReports.Add(sectionReport); + } + + return sectionReports; + } + + private async Task> GetDrillerReportsAsync(int idWell, CancellationToken token) + { + var schedules = await scheduleRepository.GetByIdWellAsync(idWell, token); + + var result = new List(); + + foreach (var schedule in schedules) + { + var subsystemRequest = new SubsystemRequest + { + IdWell = idWell, + IdDriller = schedule.IdDriller + }; + + var drillerReport = new DrillerReportDto + { + Shedule = schedule, + SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token); + }; + + result.Add(drillerReport); + } + + return result; + } +} \ No newline at end of file From cf40bb85a10beb767fb6a72398ed622da5e05870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 2 Sep 2024 09:43:21 +0500 Subject: [PATCH 03/13] =?UTF-8?q?=D0=9A=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B8=D0=B8=20=D0=B2=20DTOs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Data/DrillerDto.cs | 5 + .../Data/WellReport/DrillerReportDto.cs | 15 ++- .../Data/WellReport/DrillingBySetpointsDto.cs | 34 ++++--- .../Data/WellReport/OperatingModeDto.cs | 95 ++++++++++--------- .../Data/WellReport/SectionReportDto.cs | 22 ++++- AsbCloudApp/Data/WellReport/WellReportDto.cs | 46 +++++++-- 6 files changed, 142 insertions(+), 75 deletions(-) diff --git a/AsbCloudApp/Data/DrillerDto.cs b/AsbCloudApp/Data/DrillerDto.cs index 1a11bd2a..01a4473d 100644 --- a/AsbCloudApp/Data/DrillerDto.cs +++ b/AsbCloudApp/Data/DrillerDto.cs @@ -29,4 +29,9 @@ public class DrillerDto : IId /// Отчество /// public string? Patronymic { get; set; } + + /// + /// Полное имя + /// + public string FullName => $"{Surname} {Name} {Patronymic}"; } diff --git a/AsbCloudApp/Data/WellReport/DrillerReportDto.cs b/AsbCloudApp/Data/WellReport/DrillerReportDto.cs index ce2527f3..fed9a917 100644 --- a/AsbCloudApp/Data/WellReport/DrillerReportDto.cs +++ b/AsbCloudApp/Data/WellReport/DrillerReportDto.cs @@ -1,12 +1,21 @@ using AsbCloudApp.Data.Subsystems; using System.Collections.Generic; +using System.Linq; namespace AsbCloudApp.Data.WellReport; -//TODO: комментарии +/// +/// Показатели бурильщиков +/// public class DrillerReportDto { - public ScheduleDto Shedule { get; set; } + /// + /// Расписание + /// + public ScheduleDto Shedule { get; set; } = null!; - public IEnumerable SubsystemsStat { get; set; } + /// + /// Наработка подсистем + /// + public IEnumerable SubsystemsStat { get; set; } = Enumerable.Empty(); } \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs b/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs index fdb70a6c..d7175141 100644 --- a/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs +++ b/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs @@ -1,29 +1,27 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using AsbCloudApp.Data.ProcessMaps.Report; +namespace AsbCloudApp.Data.WellReport; -namespace AsbCloudApp.Data.WellReport; - -//TODO: комментарии +/// +/// Бурение по уставкам +/// public class DrillingBySetpointsDto { - public DrillingBySetpointsDto(IEnumerable processMapReport) - { - if (processMapReport.All(x => x.IdWellSectionType != processMapReport.ElementAt(0).IdWellSectionType)) - throw new ArgumentException("Not all entries belong to the same well section", nameof(processMapReport)); - - Pressure = processMapReport.Sum(x => x.DeltaDepth * x.PressureDiff.SetpointUsage / 100), - AxialLoad = processMapReport.Sum(x => x.DeltaDepth * x.AxialLoad.SetpointUsage / 100), - TopDriveTorque = processMapReport.Sum(x => x.DeltaDepth * x.TopDriveTorque.SetpointUsage / 100), - SpeedLimit = processMapReport.Sum(x => x.DeltaDepth * x.SpeedLimit.SetpointUsage / 100) - } - + /// + /// Давление + /// public double? Pressure { get; set; } + /// + /// Нагрузка + /// public double? AxialLoad { get; set; } + /// + /// Момент + /// public double? TopDriveTorque { get; set; } + /// + /// Скорость + /// public double? SpeedLimit { get; set; } } \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/OperatingModeDto.cs b/AsbCloudApp/Data/WellReport/OperatingModeDto.cs index d48aba9e..c355c623 100644 --- a/AsbCloudApp/Data/WellReport/OperatingModeDto.cs +++ b/AsbCloudApp/Data/WellReport/OperatingModeDto.cs @@ -1,78 +1,87 @@ -using AsbCloudApp.Data.ProcessMaps.Operations; -using System; -using System.Collections.Generic; -using System.Linq; -using AsbCloudApp.Data.WellOperation; +namespace AsbCloudApp.Data.WellReport; -namespace AsbCloudApp.Data.WellReport; - -//TODO: комментарии +/// +/// Режим работы +/// public class OperatingModeDto { - public OperatingModeDto(IEnumerable factWellOperations) - { - if (factWellOperations.All(x => x.IdWellSectionType != factWellOperations.ElementAt(0).IdWellSectionType)) - throw new ArgumentException("Not all entries belong to the same well section", nameof(factWellOperations)); - - if (factWellOperations.All(x => x.IdType != 1)) - throw new ArgumentException("Invalid list. There are planned operations", nameof(factWellOperations)); - - DepthStart = factWellOperations.Min(w => w.DepthStart); - DepthEnd = factWellOperations.Max(w => w.DepthEnd); - } - - public OperatingModeDto(IEnumerable processMapPlanRotor) - { - if (processMapPlanRotor.All(x => x.IdWellSectionType != processMapPlanRotor.ElementAt(0).IdWellSectionType)) - throw new ArgumentException("Not all entries belong to the same well section", nameof(processMapPlanRotor)); - - DepthStart = processMapPlanRotor.Min(p => p.DepthStart); - DepthEnd = processMapPlanRotor.Max(p => p.DepthEnd); - RopMin = processMapPlanRotor.Min(p => p.RopMax); - RopMax = processMapPlanRotor.Max(p => p.RopMax); - RopAvg = processMapPlanRotor.Average(p => p.RopMax); - WeightOnBitMin = processMapPlanRotor.Min(p => p.WeightOnBit); - WeightOnBitMax = processMapPlanRotor.Max(p => p.WeightOnBitMax); - WeightOnBitAvg = processMapPlanRotor.Average(p => p.WeightOnBit); - DriveTorqueMin = processMapPlanRotor.Min(p => p.TopDriveTorque); - DriveTorqueMax = processMapPlanRotor.Max(p => p.TopDriveTorqueMax); - DriveTorqueAvg = processMapPlanRotor.Average(p => p.TopDriveTorque); - DifferentialPressureMin = processMapPlanRotor.Min(p => p.DifferentialPressure); - DifferentialPressureMax = processMapPlanRotor.Max(p => p.DifferentialPressureMax); - DifferentialPressureAvg = processMapPlanRotor.Average(p => p.DifferentialPressure); - FrowRateMin = processMapPlanRotor.Min(p => p.FlowRate); - FrowRateMax = processMapPlanRotor.Max(p => p.FlowRateMax); - } - + /// + /// Интервал от + /// public double DepthStart { get; set; } + /// + /// Интервал до + /// public double DepthEnd { get; set; } + /// + /// Скорость проходки мин, м/ч + /// public double? RopMin { get; set; } + /// + /// Скорость проходки максимум, м/ч + /// public double? RopMax { get; set; } + /// + /// Скорость проходки среднее, м/ч + /// public double? RopAvg { get; set; } + /// + /// Нагрузка на долото минимум, т + /// public double? WeightOnBitMin { get; set; } + /// + /// Нагрузка на долото максимум, т + /// public double? WeightOnBitMax { get; set; } + /// + /// Нагрузка на долото среднее, т + /// public double? WeightOnBitAvg { get; set; } + /// + /// Момент минимум, кН*м + /// public double? DriveTorqueMin { get; set; } + /// + /// Момент максимум, кН*м + /// public double? DriveTorqueMax { get; set; } + /// + /// Момент среднее, кН*м + /// public double? DriveTorqueAvg { get; set; } + /// + /// Перепад давления минимум, атм + /// public double? DifferentialPressureMin { get; set; } + /// + /// Перепад давления максимум, атм + /// public double? DifferentialPressureMax { get; set; } + /// + /// Перепад давления среднее, атм + /// public double? DifferentialPressureAvg { get; set; } + /// + /// Q насосов минимум л/с + /// public double? FrowRateMin { get; set; } + /// + /// Q насосов максимум л/с + /// public double? FrowRateMax { get; set; } } \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/SectionReportDto.cs b/AsbCloudApp/Data/WellReport/SectionReportDto.cs index a300c6a9..0acf094d 100644 --- a/AsbCloudApp/Data/WellReport/SectionReportDto.cs +++ b/AsbCloudApp/Data/WellReport/SectionReportDto.cs @@ -3,14 +3,28 @@ using AsbCloudApp.Data.Subsystems; namespace AsbCloudApp.Data.WellReport; -//TODO: комментарии +/// +/// Показатели по секции +/// public class SectionReportDto { + /// + /// Идентификатор секции + /// public int IdSection { get; set; } - public IEnumerable SubsystemsStat { get; set; } - - public PlanFactDto? OperatingMode { get; set; } + /// + /// Наработка подсистем + /// + public IEnumerable SubsystemsStat { get; set; } = []; + + /// + /// Режимы бурения + /// + public PlanFactDto OperatingMode { get; set; } = null!; + /// + /// Бурение по уставкам + /// public DrillingBySetpointsDto? DrillingBySetpoints { get; set; } } \ No newline at end of file diff --git a/AsbCloudApp/Data/WellReport/WellReportDto.cs b/AsbCloudApp/Data/WellReport/WellReportDto.cs index d94a7d0c..ae8e1b9c 100644 --- a/AsbCloudApp/Data/WellReport/WellReportDto.cs +++ b/AsbCloudApp/Data/WellReport/WellReportDto.cs @@ -4,26 +4,58 @@ using AsbCloudApp.Data.User; namespace AsbCloudApp.Data.WellReport; -//TODO: комментарии +/// +/// Отчёт по скважине +/// public class WellReportDto { + /// + /// Информация о скважине + /// public WellDto Well { get; set; } + /// + /// Дата начала бурения + /// public DateTimeOffset? DateFrom { get; set; } + /// + /// Дата окончания бурения + /// public DateTimeOffset? DateTo { get; set; } + /// + /// Дни бурения + /// public PlanFactDto Days { get; set; } = null!; - public PlanFactDto WellBoreDepth { get; set; } + /// + /// Проектная глубина + /// + public PlanFactDto WellBoreDepth { get; set; } = null!; - public PlanFactDto VerticalDepth { get; set; } + /// + /// Вертикальная глубина + /// + public PlanFactDto VerticalDepth { get; set; } = null!; + /// + /// Дни бурения без НПВ + /// public double WithoutNtpDays { get; set; } - public IEnumerable Constacts { get; set; } + /// + /// Контакты + /// + public IEnumerable Contacts { get; set; } = []; - public IEnumerable SectionReports { get; set; } + /// + /// Показатели по секциям + /// + public IEnumerable SectionReports { get; set; } = []; - public IEnumerable DrillerReports { get; set; } -} + /// + /// Показатели по бурильщикам + /// + public IEnumerable DrillerReports { get; set; } = []; +} \ No newline at end of file From 28788bde1fb9da9f0d8d44632fffbb1d09e22d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 2 Sep 2024 09:47:34 +0500 Subject: [PATCH 04/13] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/IWellOperationRepository.cs | 12 +++-- .../Repository/WellOperationRepository.cs | 44 ++++++++++--------- .../Services/WellService.cs | 2 +- AsbCloudInfrastructure/XLExtentions.cs | 27 +++++++----- 4 files changed, 44 insertions(+), 41 deletions(-) diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs index 26daec7d..c18056e2 100644 --- a/AsbCloudApp/Repositories/IWellOperationRepository.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -62,13 +62,11 @@ public interface IWellOperationRepository Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken); /// - /// Возвращает первую и последнюю операцию - /// - /// - /// - /// - /// - Task<(WellOperationBaseDto First, WellOperationBaseDto Last)?> GetFirstAndLastAsync(int idWell, int idType, CancellationToken token); + /// Возвращает первую и последнюю фактическую операцию + /// + /// + /// + (WellOperationBaseDto First, WellOperationBaseDto Last)? GetFirstAndLastFact(int idWell); /// /// Получить список операций по запросу diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index 25033c6d..2fa7b639 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -195,34 +195,36 @@ public class WellOperationRepository : CrudRepositoryBase GetFirstAndLastAsync(int idWell, int idType, CancellationToken token) + public (WellOperationBaseDto First, WellOperationBaseDto Last)? GetFirstAndLastFact(int idWell) { - var cachedDictionary = await memoryCache.GetOrCreateAsync(cacheKeyWellOperations, async (entry) => - { - entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5); - var query = dbContext.Set() - .Where(o => o.IdType == idType) - .GroupBy(o => o.IdWell) - .Select(group => new - { - IdWell = group.Key, - FirstFact = group.OrderBy(o => o.DateStart).First(), - LastFact = group.OrderBy(o => o.DateStart).Last(), - }); + var cachedDictionary = memoryCache.GetOrCreate(cacheKeyWellOperations, (entry) => + { + entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5); + var query = dbContext.Set() + .Where(o => o.IdType == WellOperation.IdOperationTypeFact) + .GroupBy(o => o.IdWell) + .Select(group => new + { + IdWell = group.Key, + FirstFact = group.OrderBy(o => o.DateStart).First(), + LastFact = group.OrderBy(o => o.DateStart).Last(), + }); - var entities = await query.ToArrayAsync(token); + var entities = query.ToArray(); - var dictionary = entities.ToDictionary(s => s.IdWell, s => (Convert(s.FirstFact), Convert(s.LastFact))); - entry.Value = dictionary; + var dictionary = entities.ToDictionary(s => s.IdWell, s => (Convert(s.FirstFact), Convert(s.LastFact))); + entry.Value = dictionary; - return dictionary; - })!; + return dictionary; + + })!; + + var firstAndLast = cachedDictionary.GetValueOrDefault(idWell); + return firstAndLast; - var firstAndLast = cachedDictionary?.GetValueOrDefault(idWell); - return firstAndLast; } - public override async Task DeleteAsync(int id, CancellationToken token) + public override async Task DeleteAsync(int id, CancellationToken token) { var result = await base.DeleteAsync(id, token); if (result > 0) diff --git a/AsbCloudInfrastructure/Services/WellService.cs b/AsbCloudInfrastructure/Services/WellService.cs index fd7d1dd5..ba29dc06 100644 --- a/AsbCloudInfrastructure/Services/WellService.cs +++ b/AsbCloudInfrastructure/Services/WellService.cs @@ -274,7 +274,7 @@ public class WellService : CrudCacheRepositoryBase, IWellService dto.Timezone = GetTimezone(entity.Id); dto.StartDate = wellOperationRepository - .GetFirstAndLast(entity.Id)?.First?.DateStart; + .GetFirstAndLastFact(entity.Id)?.First?.DateStart; dto.WellType = entity.WellType.Caption; dto.Cluster = entity.Cluster.Caption; dto.Deposit = entity.Cluster.Deposit.Caption; diff --git a/AsbCloudInfrastructure/XLExtentions.cs b/AsbCloudInfrastructure/XLExtentions.cs index 7c85c0a6..62992ec2 100644 --- a/AsbCloudInfrastructure/XLExtentions.cs +++ b/AsbCloudInfrastructure/XLExtentions.cs @@ -15,22 +15,25 @@ public static class XLExtentions workbook.Worksheets.FirstOrDefault(ws => string.Equals(ws.Name.Trim(), sheetName.Trim(), StringComparison.CurrentCultureIgnoreCase)) ?? throw new FileFormatException(string.Format(NotFoundSheetTemplate, sheetName)); - public static IXLCell SetCellValue(this IXLCell cell, T value, string? format = null) + public static IXLCell SetCellValue(this IXLCell cell, T? value, string? format = null) { - if (value is DateTime || value is DateTimeOffset) - { - cell.Style.DateFormat.Format = format ?? "DD.MM.YYYY HH:MM:SS"; + if (value == null) + return cell; - if (value is DateTimeOffset dateTimeOffset) - { - cell.Value = XLCellValue.FromObject(dateTimeOffset.DateTime); - return cell; - } - } + if (value is DateTime || value is DateTimeOffset) + { + cell.Style.DateFormat.Format = format ?? "DD.MM.YYYY HH:MM:SS"; - cell.Value = XLCellValue.FromObject(value); + if (value is DateTimeOffset dateTimeOffset) + { + cell.Value = XLCellValue.FromObject(dateTimeOffset.DateTime); + return cell; + } + } - return cell; + cell.Value = XLCellValue.FromObject(value); + + return cell; } public static IXLCell SetHyperlink(this IXLCell cell, string link) From 307c29fcfd6c096dc45656934a5f5260a066e003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 2 Sep 2024 10:07:18 +0500 Subject: [PATCH 05/13] =?UTF-8?q?=D0=A4=D0=BE=D1=80=D0=BC=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B8=20=D1=8D=D0=BA?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D1=80=D1=82=20=D0=BE=D1=82=D1=87=D1=91=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Services/IWellReportService.cs | 10 - .../WellReport/IWellReportExportService.cs | 19 + .../Services/WellReport/IWellReportService.cs | 19 + .../AsbCloudInfrastructure.csproj | 1 + AsbCloudInfrastructure/DependencyInjection.cs | 9 +- .../Services/WellReport/WellReport.xlsx | Bin 0 -> 38088 bytes .../WellReport/WellReportExportService.cs | 382 ++++++++++++++++++ .../Services/WellReport/WellReportService.cs | 234 +++++++++++ .../Services/WellReportService.cs | 204 ---------- 9 files changed, 663 insertions(+), 215 deletions(-) delete mode 100644 AsbCloudApp/Services/IWellReportService.cs create mode 100644 AsbCloudApp/Services/WellReport/IWellReportExportService.cs create mode 100644 AsbCloudApp/Services/WellReport/IWellReportService.cs create mode 100644 AsbCloudInfrastructure/Services/WellReport/WellReport.xlsx create mode 100644 AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs create mode 100644 AsbCloudInfrastructure/Services/WellReport/WellReportService.cs delete mode 100644 AsbCloudInfrastructure/Services/WellReportService.cs diff --git a/AsbCloudApp/Services/IWellReportService.cs b/AsbCloudApp/Services/IWellReportService.cs deleted file mode 100644 index b69c6383..00000000 --- a/AsbCloudApp/Services/IWellReportService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Data.WellReport; - -namespace AsbCloudApp.Services; - -public interface IWellReportService -{ - Task GetAsync(int idWell, CancellationToken token); -} \ No newline at end of file diff --git a/AsbCloudApp/Services/WellReport/IWellReportExportService.cs b/AsbCloudApp/Services/WellReport/IWellReportExportService.cs new file mode 100644 index 00000000..a697e260 --- /dev/null +++ b/AsbCloudApp/Services/WellReport/IWellReportExportService.cs @@ -0,0 +1,19 @@ +using System.IO; +using System.Threading.Tasks; +using System.Threading; + +namespace AsbCloudApp.Services.WellReport; + +/// +/// Сервис экспорта отчёта +/// +public interface IWellReportExportService +{ + /// + /// Экспортировать + /// + /// + /// + /// + Task<(string Name, Stream File)?> ExportAsync(int idWell, CancellationToken token); +} \ No newline at end of file diff --git a/AsbCloudApp/Services/WellReport/IWellReportService.cs b/AsbCloudApp/Services/WellReport/IWellReportService.cs new file mode 100644 index 00000000..9bf61049 --- /dev/null +++ b/AsbCloudApp/Services/WellReport/IWellReportService.cs @@ -0,0 +1,19 @@ +using System.Threading; +using System.Threading.Tasks; +using AsbCloudApp.Data.WellReport; + +namespace AsbCloudApp.Services.WellReport; + +/// +/// Сервис формирования отчёта +/// +public interface IWellReportService +{ + /// + /// Сформировать + /// + /// + /// + /// + Task GetAsync(int idWell, CancellationToken token); +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj index 2942a43a..327b70b7 100644 --- a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj +++ b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj @@ -53,6 +53,7 @@ + diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 7e8d5867..ca66ebe8 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -47,6 +47,8 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; +using AsbCloudApp.Services.WellReport; +using AsbCloudInfrastructure.Services.WellReport; namespace AsbCloudInfrastructure; @@ -469,7 +471,9 @@ public static class DependencyInjection services.AddTransient, TrajectoryEditableRepository>(); services.AddTransient, TrajectoryEditableRepository>(); services.AddTransient(); - services.AddTransient(); + services.AddTransient, TrajectoryEditableRepository>(); + services.AddTransient, TrajectoryEditableRepository>(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient, CrudCacheRepositoryBase(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + return services; } } diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReport.xlsx b/AsbCloudInfrastructure/Services/WellReport/WellReport.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9e3b5ffd4a11210ae752530c9590d1fc61d818ce GIT binary patch literal 38088 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 PlanOperatingModeRows = new Dictionary() + { + { 2, 79 }, // Направление план + { 3, 81 }, // Кондуктор план + { 9, 83 }, // Кондуктор 2 план + { 1, 85 }, // Пилотный ствол план + { 7, 87 }, // Пилотный ствол 2 план + { 13, 89 }, // Пилотный ствол 3 план + { 4, 91 }, // Эксплуатационная колонна план + { 10, 93 }, // Эксплуатационная колонна 2 план + { 6, 95 }, // Хвостовик план + { 12, 97 }, // Хвостовик 2 план + { 18, 99 }, // Хвостовик 3 план + { 24, 101 }, // Хвостовик 4 план + { 30, 103 }, // Хвостовик 5 план + { 34, 105 }, // Хвостовик 6 план + { 35, 107 }, // Хвостовик 7 план + { 36, 109 }, // Хвостовик 8 план + { 37, 111 }, // Хвостовик 9 план + { 38, 113 } // Хвостовик 10 план + }; + + private static readonly IDictionary FactOperatingModeRows = new Dictionary + { + { 2, 80 }, // Направление факт + { 3, 82 }, // Кондуктор факт + { 9, 84 }, // Кондуктор 2 факт + { 1, 86 }, // Пилотный ствол факт + { 7, 88 }, // Пилотный ствол 2 факт + { 13, 90 }, // Пилотный ствол 3 факт + { 4, 92 }, // Эксплуатационная колонна факт + { 10, 94 }, // Эксплуатационная колонна 2 факт + { 6, 96 }, // Хвостовик факт + { 12, 98 }, // Хвостовик 2 факт + { 18, 100 }, // Хвостовик 3 факт + { 24, 102 }, // Хвостовик 4 факт + { 30, 104 }, // Хвостовик 5 факт + { 34, 106 }, // Хвостовик 6 факт + { 35, 108 }, // Хвостовик 7 факт + { 36, 110 }, // Хвостовик 8 факт + { 37, 112 }, // Хвостовик 9 факт + { 38, 114 } // Хвостовик 10 факт + }; + + private static readonly IDictionary SubsystemRows = new Dictionary() + { + { 2, 140 }, // Направление + { 3, 141 }, // Кондуктор + { 9, 142 }, // Кондуктор 2 + { 1, 143 }, // Пилотный ствол + { 7, 144 }, // Пилотный ствол 2 + { 13, 145 }, // Пилотный ствол 3 + { 4, 146 }, // Эксплуатационная колонна + { 10, 147 }, // Эксплуатационная колонна 2 + { 6, 148 }, // Хвостовик + { 12, 149 }, // Хвостовик 2 + { 18, 150 }, // Хвостовик 3 + { 24, 151 }, // Хвостовик 4 + { 30, 152 }, // Хвостовик 5 + { 34, 153 }, // Хвостовик 6 + { 35, 154 }, // Хвостовик 7 + { 36, 155 }, // Хвостовик 8 + { 37, 156 }, // Хвостовик 9 + { 38, 157 } // Хвостовик 10 + }; + + private static readonly IDictionary SetpointsRows = new Dictionary() + { + { 2, 161 }, // Направление + { 3, 162 }, // Кондуктор + { 9, 163 }, // Кондуктор 2 + { 1, 164 }, // Пилотный ствол + { 7, 165 }, // Пилотный ствол 2 + { 13, 166 }, // Пилотный ствол 3 + { 4, 167 }, // Эксплуатационная колонна + { 10, 168 }, // Эксплуатационная колонна 2 + { 6, 169 }, // Хвостовик + { 12, 170 }, // Хвостовик 2 + { 18, 171 }, // Хвостовик 3 + { 24, 172 }, // Хвостовик 4 + { 30, 173 }, // Хвостовик 5 + { 34, 174 }, // Хвостовик 6 + { 35, 175 }, // Хвостовик 7 + { 36, 176 }, // Хвостовик 8 + { 37, 177 }, // Хвостовик 9 + { 38, 178 } // Хвостовик 10 + }; + + private const string TemplateName = "WellReport.xlsx"; + private const string SheetName = "Отчёт"; + + private readonly IWellReportService wellReportService; + + private const string DateFromCell = "D5"; + private const string DateToCell = "E5"; + private const string DaysPlanCell = "D6"; + private const string DaysFactCell = "E6"; + private const string WithoutNtpDaysCell = "D8"; + private const string WellBoreDepthPlanCell = "D12"; + private const string VerticalDepthPlanCell = "E12"; + private const string WellBoreDepthFactCell = "D13"; + private const string VerticalDepthFactCell = "E13"; + private const string WellCell = "I5"; + private const string ClusterCell = "I6"; + private const string DepositCell = "I7"; + private const string CustomerCell = "N5"; + + public WellReportExportService(IWellReportService wellReportService) + { + this.wellReportService = wellReportService; + } + + public async Task<(string Name, Stream File)?> ExportAsync(int idWell, CancellationToken token) + { + var report = await wellReportService.GetAsync(idWell, token); + + if (report == null) + return null; + + var stream = Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateName); + using var workbook = new XLWorkbook(stream); + + var sheet = workbook.GetWorksheet(SheetName); + + FillSheet(sheet, report); + + MemoryStream memoryStream = new(); + workbook.SaveAs(memoryStream, new SaveOptions { }); + memoryStream.Seek(0, SeekOrigin.Begin); + + var name = $"Отчёт по скважине {report.Well.Caption} куст {report.Well.Cluster}.xlsx"; + + return (name, memoryStream); + } + + private static void FillSheet(IXLWorksheet sheet, WellReportDto report) + { + sheet.Cell(DateFromCell).SetCellValue(report.DateFrom); + sheet.Cell(DateToCell).SetCellValue(report.DateTo); + sheet.Cell(DaysPlanCell).SetCellValue(report.Days.Plan); + sheet.Cell(DaysFactCell).SetCellValue(report.Days.Fact); + sheet.Cell(WithoutNtpDaysCell).SetCellValue(report.WithoutNtpDays); + sheet.Cell(WellBoreDepthPlanCell).SetCellValue(report.WellBoreDepth.Plan); + sheet.Cell(WellBoreDepthFactCell).SetCellValue(report.WellBoreDepth.Fact); + sheet.Cell(VerticalDepthPlanCell).SetCellValue(report.VerticalDepth.Plan); + sheet.Cell(VerticalDepthFactCell).SetCellValue(report.VerticalDepth.Fact); + sheet.Cell(WellCell).SetCellValue(report.Well.Caption); + sheet.Cell(ClusterCell).SetCellValue(report.Well.Cluster); + sheet.Cell(DepositCell).SetCellValue(report.Well.Deposit); + + var customer = report.Well.Companies.FirstOrDefault(x => x.IdCompanyType == 1); + sheet.Cell(CustomerCell).SetCellValue(customer?.Caption); + + FillContacts(sheet, report.Contacts); + FillSectionReports(sheet, report.SectionReports); + FillDrillerReports(sheet, report.DrillerReports); + } + + private static void FillContacts(IXLWorksheet sheet, IEnumerable contacts) + { + var positionsByCompanyType = new Dictionary() + { + { 7, "Супервайзер" }, + { 2, "Мастер" }, + { 3, "Инженер по автоматизации" }, + { 5, "Инженер по р-рам " }, + { 6, "Инженер ННБ" }, + { 14, "Инженер по долотам" }, + { 4, "Инженер ГТИ" }, + { 9, "Инженер по цементированию" } + }; + + const int positionColumn = 11; + const int fullNameColumn = 14; + const int companyColumn = 16; + const int phoneColumn = 18; + + contacts = contacts.OrderByDescending(x => x.Id) + .GroupBy(x => x.IdCompanyType) + .Select(x => x.First()); + + var row = 6; + + foreach (var contact in contacts) + { + var position = positionsByCompanyType[contact.IdCompanyType]; + + sheet.Cell(row, positionColumn).SetCellValue(position); + sheet.Cell(row, fullNameColumn).SetCellValue(contact.FullName); + sheet.Cell(row, companyColumn).SetCellValue(contact.Company); + sheet.Cell(row, phoneColumn).SetCellValue(contact.Phone); + + row++; + } + } + + private static void FillDrillerReports(IXLWorksheet sheet, IEnumerable drillerReports) + { + drillerReports = drillerReports.OrderBy(x => x.Shedule.DrillStart); + + const int IdSubsystemAPDRotor = 11; + const int IdSubsystemAPDSlide = 12; + const int IdSubsystemOscillation = 65536; + + const int fullNameColumn = 1; + const int drillStartColumn = 5; + const int drillEndColumn = 6; + const int shiftStart = 7; + const int shiftEnd = 8; + const int kUsageApdRotorColumn = 9; + const int kUsageApdSlideColumn = 10; + const int kUsageOscillationColumn = 11; + + var row = 182; + + foreach (var drillingReport in drillerReports) + { + sheet.Cell(row, fullNameColumn).SetCellValue(drillingReport.Shedule.Driller?.FullName); + sheet.Cell(row, drillStartColumn).SetCellValue(drillingReport.Shedule.DrillStart); + sheet.Cell(row, drillEndColumn).SetCellValue(drillingReport.Shedule.DrillEnd); + sheet.Cell(row, shiftStart).SetCellValue(drillingReport.Shedule.ShiftStart.ToString()); + sheet.Cell(row, shiftEnd).SetCellValue(drillingReport.Shedule.ShiftEnd.ToString()); + + foreach (var subsystemStat in drillingReport.SubsystemsStat) + { + switch (subsystemStat.IdSubsystem) + { + case IdSubsystemAPDRotor: + sheet.Cell(row, kUsageApdRotorColumn).SetCellValue(subsystemStat.KUsage); + break; + case IdSubsystemAPDSlide: + sheet.Cell(row, kUsageApdSlideColumn).SetCellValue(subsystemStat.KUsage); + break; + case IdSubsystemOscillation: + sheet.Cell(row, kUsageOscillationColumn).SetCellValue(subsystemStat.KUsage); + break; + } + } + + row++; + } + } + + private static void FillSectionReports(IXLWorksheet sheet, IEnumerable sectionReports) + { + foreach (var sectionReport in sectionReports) + { + FillOperatingMode(sheet, sectionReport.IdSection, sectionReport.OperatingMode); + + var drillingBySetpoints = sectionReport.DrillingBySetpoints; + + if (drillingBySetpoints != null) + FillDrillingBySetpoints(sheet, sectionReport.IdSection, drillingBySetpoints); + + FillSubsystemsStat(sheet, sectionReport.IdSection, sectionReport.SubsystemsStat); + } + } + + private static void FillDrillingBySetpoints(IXLWorksheet sheet, int idSection, + DrillingBySetpointsDto drillingBySetpoints) + { + const int pressureColumn = 8; + const int axialLoadColumn = 9; + const int topDriveTorqueColumn = 10; + const int speedLimitColumn = 11; + + if (!SetpointsRows.TryGetValue(idSection, out var row)) + return; + + sheet.Cell(row, pressureColumn).SetCellValue(drillingBySetpoints.Pressure); + sheet.Cell(row, axialLoadColumn).SetCellValue(drillingBySetpoints.AxialLoad); + sheet.Cell(row, topDriveTorqueColumn).SetCellValue(drillingBySetpoints.TopDriveTorque); + sheet.Cell(row, speedLimitColumn).SetCellValue(drillingBySetpoints.SpeedLimit); + } + + private static void FillSubsystemsStat(IXLWorksheet sheet, int idSection, + IEnumerable subsystemsStat) + { + const int idSubsystemAPDRotor = 11; + const int idSubsystemAPDSlide = 12; + const int idSubsystemOscillation = 65536; + + const int kUsageApdRotorColumn = 3; + const int kUsageApdSlideColumn = 4; + const int kUsageOscillationColumn = 5; + + const int sumDepthIntervalApdRotorColumn = 14; + const int sumDepthIntervalApdSlideColumn = 15; + const int sumDepthIntervalApdOscillation = 17; + + if (!SubsystemRows.TryGetValue(idSection, out var row)) + return; + + foreach (var subsystemStat in subsystemsStat) + { + switch (subsystemStat.IdSubsystem) + { + case idSubsystemAPDRotor: + sheet.Cell(row, kUsageApdRotorColumn).SetCellValue(subsystemStat.KUsage); + sheet.Cell(row, sumDepthIntervalApdRotorColumn).SetCellValue(subsystemStat.SumDepthInterval); + break; + case idSubsystemAPDSlide: + sheet.Cell(row, kUsageApdSlideColumn).SetCellValue(subsystemStat.KUsage); + sheet.Cell(row, sumDepthIntervalApdSlideColumn).SetCellValue(subsystemStat.SumDepthInterval); + break; + case idSubsystemOscillation: + sheet.Cell(row, kUsageOscillationColumn).SetCellValue(subsystemStat.KUsage); + sheet.Cell(row, sumDepthIntervalApdOscillation).SetCellValue(subsystemStat.SumDepthInterval); + break; + } + } + } + + private static void FillOperatingMode(IXLWorksheet sheet, int idSection, + PlanFactDto operatingMode) + { + const int depthStartColumn = 3; + const int depthEndColumn = 4; + const int ropMinColumn = 6; + const int ropMaxColumn = 7; + const int ropAvgColumn = 8; + const int weightOnBitMinColumn = 9; + const int weightOnBitMaxColumn = 10; + const int weightOnBitAvgColumn = 11; + const int driveTorqueMinColumn = 12; + const int driveTorqueMaxColumn = 13; + const int driveTorqueAvgColumn = 14; + const int differentialPressureMinColumn = 15; + const int differentialPressureMaxColumn = 16; + const int differentialPressureAvgColumn = 17; + const int frowRateMinColumn = 18; + const int frowRateMaxColumn = 19; + + if (!PlanOperatingModeRows.TryGetValue(idSection, out var planRow)) + return; + + if (!FactOperatingModeRows.TryGetValue(idSection, out var factRow)) + return; + + sheet.Cell(planRow, depthStartColumn).SetCellValue(operatingMode.Plan?.DepthStart); + sheet.Cell(planRow, depthEndColumn).SetCellValue(operatingMode.Plan?.DepthEnd); + + sheet.Cell(planRow, ropMinColumn).SetCellValue(operatingMode.Plan?.RopMin); + sheet.Cell(planRow, ropMaxColumn).SetCellValue(operatingMode.Plan?.RopMax); + sheet.Cell(planRow, ropAvgColumn).SetCellValue(operatingMode.Plan?.RopAvg); + + sheet.Cell(planRow, weightOnBitMinColumn).SetCellValue(operatingMode.Plan?.WeightOnBitMin); + sheet.Cell(planRow, weightOnBitMaxColumn).SetCellValue(operatingMode.Plan?.WeightOnBitMax); + sheet.Cell(planRow, weightOnBitAvgColumn).SetCellValue(operatingMode.Plan?.WeightOnBitAvg); + + sheet.Cell(planRow, driveTorqueMinColumn).SetCellValue(operatingMode.Plan?.DriveTorqueMin); + sheet.Cell(planRow, driveTorqueMaxColumn).SetCellValue(operatingMode.Plan?.DriveTorqueMax); + sheet.Cell(planRow, driveTorqueAvgColumn).SetCellValue(operatingMode.Plan?.DriveTorqueAvg); + + sheet.Cell(planRow, differentialPressureMinColumn).SetCellValue(operatingMode.Plan?.DifferentialPressureMin); + sheet.Cell(planRow, differentialPressureMaxColumn).SetCellValue(operatingMode.Plan?.DifferentialPressureMax); + sheet.Cell(planRow, differentialPressureAvgColumn).SetCellValue(operatingMode.Plan?.DifferentialPressureAvg); + + sheet.Cell(planRow, frowRateMinColumn).SetCellValue(operatingMode.Plan?.FrowRateMin); + sheet.Cell(planRow, frowRateMaxColumn).SetCellValue(operatingMode.Plan?.FrowRateMax); + + sheet.Cell(factRow, depthStartColumn).SetCellValue(operatingMode.Fact?.DepthStart); + sheet.Cell(factRow, depthEndColumn).SetCellValue(operatingMode.Fact?.DepthEnd); + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs new file mode 100644 index 00000000..49b7d1fa --- /dev/null +++ b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs @@ -0,0 +1,234 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMaps.Operations; +using AsbCloudApp.Data.Trajectory; +using AsbCloudApp.Data.WellOperation; +using AsbCloudApp.Data.WellReport; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudApp.Services.ProcessMaps.WellDrilling; +using AsbCloudApp.Services.WellReport; +using AsbCloudDb.Model; + +namespace AsbCloudInfrastructure.Services.WellReport; + +public class WellReportService : IWellReportService +{ + private readonly IWellService wellService; + private readonly IWellOperationService wellOperationService; + private readonly IWellContactService wellContactService; + private readonly IProcessMapReportDrillingService processMapReportDrillingService; + private readonly ISubsystemService subsystemService; + + private readonly ITrajectoryRepository trajectoryPlanRepository; + private readonly ITrajectoryRepository trajectoryFactRepository; + + private readonly IChangeLogRepository + processMapPlanRotorRepository; + + private readonly IScheduleRepository scheduleRepository; + + private IEnumerable factWellOperations; + private IEnumerable planWellOperations; + + public WellReportService(IWellService wellService, IWellOperationService wellOperationService, + IWellContactService wellContactService, IProcessMapReportDrillingService processMapReportDrillingService, + ISubsystemService subsystemService, ITrajectoryRepository trajectoryPlanRepository, + ITrajectoryRepository trajectoryFactRepository, + IChangeLogRepository processMapPlanRotorRepository, + IScheduleRepository scheduleRepository, IEnumerable factWellOperations, + IEnumerable planWellOperations) + { + this.wellService = wellService; + this.wellOperationService = wellOperationService; + this.wellContactService = wellContactService; + this.processMapReportDrillingService = processMapReportDrillingService; + this.subsystemService = subsystemService; + this.trajectoryPlanRepository = trajectoryPlanRepository; + this.trajectoryFactRepository = trajectoryFactRepository; + this.processMapPlanRotorRepository = processMapPlanRotorRepository; + this.scheduleRepository = scheduleRepository; + this.factWellOperations = factWellOperations; + this.planWellOperations = planWellOperations; + } + + public async Task GetAsync(int idWell, CancellationToken token) + { + var well = await wellService.GetOrDefaultAsync(idWell, token); + + if (well == null) + return null; + + await InitWellOperations(idWell, token); + + var wellContactRequest = new WellContactRequest + { + IdsWells = new[] { idWell }, + }; + + var contacts = await wellContactService.GetAllAsync(wellContactRequest, token); + + var sectionReports = await GetSectionReportsAsync(idWell, token); + var drillerReports = await GetDrillerReportsAsync(idWell, token); + + var firstFactOperation = factWellOperations.MinByOrDefault(x => x.DateStart); + var lastFactOperation = factWellOperations.MaxByOrDefault(x => x.DateStart); + + var lastPlanOperation = planWellOperations.MaxByOrDefault(x => x.DateStart); + + var planTrajectories = await trajectoryPlanRepository.GetAsync(idWell, token); + var factTrajectories = await trajectoryFactRepository.GetAsync(idWell, token); + + var factOperationsWithoutNpt = factWellOperations + .Where(x => x.NptHours == 0); + + return new WellReportDto + { + Well = well, + DateFrom = firstFactOperation?.DateStart, + DateTo = lastPlanOperation?.DateStart.AddHours(lastPlanOperation.DurationHours), + Days = new PlanFactDto + { + Plan = lastPlanOperation?.Day, + Fact = lastFactOperation?.Day + }, + WellBoreDepth = new PlanFactDto + { + Plan = planWellOperations.MaxOrDefault(x => x.DepthEnd), + Fact = factWellOperations.MaxOrDefault(x => x.DepthEnd) + }, + VerticalDepth = new PlanFactDto + { + Plan = planTrajectories.Max(x => x.VerticalDepth), + Fact = factTrajectories.Max(x => x.VerticalDepth) + }, + WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.Day), + Contacts = contacts, + SectionReports = sectionReports, + DrillerReports = drillerReports, + }; + } + + private async Task InitWellOperations(int idWell, CancellationToken token) + { + var request = new WellOperationRequest(new[] { idWell }) + { + OperationType = WellOperation.IdOperationTypeFact + }; + + factWellOperations = await wellOperationService.GetAsync(request, token); + + request.OperationType = WellOperation.IdOperationTypePlan; + + planWellOperations = await wellOperationService.GetAsync(request, token); + } + + private async Task> GetSectionReportsAsync(int idWell, CancellationToken token) + { + var factWellOperationsBySection = factWellOperations.GroupBy(x => x.IdWellSectionType); + + var processMapPlanRequest = new ProcessMapPlanBaseRequestWithWell(idWell); + + var processMapPlanRotorBySection = + (await processMapPlanRotorRepository.GetCurrent(processMapPlanRequest, token)) + .GroupBy(x => x.IdWellSectionType) + .ToDictionary(x => x.Key, x => x.AsEnumerable()); + + var dataSaubStatRequest = new DataSaubStatRequest(); + + var processMapReportBySection = + (await processMapReportDrillingService.GetAsync(idWell, dataSaubStatRequest, token)) + .GroupBy(x => x.IdWellSectionType) + .ToDictionary(x => x.Key, x => x.AsEnumerable()); + + var sectionReports = new List(); + + foreach (var group in factWellOperationsBySection) + { + var subsystemRequest = new SubsystemRequest + { + IdWell = idWell, + GeDepth = group.Min(y => y.DepthStart), + LeDepth = group.Max(y => y.DepthEnd) + }; + + var sectionReport = new SectionReportDto + { + IdSection = group.Key, + SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token), + OperatingMode = new PlanFactDto + { + Fact = new OperatingModeDto + { + DepthStart = factWellOperations.Min(w => w.DepthStart), + DepthEnd = factWellOperations.Max(w => w.DepthEnd) + } + } + }; + + if (processMapPlanRotorBySection.TryGetValue(group.Key, out var processMapPlanRotor)) + sectionReport.OperatingMode.Plan = new OperatingModeDto + { + DepthStart = processMapPlanRotor.Min(p => p.DepthStart), + DepthEnd = processMapPlanRotor.Max(p => p.DepthEnd), + RopMin = processMapPlanRotor.Min(p => p.RopMax), + RopMax = processMapPlanRotor.Max(p => p.RopMax), + RopAvg = processMapPlanRotor.Average(p => p.RopMax), + WeightOnBitMin = processMapPlanRotor.Min(p => p.WeightOnBit), + WeightOnBitMax = processMapPlanRotor.Max(p => p.WeightOnBitMax), + WeightOnBitAvg = processMapPlanRotor.Average(p => p.WeightOnBit), + DriveTorqueMin = processMapPlanRotor.Min(p => p.TopDriveTorque), + DriveTorqueMax = processMapPlanRotor.Max(p => p.TopDriveTorqueMax), + DriveTorqueAvg = processMapPlanRotor.Average(p => p.TopDriveTorque), + DifferentialPressureMin = processMapPlanRotor.Min(p => p.DifferentialPressure), + DifferentialPressureMax = processMapPlanRotor.Max(p => p.DifferentialPressureMax), + DifferentialPressureAvg = processMapPlanRotor.Average(p => p.DifferentialPressure), + FrowRateMin = processMapPlanRotor.Min(p => p.FlowRate), + FrowRateMax = processMapPlanRotor.Max(p => p.FlowRateMax) + }; + + if (processMapReportBySection.TryGetValue(group.Key, out var processMapReport)) + sectionReport.DrillingBySetpoints = new DrillingBySetpointsDto + { + Pressure = processMapReport.Sum(x => x.DeltaDepth * x.PressureDiff.SetpointUsage / 100), + AxialLoad = processMapReport.Sum(x => x.DeltaDepth * x.AxialLoad.SetpointUsage / 100), + TopDriveTorque = processMapReport.Sum(x => x.DeltaDepth * x.TopDriveTorque.SetpointUsage / 100), + SpeedLimit = processMapReport.Sum(x => x.DeltaDepth * x.SpeedLimit.SetpointUsage / 100) + }; + + sectionReports.Add(sectionReport); + } + + return sectionReports; + } + + private async Task> GetDrillerReportsAsync(int idWell, CancellationToken token) + { + var schedules = await scheduleRepository.GetByIdWellAsync(idWell, token); + + var result = new List(); + + foreach (var schedule in schedules) + { + var subsystemRequest = new SubsystemRequest + { + IdWell = idWell, + IdDriller = schedule.IdDriller + }; + + var drillerReport = new DrillerReportDto + { + Shedule = schedule, + SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token) + }; + + result.Add(drillerReport); + } + + return result; + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReportService.cs deleted file mode 100644 index 0ea23674..00000000 --- a/AsbCloudInfrastructure/Services/WellReportService.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Data; -using AsbCloudApp.Data.ProcessMaps.Operations; -using AsbCloudApp.Data.Trajectory; -using AsbCloudApp.Data.WellOperation; -using AsbCloudApp.Data.WellReport; -using AsbCloudApp.Exceptions; -using AsbCloudApp.Repositories; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using AsbCloudApp.Services.ProcessMaps.WellDrilling; -using AsbCloudDb.Model; - -namespace AsbCloudInfrastructure.Services; - -public class WellReportService : IWellReportService -{ - private readonly IWellService wellService; - private readonly IWellOperationService wellOperationService; - private readonly IWellContactService wellContactService; - private readonly IProcessMapReportDrillingService processMapReportDrillingService; - private readonly ISubsystemService subsystemService; - - private readonly ITrajectoryRepository trajectoryPlanRepository; - private readonly ITrajectoryRepository trajectoryFactRepository; - - private readonly IChangeLogRepository - processMapPlanRotorRepository; - - private readonly IScheduleRepository scheduleRepository; - - private IEnumerable factWellOperations; - private IEnumerable planWellOperations; - - public WellReportService(IWellService wellService, IWellOperationService wellOperationService, - IWellContactService wellContactService, IProcessMapReportDrillingService processMapReportDrillingService, - ISubsystemService subsystemService, ITrajectoryRepository trajectoryPlanRepository, - ITrajectoryRepository trajectoryFactRepository, - IChangeLogRepository processMapPlanRotorRepository, - IScheduleRepository scheduleRepository, IEnumerable factWellOperations, - IEnumerable planWellOperations) - { - this.wellService = wellService; - this.wellOperationService = wellOperationService; - this.wellContactService = wellContactService; - this.processMapReportDrillingService = processMapReportDrillingService; - this.subsystemService = subsystemService; - this.trajectoryPlanRepository = trajectoryPlanRepository; - this.trajectoryFactRepository = trajectoryFactRepository; - this.processMapPlanRotorRepository = processMapPlanRotorRepository; - this.scheduleRepository = scheduleRepository; - this.factWellOperations = factWellOperations; - this.planWellOperations = planWellOperations; - } - - public async Task GetAsync(int idWell, CancellationToken token) - { - var well = await wellService.GetOrDefaultAsync(idWell, token) - ?? throw new ArgumentInvalidException(nameof(idWell), "Скважина не найдена"); - - await InitWellOperations(idWell, token); - - var wellContactRequest = new WellContactRequest - { - IdsWells = new[] { idWell }, - }; - - var contacts = await wellContactService.GetAllAsync(wellContactRequest, token); - - var sectionReports = await GetSectionReportsAsync(idWell, token); - var drillerReports = await GetDrillerReportsAsync(idWell, token); - - var firstFactOperation = factWellOperations.MinByOrDefault(x => x.DateStart); - var lastFactOperation = factWellOperations.MaxByOrDefault(x => x.DateStart); - - var lastPlanOperation = planWellOperations.MaxByOrDefault(x => x.DateStart); - - var planTrajectories = await trajectoryPlanRepository.GetAsync(idWell, token); - var factTrajectories = await trajectoryFactRepository.GetAsync(idWell, token); - - var factOperationsWithoutNpt = factWellOperations - .Where(x => x.NptHours == 0); - - return new WellReportDto - { - Well = well, - DateFrom = firstFactOperation?.DateStart, - DateTo = lastPlanOperation?.DateStart.AddHours(lastPlanOperation.DurationHours), - Days = new PlanFactDto - { - Plan = lastPlanOperation?.Day, - Fact = lastFactOperation?.Day - }, - WellBoreDepth = new PlanFactDto - { - Plan = planWellOperations.MaxOrDefault(x => x.DepthEnd), - Fact = factWellOperations.MaxOrDefault(x => x.DepthEnd) - }, - VerticalDepth = new PlanFactDto - { - Plan = planTrajectories.Max(x => x.VerticalDepth), - Fact = factTrajectories.Max(x => x.VerticalDepth) - }, - Constacts = contacts, - SectionReports = sectionReports, - DrillerReports = drillerReports, - WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.Day) - }; - } - - private async Task InitWellOperations(int idWell, CancellationToken token) - { - var request = new WellOperationRequest(new[] { idWell }) - { - OperationType = WellOperation.IdOperationTypeFact - }; - - factWellOperations = await wellOperationService.GetAsync(request, token); - - request.OperationType = WellOperation.IdOperationTypePlan; - - planWellOperations = await wellOperationService.GetAsync(request, token); - } - - private async Task> GetSectionReportsAsync(int idWell, CancellationToken token) - { - var factWellOperationsBySection = factWellOperations.GroupBy(x => x.IdWellSectionType); - - var processMapPlanRequest = new ProcessMapPlanBaseRequestWithWell(idWell); - - var processMapPlanRotorBySection = - (await processMapPlanRotorRepository.GetCurrent(processMapPlanRequest, token)) - .GroupBy(x => x.IdWellSectionType) - .ToDictionary(x => x.Key, x => x.AsEnumerable()); - - var dataSaubStatRequest = new DataSaubStatRequest(); - - var processMapReportBySection = - (await processMapReportDrillingService.GetAsync(idWell, dataSaubStatRequest, token)) - .GroupBy(x => x.IdWellSectionType) - .ToDictionary(x => x.Key, x => x.AsEnumerable()); - - var sectionReports = new List(); - - foreach (var group in factWellOperationsBySection) - { - var subsystemRequest = new SubsystemRequest - { - IdWell = idWell, - GeDepth = group.Min(y => y.DepthStart), - LeDepth = group.Max(y => y.DepthEnd) - }; - - var sectionReport = new SectionReportDto - { - IdSection = group.Key, - SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token), - OperatingMode = new PlanFactDto - { - Fact = new OperatingModeDto(factWellOperations), - } - }; - - if (processMapPlanRotorBySection.TryGetValue(group.Key, out var processMapPlanRotor)) - sectionReport.OperatingMode.Plan = new OperatingModeDto(processMapPlanRotor); - - if (processMapReportBySection.TryGetValue(group.Key, out var processMapReport)) - sectionReport.DrillingBySetpoints = new DrillingBySetpointsDto(processMapReport); - - sectionReports.Add(sectionReport); - } - - return sectionReports; - } - - private async Task> GetDrillerReportsAsync(int idWell, CancellationToken token) - { - var schedules = await scheduleRepository.GetByIdWellAsync(idWell, token); - - var result = new List(); - - foreach (var schedule in schedules) - { - var subsystemRequest = new SubsystemRequest - { - IdWell = idWell, - IdDriller = schedule.IdDriller - }; - - var drillerReport = new DrillerReportDto - { - Shedule = schedule, - SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token); - }; - - result.Add(drillerReport); - } - - return result; - } -} \ No newline at end of file From e2f053af6c857c39d159e581cc3cc73952fcf664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 2 Sep 2024 10:16:04 +0500 Subject: [PATCH 06/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20API=20=D1=8D?= =?UTF-8?q?=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82=D0=B0=20=D0=BE=D1=82=D1=87?= =?UTF-8?q?=D1=91=D1=82=D0=B0=20=D0=BF=D0=BE=20=D1=81=D0=BA=D0=B2=D0=B0?= =?UTF-8?q?=D0=B6=D0=B8=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudWebApi/Controllers/WellController.cs | 27 +++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/AsbCloudWebApi/Controllers/WellController.cs b/AsbCloudWebApi/Controllers/WellController.cs index 3bdf5819..d6d97547 100644 --- a/AsbCloudWebApi/Controllers/WellController.cs +++ b/AsbCloudWebApi/Controllers/WellController.cs @@ -1,13 +1,12 @@ using AsbCloudApp.Data; -using AsbCloudApp.Exceptions; using AsbCloudApp.Services; -using AsbCloudDb.Model; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Services.WellReport; using Microsoft.AspNetCore.Http; namespace AsbCloudWebApi.Controllers; @@ -21,11 +20,13 @@ namespace AsbCloudWebApi.Controllers; public class WellController : ControllerBase { private readonly IWellService wellService; + private readonly IWellReportExportService wellReportExportService; - public WellController(IWellService wellService) - { - this.wellService = wellService; - } + public WellController(IWellService wellService, IWellReportExportService wellReportExportService) + { + this.wellService = wellService; + this.wellReportExportService = wellReportExportService; + } /// /// Возвращает список доступных скважин @@ -151,16 +152,24 @@ public class WellController : ControllerBase } + //TODO: навзание пока такое. У нас в API уже есть метод с такой сигнатурой. + /// /// Получить отчёт по скважине /// /// /// /// - [HttpGet("{idWell}/report")] - [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK)] - public Task GetReportAsync(int idWell, CancellationToken token) + [HttpGet("{idWell}/report/export")] + [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public async Task ExportAsync(int idWell, CancellationToken token) { + var report = await wellReportExportService.ExportAsync(idWell, token); + if (report is null) + return NoContent(); + + return File(report.Value.File, "application/octet-stream", report.Value.Name); } } From ca54ae517f91ab1187d84e8a5470d434350aeaca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 2 Sep 2024 13:55:17 +0500 Subject: [PATCH 07/13] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D0=BD=D0=B5?= =?UTF-8?q?=D0=B9=D0=BC=D0=B8=D0=BD=D0=B3=D0=B0=20=D0=B8=20=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D0=B2=D0=B8=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Data/WellReport/DrillingBySetpointsDto.cs | 32 +++++++++---------- .../WellReport/WellReportExportService.cs | 25 ++++++++------- .../Services/WellReport/WellReportService.cs | 22 ++++++------- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs b/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs index d7175141..a1c43036 100644 --- a/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs +++ b/AsbCloudApp/Data/WellReport/DrillingBySetpointsDto.cs @@ -5,23 +5,23 @@ /// public class DrillingBySetpointsDto { - /// - /// Давление - /// - public double? Pressure { get; set; } + /// + /// Метры пробуренные по уставке давления + /// + public double? MetersByPressure { get; set; } - /// - /// Нагрузка - /// - public double? AxialLoad { get; set; } + /// + /// Метры пробуренные по уставке нагрузки + /// + public double? MetersByLoad { get; set; } - /// - /// Момент - /// - public double? TopDriveTorque { get; set; } + /// + /// Метры пробуренные по уставке момента + /// + public double? MetersByTorque { get; set; } - /// - /// Скорость - /// - public double? SpeedLimit { get; set; } + /// + /// Метры пробуренные по уставке скорости + /// + public double? MetersBySpeed { get; set; } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs index 457a620c..55ec4fb0 100644 --- a/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs +++ b/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs @@ -199,16 +199,17 @@ public class WellReportExportService : IWellReportExportService var row = 6; foreach (var contact in contacts) - { - var position = positionsByCompanyType[contact.IdCompanyType]; + { + if (!positionsByCompanyType.TryGetValue(contact.IdCompanyType, out var position)) + continue; - sheet.Cell(row, positionColumn).SetCellValue(position); - sheet.Cell(row, fullNameColumn).SetCellValue(contact.FullName); - sheet.Cell(row, companyColumn).SetCellValue(contact.Company); - sheet.Cell(row, phoneColumn).SetCellValue(contact.Phone); + sheet.Cell(row, positionColumn).SetCellValue(position); + sheet.Cell(row, fullNameColumn).SetCellValue(contact.FullName); + sheet.Cell(row, companyColumn).SetCellValue(contact.Company); + sheet.Cell(row, phoneColumn).SetCellValue(contact.Phone); - row++; - } + row++; + } } private static void FillDrillerReports(IXLWorksheet sheet, IEnumerable drillerReports) @@ -284,10 +285,10 @@ public class WellReportExportService : IWellReportExportService if (!SetpointsRows.TryGetValue(idSection, out var row)) return; - sheet.Cell(row, pressureColumn).SetCellValue(drillingBySetpoints.Pressure); - sheet.Cell(row, axialLoadColumn).SetCellValue(drillingBySetpoints.AxialLoad); - sheet.Cell(row, topDriveTorqueColumn).SetCellValue(drillingBySetpoints.TopDriveTorque); - sheet.Cell(row, speedLimitColumn).SetCellValue(drillingBySetpoints.SpeedLimit); + sheet.Cell(row, pressureColumn).SetCellValue(drillingBySetpoints.MetersByPressure); + sheet.Cell(row, axialLoadColumn).SetCellValue(drillingBySetpoints.MetersByLoad); + sheet.Cell(row, topDriveTorqueColumn).SetCellValue(drillingBySetpoints.MetersByTorque); + sheet.Cell(row, speedLimitColumn).SetCellValue(drillingBySetpoints.MetersBySpeed); } private static void FillSubsystemsStat(IXLWorksheet sheet, int idSection, diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs index 49b7d1fa..59626c04 100644 --- a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs +++ b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs @@ -35,13 +35,15 @@ public class WellReportService : IWellReportService private IEnumerable factWellOperations; private IEnumerable planWellOperations; - public WellReportService(IWellService wellService, IWellOperationService wellOperationService, - IWellContactService wellContactService, IProcessMapReportDrillingService processMapReportDrillingService, - ISubsystemService subsystemService, ITrajectoryRepository trajectoryPlanRepository, + public WellReportService(IWellService wellService, + IWellOperationService wellOperationService, + IWellContactService wellContactService, + IProcessMapReportDrillingService processMapReportDrillingService, + ISubsystemService subsystemService, + ITrajectoryRepository trajectoryPlanRepository, ITrajectoryRepository trajectoryFactRepository, IChangeLogRepository processMapPlanRotorRepository, - IScheduleRepository scheduleRepository, IEnumerable factWellOperations, - IEnumerable planWellOperations) + IScheduleRepository scheduleRepository) { this.wellService = wellService; this.wellOperationService = wellOperationService; @@ -52,8 +54,6 @@ public class WellReportService : IWellReportService this.trajectoryFactRepository = trajectoryFactRepository; this.processMapPlanRotorRepository = processMapPlanRotorRepository; this.scheduleRepository = scheduleRepository; - this.factWellOperations = factWellOperations; - this.planWellOperations = planWellOperations; } public async Task GetAsync(int idWell, CancellationToken token) @@ -194,10 +194,10 @@ public class WellReportService : IWellReportService if (processMapReportBySection.TryGetValue(group.Key, out var processMapReport)) sectionReport.DrillingBySetpoints = new DrillingBySetpointsDto { - Pressure = processMapReport.Sum(x => x.DeltaDepth * x.PressureDiff.SetpointUsage / 100), - AxialLoad = processMapReport.Sum(x => x.DeltaDepth * x.AxialLoad.SetpointUsage / 100), - TopDriveTorque = processMapReport.Sum(x => x.DeltaDepth * x.TopDriveTorque.SetpointUsage / 100), - SpeedLimit = processMapReport.Sum(x => x.DeltaDepth * x.SpeedLimit.SetpointUsage / 100) + MetersByPressure = processMapReport.Sum(x => x.DeltaDepth * x.PressureDiff.SetpointUsage / 100), + MetersByLoad = processMapReport.Sum(x => x.DeltaDepth * x.AxialLoad.SetpointUsage / 100), + MetersByTorque = processMapReport.Sum(x => x.DeltaDepth * x.TopDriveTorque.SetpointUsage / 100), + MetersBySpeed = processMapReport.Sum(x => x.DeltaDepth * x.SpeedLimit.SetpointUsage / 100) }; sectionReports.Add(sectionReport); From 7d172129e654e0df7d3234b52d919d72582976f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 2 Sep 2024 18:42:47 +0500 Subject: [PATCH 08/13] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=81=D0=BE?= =?UTF-8?q?=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D1=83=20=D0=BE=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WellOperationService/WellOperationService.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs index 17665e8c..750e99db 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs @@ -161,7 +161,7 @@ public class WellOperationService : IWellOperationService var groupedByWellAndTypeDtos = wellOperationsBaseDtos .GroupBy(e => new { e.IdWell, e.IdType }); - var result = new List(); + var wellOperations = new List(); var count = 0; foreach (var wellOperationsWithTypeDto in groupedByWellAndTypeDtos) { @@ -179,8 +179,6 @@ public class WellOperationService : IWellOperationService if (request.Take != null) filteredWellOperations = filteredWellOperations.Take((int)request.Take); - var timezoneOffset = wellService.GetTimezone(wellOperationsWithTypeDto.Key.IdWell).Offset; - var dtos = filteredWellOperations .Select(dto => { @@ -192,8 +190,13 @@ public class WellOperationService : IWellOperationService return newDto; }); - result.AddRange(dtos); + wellOperations.AddRange(dtos); } + + var result = + request.SortFields?.Any() is true ? + wellOperations.AsQueryable().SortBy(request.SortFields) : + wellOperations.AsQueryable().OrderBy(e => e.DateStart); return (result, count); } @@ -308,10 +311,6 @@ public class WellOperationService : IWellOperationService var leDateUtc = request.LeDate.Value.UtcDateTime; dtos = dtos.Where(e => e.DateStart <= leDateUtc); } - if (request.SortFields?.Any() is true) - dtos = dtos.AsQueryable().SortBy(request.SortFields); - else - dtos = dtos.AsQueryable().OrderBy(e => e.DateStart); return dtos; } From 0adf95c37017cfcab5febb214b8143bf8f482ab6 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Tue, 3 Sep 2024 10:47:41 +0500 Subject: [PATCH 09/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B1=D0=B0=D0=B3=D0=BE=D0=B2=20=D0=BF=D0=BE=20=D1=80=D1=82?= =?UTF-8?q?=D0=BA:=20-=20=D0=B2=20=D1=8D=D0=BA=D1=81=D0=B5=D0=BB=D1=8C=20?= =?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB=D0=B5=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=B0=D0=B2=D1=82=D0=BE/=D1=80=D1=83?= =?UTF-8?q?=D1=87=D0=BD=D0=BE=D0=B9=20=D0=BF=D1=80=D0=BE=D0=BC=D0=B0=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=D0=BC=D0=B8=200/1=20-=20?= =?UTF-8?q?=D0=B2=20=D1=8D=D0=BA=D1=81=D0=B5=D0=BB=D1=8C=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=B5=20"=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=83=D0=B3=D0=BB=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BE=D1=81=D1=86=D0=B8=D0=BB=D0=BB=D1=8F=D1=86=D0=B8=D0=B8?= =?UTF-8?q?"=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D1=88=D0=B0=D0=BF=D0=BA=D0=B0=20-=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D1=81=D0=BA=D1=80=D0=B8?= =?UTF-8?q?=D0=BF=D1=82=20=D0=BF=D0=BE=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8E=20=D1=81=D0=B8=D0=BA=D0=B2=D0=B5?= =?UTF-8?q?=D0=BD=D1=81=D0=BE=D0=B2=20=D0=B2=20readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudDb/Readme.md | 9 ++++++++- ...ProcessMapPlanOscillationAnglesTemplate.cs | 2 +- .../Templates/ProcessMapPlanOscillation.xlsx | Bin 31484 -> 31474 bytes .../ProcessMapPlanOscillationAngles.xlsx | Bin 33771 -> 33748 bytes 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/AsbCloudDb/Readme.md b/AsbCloudDb/Readme.md index 0ad34426..88f964f4 100644 --- a/AsbCloudDb/Readme.md +++ b/AsbCloudDb/Readme.md @@ -64,4 +64,11 @@ pg_restore -Fc -d postgres -U postgres -W dump_2022-01-11.bak Then 'exit restore mode' psql: ``` SELECT timescaledb_post_restore(); - ``` \ No newline at end of file + ``` + +# SEQUENCES +Обновление Sequence (на примере t_process_map_plan_rotor): + + ``` + SELECT setval('t_process_map_plan_rotor_id_seq', (select max(id) from t_process_map_plan_rotor), true); +``` \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/ExcelServices/Templates/ProcessMapPlanTemplates/ProcessMapPlanOscillationAnglesTemplate.cs b/AsbCloudInfrastructure/Services/ExcelServices/Templates/ProcessMapPlanTemplates/ProcessMapPlanOscillationAnglesTemplate.cs index be5cfec0..92cf3d0e 100644 --- a/AsbCloudInfrastructure/Services/ExcelServices/Templates/ProcessMapPlanTemplates/ProcessMapPlanOscillationAnglesTemplate.cs +++ b/AsbCloudInfrastructure/Services/ExcelServices/Templates/ProcessMapPlanTemplates/ProcessMapPlanOscillationAnglesTemplate.cs @@ -8,7 +8,7 @@ public class ProcessMapPlanOscillationAnglesTemplate : ITemplateParameters { public string SheetName => "Определение углов осцилляции"; - public int HeaderRowsCount => 3; + public int HeaderRowsCount => 2; public string FileName => "ProcessMapPlanOscillationAngles.xlsx"; diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Templates/ProcessMapPlanOscillation.xlsx b/AsbCloudInfrastructure/Services/ProcessMapPlan/Templates/ProcessMapPlanOscillation.xlsx index b193887ae8fe5be42faf807e9697e043a40c9ef2..d4b53fab5c7b7e9db2116e34c14b1a9c9bc75b94 100644 GIT binary patch literal 31474 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 T3*q2c5B|Lak$@!qS^xV#V#HRU diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Templates/ProcessMapPlanOscillationAngles.xlsx b/AsbCloudInfrastructure/Services/ProcessMapPlan/Templates/ProcessMapPlanOscillationAngles.xlsx index 329320444607a37b3c7bc11caa2cbcadd78e9666..772391bb8987f3d21468ebc68dd0e0d927f25070 100644 GIT binary patch literal 33748 zcmeIb2Ut_vwl)lC6p4rhL9t-Lh6WJ9MpeXuA_#g z<-$Dt{QNxYk-M(({C0qWbELhgm4mbtCrx_(@p6I8>iaa0N0M~;HdX#Nv4l(K2|MMs z=S$dZ!9RRgcxQb2%!c)=pQIH$we!NTZp5@-vN_Z)v-hIWL+G`Ke8jyb=(xf%mYtjQ z(ek%m#p{lr)3H^Pv=7kInEcvxs`R~wW1xn>_X*95)x7;C!#8=9RQ>D?p)Rtln-BW# zUK@VA-p*YAZ6juR-d#;=l)TLa@vZL4N4jCVf_6H8*0}V}GwyiadO_3s0&eZ5=$x_+ zTJW09t7Xn>t_$7SH}YAeHtXrm`QWmFmoGQu=JeU$zA?F?Ja7G78FNPu&E4qpmqwyC zZaae1@P|jvmGy1VzPOVAUYK0i2tYyw9}kcApVA}*YxcQy)$Q4@x{AFZ{^9x8{P`C0tkT$%^QUQwhU9`5}4KByVu#g6wMBhKFm zDk|K0=M4!VecC@8ve9Gry*HjJ`p+iC5xqWF%g` zt-Uu^wI<-|4cSY^Nd~yDeVIPn%=bz-VIVu6zNt2{)7}~H&Onp~AAM2yR@+gQ=i9+u za^Iwmr=56>-gaF`jvdV2O0L9>+cH`^Cw7x7aN%Qqa|iEd&BO$CJgqDix0~Ke-i&Ol zcDgQj*m=F4wqn(?vVYUEnYd_ zm(CW#J&Mo>u{w;fL z50*#Z@6}6ldbj_<&j;TCJ=+2Fk9xP@Lhp8Pbh9#b;Ph=O9AVomvkBdSOPM3>RgE4x z^Wo&)SmGs$M$CoU?U%YG^tUP4UjolhrJJmO&I73mDHAqYFOCWA*^SAp&BZABA8;+) zwI@6$#p$}5_p1{0r_-YC0q4Y3P6cWddY(B^AQj#tY$T*Sse2-hA@%7h-$tJpsmJdx zDI@d;)sLSY0BOnSD)EXQex7jP^g+$#XT1_4Zdl^23Fbu)WR8DNw@`d!Dxj!rT62%e z$JaO325WU+vwUxBAoEe_v9Bqr!f@0R0@MWYc~OajLaI32m4>~kMAw&IIKHe738lCzm&X2EH!c@>{Z`DS!tNb$&!C(nT<4UW7A8)*ROY>#a z9(}Zh1i#0oiFF5ZLoQu7wM=_N$yjCI=5@%N7l)FrY3r664c0Zo;y{(T+NRlwddi3j zze|Lj={{fE@svP|&vG}#WCdTLKOc|KZ9WiDe<9WG@*_=VaHGMtSC65}q}K(W16w-= zsUAW*MXum=b%R zKAI9Ma!xEY+3(y3ZaQ2#epfW@`Hc#jj-K+Ij<2z2)A3=~{K;=ZSVxR3Ccgrd{7%J<5kMMbR_;g90Q%F2B2kU8V{&773nlVvZ{F{giczxS&<$tdTeI`?kE9)yNb*B`0|2;VtkreQKNfD0PVP zTJGiKN!zl#7fIRt+ttPM5OZ=J8crR!yHy)DL{p`GL+aaFni8e;-+p1n51&Dqz0i@* zIT|-;Q}3ejErt*uZ!WQVCh-gQ=%!tHP?hy+QlZeD%AaqvJY%DB6J1z90669uj(6oC<(;<({ik0dt#QXh6FShA9 z$9-15syp{t^0h%5j&N+Rv$>=bf)e882wo%NAj(b;JA{RUr(Pc_-zzgd!5|yC;@=8)Y;iI&@$AO`M*j;_sl_D6rFKehP^_;R~PpUkOQNCL@ zLw)i={f+v}q4Fts!``xT6NiICYIk)GO*kbbtq9Uem}eB9C-K7(l;*_ zi?7mOV{`RVAr&piUmZ{NFBC(;-^_xkwveQU2qlx*TRUS0j+NVs}L$rk=j!RikuIH%kB zjfJW|sBlhq@^`MS{-Dk|mEbpCU;W`C=X4)`=Z2eg`zqc%b$#s1bN1BPC*6kz6)&HP zCM!HXS#+(=Ezy@x|J2ze&Q+sRytp0TjZXdZC(%GDB~I}_oP3PNSe~W}42}t`a0RLV zr4u!}Kp(gG?r)t{ZlMj3N>wGKPHhr^s{C}HDo$HrcnNwDsQ+8^^-f_e}kgzp^u=U&j z#pS)vmCe=W_G*0w9k4h|G^oXq8<3~oBdN#}&jPY32- zdGORYbiK|U_Vr8rI(IoGXHU$Zdu-TFN5orsKYy{eh>Gk>GYR!SospC9)KDrRQ?&G` z+0|pzRHtH@S#_HLwU`h0M5Lv+p4F0;bNsGH862vR*LjtA#zrB3t8I=#<~P?9_6`Om z8VQ3JGEd^9)v@)a@Q)}SN^ zJ>=gu@TTEjTZV#NlEJi&O$+W|wb5&6SetIhwfCqC4(l9sEJ9$-{J4p378>D&gu=Jd zPxtOi(h#`P5So@sw03W?dXLtx6EZYaG2{=RC_WWV!w!#RuMk&*CL8eXHN_i*J<6I* z(3w9>xz5NvglXR@K3in)qPNPdNb%#olD^vyj;|JfsulFAR?Q^3NQJXLv)+Dmg0JM^ zF*yH^)@R`#e)g^F_NF&=9qlb_%(?D%Oz20OTGh4pX^KUb0sNN7s&php`Ews5#cApUGcSUp4|a#z+BAkg{IG@Yd#j_jGD?X^E_iim{zJb|_xbEOe4u9~q38T7+2FG^ zz4LP0M&K`or`5lgJ#pQ?D{o@g<loznDqV1BetGrP4c~-M?weZUa=*pr#NkyT)qE>EvmK3AKra}Up=Vz;}z zMM{WNpI-0(UGky2Tv*{QclI`a`TGa2-e|H%i@eh9606A-5R5N$mwUhdU~QmA;uSSX zCmq)I`TLKT-8b-zF0eJ*zWa!#MCBLD^-dc4K_8B!g`J5Aq)5E&*^t<*Lw3$^&b_bd zm<@a~flmhT88`6Ta_wPny;IF$s-`Ega=#mRtK)-KqaJPeq&nqo~?I1rITHqbCTVjjJ zDRpHU+({Z*c0Z$9Vde2cDuCaQ7PgZuygxTc%`3@;LZB&G7Spv?(CR+W_B>={i%IJ)6S}f zp}k45dzLltj%{{cajOLy?d*3KbG?KlzRl*X$E(AiAM%&mzYIK5UE_VD6DuXVa&mw% z`+Usy+4S(b-iFS&kY440!SJtBDrI&3H*KU&Zn9lP*!L#Sv~1>3ONT7>tT@$($;%nE zw|i3tnt}SK{ll%FbwG}rwkF#4wznOmO>FH=Io`Cj4nnJ7hp-nNCYP5r`BwKr%O1<= zZ|mP7BZ{#}Y~)NJGA@1f9fk9K>_x7vurJA#`Iib10#9$n#iByaE`LA9*t zP@bBPlb#*?n1DdWO8?kiXocMMCqAOJw`4AR3wj2o-5uadil|*~QdYks{z;yin;m7- zg$TdcPhn}|aNf&3uD*MYm&U)#2Ctra`C!en@F&l5<(F>S;Lr;@RL)r0!53>xn)eqoCc~pmWXZ9pm{RujR6< zJ%iiROX7-FhggIg`Hi7B#rfYnZL?Q`Fh3j?xpFc>(CQ2wTAFBk^3zCt=KSo6zWdM4 zcB1wf2rfe(VxyzRML8`Jxb1AFE-w$yqkq^UYkzN%>$h)n8YJQw0ob?{zV8ybEA8qQ z1)KAyd$UiUzI0yZ?kADW%xrlLtAj^l&>pS&84)LHa|W1|_aH7kf!5arikn0>o;bDn z>OgSnkO2UH(j}w4 zgL7OmA5BjC2mxf~0-ryh05<$iriqh-qpdZU&x%xmPcp*yy4vFSn_Bc%KC8*_Kdzuh z4{Xomb+G-c>5ulwgC2b0^*^)&bs|pKGN!SjQ!w;|iPUa&Tb)Qd9l56!pI!}j^9G&Nqg-ja zw_#?N=ZTrILHYTMYi@SX811$@J*?k(nYVE3)m6{q9ST@I27LZ;y%1`)Hjbt?jz~SX z+oleNoO%^O%e8=dktbk>h++8rkDJmzehhf`{DHY{OIA{v*Lw&*n@Ekl+qry|e`MGc zv7^Mp!#aHcUjIcPaRa>f)?L5-yhU=N316!x=9G!2YrpJxZM!;K;+tgXyHXDa%?BnM z&kv>?jXwRpN?%7@+4{n2Q!t!wvyfltU5nmRGj-?I$bGSS6J6H4&t)j3ZE(eL4V&h? z{UN(8FF`g z@`bGh$zMpeCQl?th%=y-`69zmK>ssX@sHZ-PxdVia~dqK4G|REU>Do(z!q3u;rBfx zN47x{^kr3mgjs2AB0cov{z;H9G?n z$FSG2hKDefC9d?A4lma0EX>%*F$`mz3hVGraF`%+QBX@D?t!E^Q2YS7M%5W6O=_+$96(!7YhYE5~T!q~|0Z>A)W%M9f zbA$l43lcNgQb}e^QyVbzBkBF3Gg$yfQ}7Q+?%3 z40`U1G=|00Vh>PN^5&<>^DF{=ZkkMD68cBGwnbs)gT$4GfgDZ!mAE=4Zsr}XgEcKG z&c+Q@vb=~*4Nu7!0H!A!hkv#O7gJ?NEWch)R>6rjbE5#3S5n4PHfnxBE$ zMh#^l*2=VN%QdJXtJO7gf|2 zGeK>s^qTX+F#T-Ft}F@mC=SW$AxIl3=bHmL2gFH?>G{ynwkyh$D$1B5phsZo{jBa8 zH4<~4sWsMbOJ;P>A7hT4BfGIPF;jD6Xv|zS+m$|2hGCS)Ar+%6smD}iftG6{kdtWv zvqM_!sWx$vLfHgPS)Bcjju~f-wGr4XWgnun)|4VHu2fT2Vtl z&t+5QEWZR4&}q!-W9&*7Tp1JT>DJbc`7X|;3rSbtNKB=vx##TL{{0Gb$SBM-l@>{s zoq5G{8}}IQ)v3f?B%v`={m9HHBKsbDY|hv7e1|x#jULCEYEdE0ch6AC%tv0WktzlB zj;?(|$b6txJnL;qOgeoftGgC3pS5SM%XGe6oHR4t7OLWD+JTAeK(m_6ZOQI#{^FQN zH0A!#C|217Y-TPh3NzJ)@tUBLz397?qL@sf-OPD6R==0>eAmP(Pg4J#5w^FM8-@}5 zS~-UOwURxjH8WWd=lK@+)n=PZLw=>PQ<(!gE|r_MDd@C(zyo(AMKR_6!k*OI&8Kw2srr_FfEAc{p^GOkP9w z+Qyo7V!UqXvPJrlJ+`q}=emOW8)kZoUPQU3MzQ6>F+)WoUK=uTnR&Tgm}mBC9#h@* zS)(Oc4F6e?ehSvGqg$C&gkzNltYi0;d~WDyMSd9yMH-Rka0NI(C7{30iP6%~MKkgv zhxYY041@wzK0T}@&8B}ueu~0~S46S)W5h=;GRkNLwNb2ZBrkv0d6Aiub0H+J>yuO9 ziIa1Hg+qXafClt7)`%0s!`kTOysq@)`4;J~>;?=!tpQg?zfPQ~1y875!?>Gz?Z?c{ zvqDvZRobRtF=r0U^o-vIZ6Wy*NxmTmujX)*(+93-z+FJ%BwsSgH}s%u4maUkb$7XU z#Pi<7tU#PWSMb4b`+K^{+8V*n;|QO&kv^f(_Yldq%Qo8Ne1gFC@6q_uV%TND5YWQm zM)i^xe>nNI+BVj|?mCjkz8m1ecr(XXD_#>IHMVp9yD)HKb49leNf*11HDi+>@|~2<%8j*xOhG>ZCz!i$lm*&fu(plUH)C3T#`n zyt-yivtVxQx$lw(9Vwf02iF)nJxIHS)``bv0QSTf#>f&iViJL`KP5E)Y_M}k>7-;x+Cs(!37}o4 z87f(e)hk_80Z5V#SZY}Ot&|T=N>b7^@X0z!SiK=hO0EXS@)l?UV0jtm>rV;Ca%))p zWtR_>TgOd1MjU;ZRGn_-3CnfP|z}H0yP`8?9sAVm-u5=;ef`rrR zC|JBEPUqmF3P8eX^`t*n&d`#fh+p@Oy6!7}!#C=NuegbCl!>qSO<-94lbZfHGqrF! z(%8Bo$*EioVzLg7YbMb!MwzHVOa#9ElyG|6q;tsZq~uiELdFFNhl3XAAizP{q6$F5 z;lLIa|4%As2sJiDrTB@b`bDMsiKqERrTK}c`$eVy^P2v9Gu>lh0|&5^bx`*~NhPO{ zNbbNL&%jPz!qw>N55)fxak{4kY~YnqOk84(E^JZ6={dE@HAjdVTGwLYk{3mso)c#n zW9}XjnWmv-xG3T@x)wpBa#B*sl!NzEWC6^`kJAKH2zIjmmk4O$@l5RGWn2wHe<10Xh{KUJY#_oYCM&T90b3MtIBH3*Q6OsA zUgO~X6mdApGK_I?4{1;PVG38o;mDStL7S8$n*Op90poDg?i|uSRuWX-AM|ONM%SvC z(FZ!NXAda87mn0v{&NT|pl;80{w-OwxHq_wr0c! zX=<0$sP=p_A6z*T=CT=+!g@V>bN<-qt@&e4SW<=`A-{GC1->=YXw+spw~A>yxO=)I z|HyPlT{WP0gfE~82Z`=A@o)+qJ4YqQS2kmo3AJE!8-^}=WP=rL$(akFvB!p8qQ<5S z2Ops=gk0hkrel;^W2CPAP}>Elt)+M5_s~1)l$ac~TAhn(<3`Ex0bQ77m0cKJKPp%4 zqn~Pv#Y=#?1ORmjWNR8`bL(=6wOAJ^_Ul<=*0Ir>tYc1t+`1IZEY#)jg&q&l*8RTk z&OhCC^3m}APw&nL%pOp-Y!Bd5eYE_*uJ@kzcP~8K zs~#@wrlZ2Eku*jm47MAlxQGt7fjnG3wkQ4Mfe6kN?$UXGahN{9-J4qLl&3b#)+wrhSi-z|658udsjt|$Q}4a@{BkvUnl|ql_4OOC=-s@s?yS1l zMms&?IehV{1gLrfNP@x_WXY?6SB>!%sj{Dvp@@aX>&L{4H0ptGCxA{;_#y@1s$~=~ z6czpfPWb@$)`Ms#h{!;};gYv_Auugyk{#9(nrP{xkN3vHJE0IBY&0mtfOrjGT%7== zB!H|ad|8&f26)wEE`TdVtO2Xvixpu&!8}-yFNN74#b7D=rYR!FuYz|Zg4Wmb34l2ip{}CB3*eLj zIL{5p+EkIitKdtAxHY(uWG9M(ZbJDy#(NjTjZGl=sa${ne6dd=^j;$9Og-Oj6z_Aq z>K876cD-0=ntn{0$kl7$ltd7`o==Jk;C~Gj{uNI73imdHXs3&$Tm!dq0kq7M>=aN? zMU+n@-n$asX%6AZ-~znC7q3f#ZcG9_uID?4;(d=-t>FT^tQTv@(C^ImJSa#YUZe^Rwt{eLfJ(AMqM*hopA@`zBiz^uqMFGCNXHkyNrJ{C zf$Hk{P$=F^ylM*$H!rS4LcDT1Kq$*2f6ak*& z0%+Y%vb%$V-bML*!h3hYJ8wh0v$+68_~OIKQ2Aug)&{-+6z^xe>NhUH{su8vj=pJ* zNVWmkI2k0{z!$~^7&1VG_rodua2`j<+FX&fhTz9i+!{D0*~OutA5cDZc<({Du@fXe zmkZErQqI~-B-V^XnHwX`r3ow8$zJh~7aiGKoz6KQUFkW?< z3y|F));+LJa{-w6;w~Jt7YCYb;A5hAS$I`87l5ZxOf+AAPrk?|WANG(kU%5fiq)KM zdeIma&WE7zA-sJcRrw;fjlqgC+#2{M*=?|b3S0RIWO{=ToxTw7k6Zx3%woF~s8b3^ zv5`;Qig#_MD*qkMRB^sh4E9Oi^pnW(>)_}VkWM3?Bo_d69Tg5nP{0VD`;fH-B7xVz zU%3F4_mk|7SwW9m`E1SfUV||9gX9-*0mL(lc~haFRM6cLDNF?P3*x)d?2L4HQ2rH<8m5)@Ww6l*Bf?=2Q_H38?Rg1Q^|?709~6IA#% z1Z5k7Cjb&yB2r}n9_9j61|->Gtf1b*YVLX9VMCeEM$H9=#xy>)Y0kRmNz;F5#jBo~ zzYF303{v%(1FdvEvsgV1dLa$8w}~&<%10y9dk+^{wn;4Ri$4B~NaszkV;V@Yi7$!^ zy}=aKx*xIe03tdVVq7Y6+!P!w%c+}fNRnNm6*S3;7nYfS5W({TvbKy10M9I@q(Pg~ zKsHT$*;YOVnch-d0QV-b{xbckG7%m#@bYxf-6p;QF2E5pRO?~HMp?v;SCHthB3I48 zGDkQ7v{y-XRaVeyD_)Dtd^v=77(~0A3t*L5Y?=Yrz#QETVRO{kZ>~}Sdi0!9d4mo z)esxcAa=Zk?5Gxbc?+y9$F0HJB)d)4(9PDoPcrk*BD~*0s;apFftkhkGN2DLKxdoz zB&>a&XL?`Y0_Zf0#ntHJYebAKz!@1JgJwQyE!0m7Qa`s?(k>O{OP z!DsNG_sx8|T!3^-R4Wv*Q6I4b3yG$PG+Kgh%X4dh{gRE_OMz_|r7ZW9=S6Df!vH-x z?nupIw0t}%%p1426T6CG$wv|c+_V~|rR)gy!qj43pcr6Ia62r>4yl>2m=`Fv0umiF zNeX++wA4W_=v{ySKx62Xo2{^*!3Dhw5U0Sm4iIsBdq`n=92aOL6%K^Z0+0 zz}g7l=@DNd!I&o1NWgH zEuTaR^Tow>Vh=DZ1-QOaGt=_q2-ae1F)vUI@RjP?VYPs-gk8)F6yx|x)1)B+TWRopY8o`*oI4{b4KL9dgLszzQp?C%+K+a{+(8dKlhb>t~LMpOW)D} z{vQrtsvXiAhP1we%lrsy>BL%dy`NShF0%xUH$>wFNzE&MNI4rmX4a+G1Y z#dAT**|=(BT6(m?S|~qMaHX7$D;FB}?+WlQaheuM1sDMwypeWTOAo0z`4_1G<$#}< zhs5iE6((=IH=fQ%AGXpl6puh4i zLvl8mhS2g`=#<3S1-%Opz|;t*VVkmXW|SX#xe$PBSL2Q>2ks?eIX3(>hvR9~GcAvf zV6RPaZ1`yous@d34*N@{qt6Su@FJ-(^9(7j@!aRafcxV}>cXA#QOd%db6?!gJLi8Y zNzPq-b_#fm>gO|N99@f~{f&wE+1~$#ZMbAQcSQb+N6r%KORO)>{G3}6|4ysKpFgzm zbFKN$U;35?@c(cCPXN9W7T4E_J;AVCLki>Wki^hQVSul1gqB~4EdK~|7^Q6G`btDP z#j_PQF}Ro)C^$SmHwSpi9h$1ey%nD`Agr@0RA5iUaICzRgoO3Z6uZvzJ6`&mO6UQe>&A>D9m!}p<1sa5NyR?>R zY2FG`pm5sdC*_t;||!;ux)@l0Nfnos#uT$(_kLpZ~RRGfM*g%_(;tc znPY|vF3{qQ@;|?Y{wEScC(i47Ki}M|2i&PeT|Y?$7y&l*+&qv};Gz7i*+o(TzBq0z z6^&OI!L|)9k_u4Haci^alo7zK#d6wZk#fMTZEuGW0KXZytG@)WL=k7yE%lfsX~3f%oPXKFdFiiYdQhszV`(D)^QCBpt?z;8L|=4$@Vcq(mq5{8I>9V(Nsqx`EX+uUX;p-cN8Ce zvf?zwJ{$MK0}1iRy(of}bz@D(DDO8~$OoYDTSu_H?LRK1F)Xin%3G+z%T16FKc;04 zox;6@KSY9yAT{C7^d}l&WnCmV@SHOD(t^Gq{r8mr7zlnk*;>(l{P%l?b&=X!;+cwDs*(-W{^&}F#YQXeXwTG3)Q#BlMHyd{~>(++cof# z!T(Ar^-jX7K{|r(Sn5vsF&bA7vId{Il7Pf+0K?-{@Ev5SHZq@3k*mU zP6LTf%Tq;bLGXK2^Ru|5>ppWD3ga2_hXU7HoLzI~%#OUA_ z$;%*Zb88k8aUFB#%16gXoxfS2u6BYNsh?}>Q}Qo{w{UfeuFKl3g(%>YuC-oJz`uZ* zSC_G%;IR3E0{bsN6g>Q)fVE(NCr-|HyFMY9Yg|j=5huQy3aiYVlpOzO}@r!7b@+OAaV|Mulm03lVnfcvC0V?H~(XZm&WEF-v ztwJB$Huh!YTT^Womin49L7AB$^pe>#H(Z=jJMOrr7!pajQ?&2cAuuzH<#f_L^1XQ6 zJJEV%?7JJp*mv&p6DkDEiOR@GDd|z%zW$-!j-m3RwjpMB&~(6>%N3Q!Xk=xT9LB)( zvD9XpV=XjiawLv4ck>mt%+y^9))Lfa_G(fbMxbLUMf+CLDvr_uvR;?ncn_$ z(&EYk%=Ge^!GNfVv8e6nn?i7*fWd;5ZAmN=)68ki%w@Vn%fqR%_S|%~^cta346A|O z!^C?zxlU3FkV7-GZ6jR{tO@biXfpey=2a1D8Flsso!VRe2%UNIgdsA|&4u3FVbu`V zamZFjhlFS&K8du>9O^hKN(h?h$NINfda&0xkCs^y5adC&u^TPhAaX`}U(2x})6NOX zP;Z>ltYgzR&V+R+T{wV@$XA%_9_twz+G1pT zRDu0Y$V5tduD|R~Sx|2Sy=^wj)C^}+Xk^qqI7mgiZSf+uqscSZ(YXqUPky$x9l4=2 zoL6C1%TTpeC~|^sj`g<2a@XYu)FUy&&%uA{mkLW*#1!85#1s z1L+`jSYdM8V-=a)@K7_)*eu8`9v=DFdexCKnUDxh~$%TyoVWTR5 z_+nt-_kTSWg5Yrj-~F-R?{UHRd8Y#nJV%_)p|L*5r3!Yn9 zpJSo@u~6+p`)AD5h0K{V2a@5VIFYAqq%~91$+y&MhEDeu&-{G`*rT@0HUkJPTXnC9 z#Afq_g1e5_ew$ad=eBu&RG`U&3$P2Bjv?>&{A3x&rpl$a@1X8n+G}=2;#P3mvG-w8 zY{M9PPbfmPvJd~FlfL*x@x3egp4-|FtlIzai~Fx!N?8Q;;JQb($(wRcR$62vlqQ#B zl?9FaLWN8l!Q#cKz2+Hy%$CA2ARL_){)o7_Y4pwetf%zz0S9@lrG885_7jh~f7rJ$ zH~i7{)6ILs7?EqPxG{IXM7{MsI`)frr*2Mgz;~kG#|yD%bvkuko4J&4-f!Ep)KOkv zx4h%>M@AUS_|Cw0r@DErqVzJ4Q(Nm&m}5I{s}LqPJ{&20HKc1ZlX2a^_0%HD8@UdV-Fa@lfGNS6VWTI&Id$R5sH-jl5mAfJ(0h_5V^al!(2;3{GxII+p`@Z+rKl z=PvE@!&(`3U8_(=u?a|Cuw#eaz=uRq(EFPrGcWqE`<;k@klRar_PuFXW5<8zU$Zyx zdSFJ!{YPP&Waspo(b&mE77y#M+UMPp%Ej2;br`cIbZc_RXd4r>{%+rdzl-o~3Py$+|IK z{Vn>%hT;8bZyTQN#q=a0R_(vOqv0wJb7MVn(lIU4cfRYgF~{rjhM!LQUfYWS29oZs z-oM|r;T{fiWj%7talgFb736Ql(RQQUs2k{2ovu9Oit1HZ==k1O{9}3AyU72$gl9SrwvD4OLk(S4z$D}>qHPhnew3@9> zK&zd0_joK?QRb~Y0x#LTTlaI!(2T<~@jEjkbuVJ-ml|w51mE^CZRY2gT9Gk~l?r^? zR&9vfxGlK@@;T<bZQ?b2<;&9^wyE%4_T|4x4he#~v7`P!$mR+NElIoNVF zt*Y`qWKEEMs!?P5rO#gh{l!tbL)=;eO3l0V3f0W;-xA6{cOSHqYSXq$ddx^e-_r;^ z#Q-&-{FY`^`Dm4dTyN(oG;!#o%$QA#oVuF#ffKkcalxU6hNne}8n+95!H0)`Mt}R< zxogV`G<#!ZM&Lo_X6Z-u=h-sT@Yj|=xEE?$X?^`;mnRD=|Vb{CH?TtYP< z@_Q`twK!&X*5$}Bz2pvSFyK?uX`>JMPa@A=R)nmwb{X4p7Qm1D_clxZ!?sriHXB|cGs+t#seD9R6FY{~$j3z6qI=nWWkMN&gAfJ6`|Li%1 zd_mXo*${}EBLwn~59oZ7PQs7pvi46ar=Qi-4U3Hccjt>6bSYx=t#XIxrQORsuRX9W z{=EkgPhge#xL_WzZwv~to|VXqyjbmcL0Znf*f-E);=+cq?K z*w&k!IcV}_XQfO3zU8eXvtN8#*oU|GGL_1?$`f|niL@)bLK)ssaW^)c$vcfGe)yBEOfFJ~0cuVsh2>c;!8 zafv%J?*$_67HRF4N`d$6PG0Yl(xRGuFMKL-H`{A?5-^^=<;QGv)bW(4uYcSb5D0Y< zqG7sZ>qb2Lu{By|8vz^5!vg$ETix@!1m{x3W8`_dwaD7OA)a4=-ahpD`>jsT3f~^2 z2hUpMu;>(|5@Ki~`E=%V)Y5O^Qha0L35wyO($n0@&B-OM=?axXj*{1)agn1{0wG!U zIynaz>6Knb(;`Qu{lZd-{CbW`qDNCEspJfRh*ErS5!nGU=~!Jkd2FH|N0#Q~a24Yy z`6wWf(AvmjIIg0#Um&E6PR<}J1}*Fqtwf`CQ$oPh2@ei zMqN2cM&L@iX%v}^-~miZWJGCS4ecERt<2A{lYQ%V=BnnXl*y{w2_s#FT*Wu596;6g zfuJ1b_2+P9%8TSNX^lpt6OeH%B2|O236mByl@6t}jw=~(CUAK=xVnV$-?>tyvt4BA zsm>0{#A`x%_}E~wFjB0?4IfiGU=-%K$jQ-Rin7LPR5fVCR7_$O9eN@U6Up$)a_I-v zTcU(_Mkp7cgp4>< z1q=h+NYY20_GAmCgh=4N#c`E`L<7|K7Q&DL4v1h`1a(00W*Rai=D z;YP|vTJ03yxn=6)qm*6w7Q(jPQt3yoqD3rH=n7lM1T;l|GO83+-9md`NK}1q)oDek zopHi+qQL|Y;0Qzt@$gW&I%};uJvz9`Od5HTtsI%q!ChBO2?13$jVx1hex|QWoIHi1WAD5!y3Rj40>eQQ$lO&2w z8ds-yl4FHa3@1`l;gRCk-88OJ+JTi%9W7No#8DW6A|wRhE!DWPti8;~p7R=6wE?G^|J#166H+YbS{$Lvm#yqR3TU)o(!DQx6Y8~KOxQ!U-Y#JYA7tr8_SmJbZ}%ST?{RnaUi zh?8_cjiLe8t2;Uyj^Im1V?|M-6Z zv{PjD3Pyg z*@@5We$bY}xKZaK=%$aI=P8Q&AWRc{H7~H<(iYf-c74pKt#={z&>cc}YccBR87tEK zBI2_*?M1hyF|-?8^m^&kf{bS-XpYmVh(ssX^dso!pIuBt6P?`CE%zKS88l7obum4q zdHIJ$%}p<09LqpIzw^Tpv}n{DvX9*NNI!CXS^@wk`5riY)aidf{l6Cn{xbGV^z*we z^w31SdpZXFobRHEy*c~HBad{77Z1cR=T*Xu))%V>0bu`lM=%o2W@^ zy{J}eJ@r=rJA5g2COcAfQx45bFur`|&MOC}c9V4KuWOe9(oJPfxN1|%bH;djc0*E$ z6Ryux^BzpPkXZg}PD9cQ&A@+I)oH7_MkMZd{c>zWVWQ#1omj2%0Z za|4A}xls5@v#>@bqr?Nnj^$L0P5S+ymU#(*H{G1iOJsSrU($yfHIqZ%?W(Do3`rV^ z6>;g#LI9Q^1YE=eRg*z_VNf7I3u(~u$^8xOm5Q!@7BATmt8!VvHfX7I|9V)?f)$Yc zorz0<akm9;pm zy_)*_ns||WP}-cEt8Li(a(Dx=$c_GINp=a^~Sf|gPx4LW8$6h_WtU#aZgR2WJJDt@SrNgK6!OuT&W2()A8Zz;JEkC zY4(|2JQL5%w~tnb#eFw&)vcRh1_ES-A=-}V@Q zUX5F0`sCT$C#!G7Z881!EFu9PfAJV2?ik#W4*Qu0y@QW-f~gm{&x>wpew68S6q)-R z@%0!ygbv%Wq#)`pLyyk4KFp#YWJv zfgIlnKU*A;kB?7tVbERRjdWNbz=IayquoHl2;DLp&8$WvhZzXSarjII>=H;oXYs9l zSacs2nhhM8oeeVDABtkd)204rS3pSr85;)gAdY8xe*E38k2hE*`yy z2c5uckysUF7zhp|$nfzUXht6zKE;43c~FR7bQDNflx3Oi$*lH72IV5`Pr%n?!E_Ot zBnfi)*0C&lEDQ2G#?TvSn1{G`0t5iBF&*Z7`UXC9sh?IntKtnN$_FGE_{Gm~Wz2Jh zU(JI3!iTQ$i~bEHJkGK-KgD!9h0J|{@N|V2WWn4(f?ht~`aX+(p9T4VNj;79%tsWt zf`nR3#|1t;j1RT-)1t8|>M)SAAi%*d-U!10OfhhMChR63>gX5!6eMh9T4wt)t9_Bf z1&AmNd^Z#J6eOTod}{`a&R{|K7(+i~Dhttw0SN+3M>(Hf!H0VJY2~ph8ZlA+AmNN( zyaSfugoQt2!uWiszh5*P1iWNgng=qS0+AaE5kM*y{+S6I00~KjeCsk6y^IABVp0jn zuZ4&yEJ*l@>6j&;&k;Z``)O6OD%vrSb0FcmU%ZbS1Mdd6&W5cNKyUd)zXb`0vn{iO znbpC_pkhRY8~kK8Y>OVa48?rwIu^Z-1?j;Uh9C_~5P-frNa)3M92C$G382sYw0NwF zK1@_7NXYSvzv#}0bBDjphMg8b3;d#+K|*`Br8$x5L`3Ft5MSNlho}f=Drj6l7{S;sg#P$S@sk0{T}0 zbi_|f!m5yCq9Vat5c|bf;uzI9cux*&QUI0vMJqvoR<5Oa6u@+fLT;!)7<$5Wb7AxK zHCalk;9JAkbQl{l1DhI+{91ts^8^Vqu^m4*(v2ITOZ>Iq>_? zr)$XE-w~eP@GW_;haf@kHQ(BVO*dgfmS9ukke;s*McyC)f$d;7(u*3Q?*3X9>q z3%LOjeEj2$d>E!a@Oyc%+D7PE|L83sAurD|JDyn`j~sr3i1LB|o(KC563|tA>+Nj% zb~a=s)-VB?T7_uz0SN}!4rL=9(iA%$rq{^vyhYJGR?6V>o4`k88}p|oXq_9obhJIJ7Fg#9TEyUi5aaiWQiX@X|^N2A%0^;pBZ;LR2I$1_ebUYvq| zc>xP*f)@L0xr2a-7l37L60|7c$}#1fnO03+kQK?;t_JV77=v@B<#R;^fb}?nxK>Z(Ihs+4r@pQ z33C7V{xgixGjMr64AKnM3ebuM2}=qrYg3thsmQ2$gyUJbaRCgmOp~PUdVWzX+w>~i zemBsKn8t6RQQ5~gV>I+W_m<3 z)Gi>J#)cfi8a@L7y946Q@Qh7(_;MEPRx@;8fL6LCNU&sC);?$UJx4-#h^u(GBMX)R z63+1WMGUrS7Tf+f)}DdPQ0-&{9BvUUQ;$=`#kj@LcTK8cMX<}YL%SHRkm%g zN%JYZrV8^E#pFzC3d+B-P%XCW!9d;o5!)dsm9UGIpS@EpzS5qgPjO7pyrs&UHPv1t z=PScjQ$mVb^H-tDwbZTzs)Nf7s`inSJ_Zey>cq$zBguNhywo3cpOC{t|J7amwS_UH zuF|HHqb}H*f7GpN=*Oc9{Yef1x4 zrgxX7VApIn@Rtu#VSYP?r$x2LqNz7;1)s&EFWfNNbO(uw;94eEypm#!AygI*_6QciOXKF;|++q9e30*$$fne!2AP zg>C6@i`=?GLILil-`+J=rM4z2J&IP@Tn@9#9G!aAfujbU<57WgKGZ$I9ealwUY1_X zxgcCwdwmMu5LXb<_#k|)P&8TI?7r=xUXv(JZPV`BGs*eJSiwH+@k-1o%ej!G-3^Yk z7G4a$t;n9j$5ILBm(KR`>sm|Zw&ah5bk4}n4e{1mI%vM4_WA(vHJU@1J+@lrKEl(+ zZnkKbso(MEb)W!}vP?UxRXf~zvv{!m^FYVN;-;$E)cgdU(^cMiCz2Zv9vZI|Uw9iB zBP|oztvq;$D{HN)oZBbnBK#J&%#CY<3bmUK9OBMx(~K6rl!aOERQ%HD9pJrv=SNa| z%PP*?K4K*}8X0Dwv+kL25jN|9|2pG{qvY);t#$$m_Vlp6sH1)61lH#|>)PPV*Mm1( zZg))52H&3BUV7nsk?pbV!C%bNm)g`n!tcFF0s_=cho-mp?B1JLe9P@jrdRZp1KURn zEZ5h2`R+|&Ux8s(55E1x&$ZV{TM^#83~_c_fsr$|66zjv;k&QjiLb3v&qR0n{IEYyP3Y02L}^4nG7u+0z2&{HF!>G)@aR z=S&N%bDI|M$p0bWHux4$hgcy?ZwBvxxP~>YAep{}HkVJ+3WW4&g)@#nLb(1zVZo0O zW={*y9uq)xq;@GdVal~@+OhlGbc{5UfN2Nw7t;>go63K9eEK1ghoAO1_-sWuf7x9q zs;}YZ4!;HaqYY}$?oDA`Nv}v)Twqj(scfKbq%=_vQS^ZP+FoGtySR?JLoxNTqR>Z9 z=!hI0BD0zwJsdhnL&`3a(ZKey6Ba5Dg1HDM{FKm)+P1B%sF6H1`fYr) ziu3LS5Kx#rSjfSdAEyBYzw&sSY|)It-oX6#VjV_nEU#}gEsfZnth27=1Mgi|r4k*n zf?J~Ga$UxjUXC$QL%f~i~f$_8VFI8sB0D#;~t*Tn*eAC0uZd-T+c@$?mdB$0JGC@B2 zZlosGS=vrMpC|3;CXXjMt4``*3=9OZIwe?zk9eYQbZ|(XK%12QmWgWWh@6;uChrC) zDl(UEvC;q-85Tt3MHZ5#9;&37c0D50>BV>V$nc!ct_Thq}zblv+G2$Isj13TrJoln<*qn)erOsXPO-AQ^u1#yXyTuG# zR@-{i;HQKnF>i2?^!Dy1oNn~F^hIY~)H^ z<%--UWmx`!a3w)=n84+f$&lk&2;@}eO!b%dT2Nicf1SL%{9wz2A@z}hTJ=E#xca+% zz388(4_)qzwwdlkMqAC*9L)p|hfvF-ZKsD-(aW@asmo%Fez?ahgUT0C-D8XmG|qoM zzp&^}Cl(-(mDHy(hJeQB&u0o2{)11hE(CIt;BzRL5Om(cD=0{Fkl>#KZ|6gzlGL+C z)YsyFn5|gyr`bO06(j`wvj7;Q9W>>EpZYw5+pK?9;8DFVt~S)f_~+E={{tmjpZZvT P8MXZ4!dW`e8q5CyRHbyt From 84f0b2f3407192edf64a708868a9d3cae1db702c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 3 Sep 2024 11:52:10 +0500 Subject: [PATCH 10/13] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/WellReport/WellReportService.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs index 59626c04..aa2a318f 100644 --- a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs +++ b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs @@ -83,10 +83,10 @@ public class WellReportService : IWellReportService var planTrajectories = await trajectoryPlanRepository.GetAsync(idWell, token); var factTrajectories = await trajectoryFactRepository.GetAsync(idWell, token); - var factOperationsWithoutNpt = factWellOperations - .Where(x => x.NptHours == 0); + var factOperationsWithoutNpt = factWellOperations.Where(o => WellOperationCategory.NonProductiveTimeSubIds + .Any(x => x != o.IdCategory)); - return new WellReportDto + return new WellReportDto { Well = well, DateFrom = firstFactOperation?.DateStart, @@ -106,7 +106,7 @@ public class WellReportService : IWellReportService Plan = planTrajectories.Max(x => x.VerticalDepth), Fact = factTrajectories.Max(x => x.VerticalDepth) }, - WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.Day), + WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.NptHours) / 24, Contacts = contacts, SectionReports = sectionReports, DrillerReports = drillerReports, @@ -164,8 +164,8 @@ public class WellReportService : IWellReportService { Fact = new OperatingModeDto { - DepthStart = factWellOperations.Min(w => w.DepthStart), - DepthEnd = factWellOperations.Max(w => w.DepthEnd) + DepthStart = group.Min(w => w.DepthStart), + DepthEnd = group.Max(w => w.DepthEnd) } } }; From 1802cef9506752d9b947efa53538416932979e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 3 Sep 2024 15:59:05 +0500 Subject: [PATCH 11/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/WellReportServiceTest.cs | 335 ++++++++++++++++++ .../Services/WellReport/WellReportService.cs | 2 +- 2 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 AsbCloudInfrastructure.Tests/Services/WellReportServiceTest.cs diff --git a/AsbCloudInfrastructure.Tests/Services/WellReportServiceTest.cs b/AsbCloudInfrastructure.Tests/Services/WellReportServiceTest.cs new file mode 100644 index 00000000..2c3fe4c2 --- /dev/null +++ b/AsbCloudInfrastructure.Tests/Services/WellReportServiceTest.cs @@ -0,0 +1,335 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMaps.Operations; +using AsbCloudApp.Data.Trajectory; +using AsbCloudApp.Data.User; +using AsbCloudApp.Data.WellOperation; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudApp.Services.ProcessMaps.WellDrilling; +using AsbCloudInfrastructure.Services.WellReport; +using NSubstitute; +using System.Collections.Generic; +using System; +using System.Threading; +using Xunit; +using AsbCloudDb.Model; +using System.Linq; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Tests.Services; + +public class WellReportServiceTest +{ + private static readonly WellDto Well = new() + { + Caption = "Скважина №1", + Cluster = "Кластер A", + Deposit = "Месторождение Б", + Latitude = 55.7558, + Longitude = 37.6176, + Timezone = new SimpleTimezoneDto { Hours = 3 }, + WellType = "Разведочная", + IdWellType = 1, + IdCluster = 1001, + IdState = 1, + StartDate = DateTimeOffset.Now.AddMonths(-2), + LastTelemetryDate = DateTimeOffset.Now, + IdTelemetry = 12345, + }; + + private static readonly IEnumerable WellOperations = new[] + { + new WellOperationDto + { + Id = 1, + IdWell = 101, + IdWellSectionType = 1001, + IdType = 1, + IdCategory = 2001, + DepthStart = 1500, + DepthEnd = 1550, + DateStart = new DateTimeOffset(new DateTime(2024, 1, 13, 2, 0, 0)), + DurationHours = 48, + IdPlan = null, + IdParentCategory = 2001, + Day = 5 + }, + new WellOperationDto + { + Id = 4, + IdWell = 101, + IdWellSectionType = 1002, + IdType = 1, + IdCategory = 2001, + DepthStart = 1500, + DepthEnd = 1550, + DateStart = new DateTimeOffset(new DateTime(2024, 1, 10, 0, 0, 0)), + DurationHours = 48, + IdPlan = null, + IdParentCategory = 2001, + Day = 3 + }, + new WellOperationDto + { + Id = 2, + IdWell = 102, + IdWellSectionType = 1002, + IdType = 0, + IdCategory = 2002, + DepthStart = 2500, + DepthEnd = 2600, + DateStart = new DateTimeOffset(new DateTime(2024, 1, 10, 0, 0, 0)), + DurationHours = 72, + IdPlan = 1, + IdParentCategory = 3002, + Day = 3 + }, + new WellOperationDto + { + Id = 3, + IdWell = 103, + IdWellSectionType = 1003, + IdType = 0, + IdCategory = 2003, + DepthStart = 3500, + DepthEnd = 3600, + DateStart = new DateTimeOffset(new DateTime(2024, 1, 10, 1, 0, 0)), + DurationHours = 24, + IdPlan = 2, + IdParentCategory = 3003, + Day = 4 + } + }; + + private readonly IWellService wellService; + private readonly IWellOperationService wellOperationService; + private readonly IWellContactService wellContactService; + private readonly IProcessMapReportDrillingService processMapReportDrillingService; + private readonly ISubsystemService subsystemService; + + private readonly ITrajectoryRepository trajectoryPlanRepository; + private readonly ITrajectoryRepository trajectoryFactRepository; + + private readonly IChangeLogRepository + processMapPlanRotorRepository; + + private readonly IScheduleRepository scheduleRepository; + + private readonly WellReportService wellReportService; + + public WellReportServiceTest() + { + wellService = Substitute.For(); + wellOperationService = Substitute.For(); + wellContactService = Substitute.For(); + processMapReportDrillingService = Substitute.For(); + subsystemService = Substitute.For(); + trajectoryPlanRepository = Substitute.For>(); + trajectoryFactRepository = Substitute.For>(); + processMapPlanRotorRepository = + Substitute.For>(); + + scheduleRepository = Substitute.For(); + + wellService.GetOrDefaultAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(Well); + + wellOperationService + .GetAsync(Arg.Is(x => x.OperationType == WellOperation.IdOperationTypeFact), + Arg.Any()) + .Returns(WellOperations.Where(x => x.IdType == WellOperation.IdOperationTypeFact)); + + wellOperationService + .GetAsync(Arg.Is(x => x.OperationType == WellOperation.IdOperationTypePlan), + Arg.Any()) + .Returns(WellOperations.Where(x => x.IdType == WellOperation.IdOperationTypePlan)); + + wellReportService = new WellReportService(wellService, + wellOperationService, + wellContactService, + processMapReportDrillingService, + subsystemService, + trajectoryPlanRepository, + trajectoryFactRepository, + processMapPlanRotorRepository, + scheduleRepository); + } + + [Fact] + public async Task Returns_well_info_not_null() + { + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + Assert.NotNull(result.Well); + } + + [Fact] + public async Task Returns_contacts_not_empty() + { + //arrange + var contacts = new[] + { + new ContactDto() + { + Id = 1, + IdCompanyType = 2, + IdWell = 101, + FullName = "Ivan Petrov", + Email = "ivan.petrov@example.com", + Phone = "+7 (123) 456-78-90", + Position = "Chief Engineer", + Company = "test" + } + }; + + wellContactService.GetAllAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(contacts); + + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + Assert.Single(result.Contacts); + } + + [Fact] + public async Task Returns_valid_from_and_to_dates() + { + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + + var expectedDateFrom = new DateTimeOffset(new DateTime(2024, 1, 10, 0, 0, 0)); + var expectedDateTo = new DateTimeOffset(new DateTime(2024, 1, 11, 1, 0, 0)); + + Assert.Equal(expectedDateFrom, result.DateFrom); + Assert.Equal(expectedDateTo, result.DateTo); + } + + [Fact] + public async Task Returns_valid_days() + { + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + + Assert.Equal(4, result.Days.Plan); + Assert.Equal(5, result.Days.Fact); + } + + [Fact] + public async Task Returns_valid_vertical_depth() + { + //arrange + var planTrajectory = new TrajectoryGeoPlanDto + { + Id = 1, + IdWell = 123, + WellboreDepth = 1500.75, + ZenithAngle = 45.5, + AzimuthGeo = 120.0, + AzimuthMagnetic = 115.5, + VerticalDepth = 1480.3, + UpdateDate = DateTimeOffset.UtcNow, + IdUser = 42 + }; + + var factTrajectory = new TrajectoryGeoFactDto + { + Id = 1, + IdWell = 123, + WellboreDepth = 1500.75, + ZenithAngle = 45.5, + AzimuthGeo = 120.0, + AzimuthMagnetic = 115.5, + VerticalDepth = 1600, + UpdateDate = DateTimeOffset.UtcNow, + IdUser = 42 + }; + + trajectoryPlanRepository.GetAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(new[] { planTrajectory }); + + trajectoryFactRepository.GetAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(new[] { factTrajectory }); + + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + + Assert.Equal(result.VerticalDepth.Plan, 1480.3); + Assert.Equal(result.VerticalDepth.Fact, 1600); + } + + [Fact] + public async Task Returns_valid_without_ntp_days() + { + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + + Assert.Equal(4, result.WithoutNtpDays); + } + + + [Fact] + public async Task Returns_section_reports_not_empty() + { + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + Assert.Equal(2, result.SectionReports.Count()); + } + + [Fact] + public async Task Returns_driller_reports_not_empty() + { + //arrange + var schedules = new[] + { + new ScheduleDto + { + Id = 1, + IdDriller = 2001, + ShiftStart = new TimeDto(7), + ShiftEnd = new TimeDto(20), + DrillStart = new DateTimeOffset(2024, 9, 1, 7, 0, 0, TimeSpan.Zero), + DrillEnd = new DateTimeOffset(2024, 9, 1, 19, 0, 0, TimeSpan.Zero), + }, + new ScheduleDto + { + Id = 2, + IdDriller = 2002, + ShiftStart = new TimeDto(20), + ShiftEnd = new TimeDto(16), + DrillStart = new DateTimeOffset(2024, 9, 1, 7, 0, 0, TimeSpan.Zero), + DrillEnd = new DateTimeOffset(2024, 9, 1, 19, 0, 0, TimeSpan.Zero), + } + }; + + scheduleRepository.GetByIdWellAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(schedules); + + //act + var result = await wellReportService.GetAsync(1, CancellationToken.None); + + //assert + Assert.NotNull(result); + Assert.Equal(2, result.DrillerReports.Count()); + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs index aa2a318f..cf9ef0fe 100644 --- a/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs +++ b/AsbCloudInfrastructure/Services/WellReport/WellReportService.cs @@ -106,7 +106,7 @@ public class WellReportService : IWellReportService Plan = planTrajectories.Max(x => x.VerticalDepth), Fact = factTrajectories.Max(x => x.VerticalDepth) }, - WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.NptHours) / 24, + WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.DurationHours) / 24, Contacts = contacts, SectionReports = sectionReports, DrillerReports = drillerReports, From 95af64f26aaa3b2ed92edc0f1374fe8fe3af430d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 4 Sep 2024 10:37:35 +0500 Subject: [PATCH 12/13] =?UTF-8?q?=D0=A0=D0=B5=D0=B6=D0=B8=D0=BC=D1=8B=20?= =?UTF-8?q?=D0=B1=D1=83=D1=80=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit УБрал условие того, чтобы был заполнен план и факт, план может быть без факта --- .../WellReport/WellReportExportService.cs | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs b/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs index 55ec4fb0..bfb4d3fb 100644 --- a/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs +++ b/AsbCloudInfrastructure/Services/WellReport/WellReportExportService.cs @@ -349,35 +349,38 @@ public class WellReportExportService : IWellReportExportService const int frowRateMinColumn = 18; const int frowRateMaxColumn = 19; - if (!PlanOperatingModeRows.TryGetValue(idSection, out var planRow)) - return; + if (PlanOperatingModeRows.TryGetValue(idSection, out var planRow)) + { + sheet.Cell(planRow, depthStartColumn).SetCellValue(operatingMode.Plan?.DepthStart); + sheet.Cell(planRow, depthEndColumn).SetCellValue(operatingMode.Plan?.DepthEnd); - if (!FactOperatingModeRows.TryGetValue(idSection, out var factRow)) - return; + sheet.Cell(planRow, ropMinColumn).SetCellValue(operatingMode.Plan?.RopMin); + sheet.Cell(planRow, ropMaxColumn).SetCellValue(operatingMode.Plan?.RopMax); + sheet.Cell(planRow, ropAvgColumn).SetCellValue(operatingMode.Plan?.RopAvg); - sheet.Cell(planRow, depthStartColumn).SetCellValue(operatingMode.Plan?.DepthStart); - sheet.Cell(planRow, depthEndColumn).SetCellValue(operatingMode.Plan?.DepthEnd); + sheet.Cell(planRow, weightOnBitMinColumn).SetCellValue(operatingMode.Plan?.WeightOnBitMin); + sheet.Cell(planRow, weightOnBitMaxColumn).SetCellValue(operatingMode.Plan?.WeightOnBitMax); + sheet.Cell(planRow, weightOnBitAvgColumn).SetCellValue(operatingMode.Plan?.WeightOnBitAvg); - sheet.Cell(planRow, ropMinColumn).SetCellValue(operatingMode.Plan?.RopMin); - sheet.Cell(planRow, ropMaxColumn).SetCellValue(operatingMode.Plan?.RopMax); - sheet.Cell(planRow, ropAvgColumn).SetCellValue(operatingMode.Plan?.RopAvg); + sheet.Cell(planRow, driveTorqueMinColumn).SetCellValue(operatingMode.Plan?.DriveTorqueMin); + sheet.Cell(planRow, driveTorqueMaxColumn).SetCellValue(operatingMode.Plan?.DriveTorqueMax); + sheet.Cell(planRow, driveTorqueAvgColumn).SetCellValue(operatingMode.Plan?.DriveTorqueAvg); - sheet.Cell(planRow, weightOnBitMinColumn).SetCellValue(operatingMode.Plan?.WeightOnBitMin); - sheet.Cell(planRow, weightOnBitMaxColumn).SetCellValue(operatingMode.Plan?.WeightOnBitMax); - sheet.Cell(planRow, weightOnBitAvgColumn).SetCellValue(operatingMode.Plan?.WeightOnBitAvg); + sheet.Cell(planRow, differentialPressureMinColumn) + .SetCellValue(operatingMode.Plan?.DifferentialPressureMin); + sheet.Cell(planRow, differentialPressureMaxColumn) + .SetCellValue(operatingMode.Plan?.DifferentialPressureMax); + sheet.Cell(planRow, differentialPressureAvgColumn) + .SetCellValue(operatingMode.Plan?.DifferentialPressureAvg); - sheet.Cell(planRow, driveTorqueMinColumn).SetCellValue(operatingMode.Plan?.DriveTorqueMin); - sheet.Cell(planRow, driveTorqueMaxColumn).SetCellValue(operatingMode.Plan?.DriveTorqueMax); - sheet.Cell(planRow, driveTorqueAvgColumn).SetCellValue(operatingMode.Plan?.DriveTorqueAvg); + sheet.Cell(planRow, frowRateMinColumn).SetCellValue(operatingMode.Plan?.FrowRateMin); + sheet.Cell(planRow, frowRateMaxColumn).SetCellValue(operatingMode.Plan?.FrowRateMax); + } - sheet.Cell(planRow, differentialPressureMinColumn).SetCellValue(operatingMode.Plan?.DifferentialPressureMin); - sheet.Cell(planRow, differentialPressureMaxColumn).SetCellValue(operatingMode.Plan?.DifferentialPressureMax); - sheet.Cell(planRow, differentialPressureAvgColumn).SetCellValue(operatingMode.Plan?.DifferentialPressureAvg); - - sheet.Cell(planRow, frowRateMinColumn).SetCellValue(operatingMode.Plan?.FrowRateMin); - sheet.Cell(planRow, frowRateMaxColumn).SetCellValue(operatingMode.Plan?.FrowRateMax); - - sheet.Cell(factRow, depthStartColumn).SetCellValue(operatingMode.Fact?.DepthStart); - sheet.Cell(factRow, depthEndColumn).SetCellValue(operatingMode.Fact?.DepthEnd); + if (FactOperatingModeRows.TryGetValue(idSection, out var factRow)) + { + sheet.Cell(factRow, depthStartColumn).SetCellValue(operatingMode.Fact?.DepthStart); + sheet.Cell(factRow, depthEndColumn).SetCellValue(operatingMode.Fact?.DepthEnd); + } } } \ No newline at end of file From a3ffac72e027620528a11de7bb9ed36c64c10d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 4 Sep 2024 13:22:04 +0500 Subject: [PATCH 13/13] =?UTF-8?q?=D0=97=D0=B0=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/WellReport/WellReport.xlsx | Bin 38088 -> 36755 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/AsbCloudInfrastructure/Services/WellReport/WellReport.xlsx b/AsbCloudInfrastructure/Services/WellReport/WellReport.xlsx index 9e3b5ffd4a11210ae752530c9590d1fc61d818ce..9cd5370ec8d22e74ef050a1f0047a9b9d9a5f406 100644 GIT binary patch delta 31044 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 ILLR062cQ@pvj6}9 delta 32370 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