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